1.8 JDK新特性 -- 函数式编程 lambda 表达式 接口里的方法

本文介绍了Java 8引入的函数式编程概念,包括Stream类、Lambda表达式和函数接口。通过函数式接口和Lambda表达式,Java实现了代码的简洁性和线程安全性。文章探讨了函数式编程的优缺点,如代码可读性、线程安全和复用性,并解释了Lambda表达式的用法和格式。同时,详细阐述了Supplier、Consumer、Predicate和Function等接口在函数式编程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是函数式编程?

Java为函数式编程引入了三个新的语法概念:Stream类、Lambda表达式和函数接口(Functional Inteface)。 Stream类用来支持通过“.”级联多个函数操作的代码编写方式;引入Lambda表达式的作用是简化代码编写;函数接口的作用是让我们可以把函数包裹成函数接口,来实现把函数当做参数一样来使用(Java 不像C那样支持函数指针,可以把函数直接当参数来使用)

函数式编程不是我们平时在 Java 中编写的函数或者方法,它是一种针对于数学的概念,可以将其理解为一个表达式或者公式,或者理解为数据之间的转换关系。

  • 在 JAVA8 之前,我们无法将一个函数作为参数传递给一个方法,也无法声明一个返回函数的方法。
  • JAVA8 对函数式编程做了哪些支持?

    JAVA8 通过函数式接口和 Lambda 表达式为我们引入了函数式编程的概念。

1.1函数式编程的优劣

优点:

  1. 代码简洁可读性强,逻辑结构清晰。
  2. 线程安全,内部API屏蔽了coder对多线程的关注。
  3. 更好的复用性,往往一个函数适用于各种计算场景。

缺点:

  1. 由于函数内数据不变原则,导致的资源占用
  2. 调试上相对于命令式的困难

好处:

在java中,我们所谓的变量都是可以变化的,比如你设置一个变量为年龄,它可以按照我们的需求去更改这个年龄大小,但是 函数式编程中的变量跟jva中完全不同,它就相当于数学中的一个变量,那个值是不可以修改的,在函数式编程最终都会被编译成机器指令去允许,但是它不会因为调用的时间或者位置的变化而变化,函数的运行是独立在外部环境的,所以说它的最大的好处就是不可变。

然而就是因为这个不可变性,我们在进行多线程的时候就不需要额外枷锁,也不会再有各种线程安全问题。很适合来处理并发问题

总而言之:函数式编程,写的更少,做的更多

2.函数式接口

在了解Lambda表达式之前,我们先要了解一些什么是函数式接口。因为在java中定义了一个承载Lambda表达式的接口,这个接口就是为函数式设计的接口,所以叫做函数式接口

这个接口封装了一个行为,不用传入参数,不用返回参数的行为,行为的具体实现也就是线程具体执行的任务需要调用者传入。这里就引入了一个概念,函数式接口是对某些行为的抽象,一个函数式接口只能有一个行为

通过函数式接口的定义我们看不出什么,到底什么是函数式接口,我们可以看源码里面的英文注释,这里我们直接给出定义。

  • 函数式接口首先是一个接口。
  • 函数式接口必须只有一个抽象函数
  • 除了一个抽象方法之外,函数式接口允许有默认方法和静态方法(接口中的默认方法和静态方法也是 JAVA8 引入的,下面的章节我们会详细讲解)。
  • java.lang.Object 的抽象方法是不计算在内的,就是在函数式接口中可以定义许多 java.lang.Object 的抽象方法。
  • 如果我们的接口满足上面的条件但是没有@FunctionalInterface注解依然会被编译器认作函数式接口。

既然我们定义了一个接口,那么我们在使用的时候肯定需要创建接口的实例,所以在函数式接口有三种实现方法,Lambda表达式,方法引用,构造方法 这三个方法来实现。

所以,Lambda 表达式的作用就是用来创建函数式接口的实例。

3.Lambda表达式

1.首先理解什么是Lambda表达式?

简单来说,我们定义一个函数,往往要去想怎么调用,怎么创建对象,但是Lambda表达式的思想是,我不用去管你怎么去做这件事情,我只关心你在做什么。我们只是为了达到目的,过程和形式并不重要。

2.Lambda优越性?

代码简洁,不用去写一大堆对象内部类,另一方面比较重要就是延时(会在下边举例)。

例如Runnable接口为例:

普通实现:

package test1;

public class test1 {
  public static void main(String[] args) {
      // 匿名内部类
        Runnable task = new Runnable() {  	
        	@Override
             public void run() { // 覆盖重写抽象方法
                 System.out.println("多线程任务执行!");
             }
        };
         new Thread(task).start(); // 启动线程
}
}

Lambda实现代码

package test1;

public class test1 {
  public static void main(String[] args) {
		  new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程

}
}

只需要一部即可完成。

3.Lambda的写法格式?

一个接口,只有一个抽象方法。

()->System.out.println("多线程任务执行!")看作是一个向上转型的对象就可以了,()代表无参,当然是可以加参数的,参数以逗号隔开,

System.out.println("多线程任务执行!")是你实现的抽象方法,在这里也就是run方法。

至于返回值,要看你对抽象方法的定义,该返回什么就返回什么,和普通方法没有区别。

4.接口里的方法

1.Supplier接口:又称为供应商,不传入参数,但是会返回

java.util.function.Supplier 接口仅包含一个无参的方法 T get() 。用来获取一个泛型参数指定类型的对 象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象 数据。

方法 :T get()

2.Consumer接口:又称消费者,传入参数,但无返回

java.util.function.Consumer 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定。

方法:因此它包含有一个有输入而无输出的accept接口方法,除accept方法,它还包含有andThen这个方法;

方法:(accept方法,andThen方法)

3.Predicate接口:有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时可以使用 java.util.function.Predicate 接口。

predicate的中文意思是“断定”,即判断的意思,判断某个东西是否满足某种条件; 因此它包含

test方法,根据输入值来做逻辑判断,其结果为True或者False。

方法:test

4.Function接口:

它代表的含义是“函数”,而函数经常是有输入输出的,因此它含有一个apply方法,包含一个输入与一个输出;
apply方法外,它还有compose与andThen及indentity三个方法

方法:apply,compose,andThen , indentity

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值