一.Lambda表达式
1.1 函数式接口
1.什么是函数式接口
在Java中,函数式接口是指只包含单个抽象方法的接口,但它也可以有其他方法,例如默认方法和静态方法。函数式接口可以使用Lambda表达式或方法引用来创建该接口的实例。Java 8引入了函数式接口的概念,以便更方便地使用Lambda表达式和函数式编程。函数式接口可以使用 @FunctionalInterface 注解进行标记,这样编译器会检查该接口是否符合函数式接口的定义。
2.函数式接口的定义
@FunctionalInterface 是 Java 8 中专门为函数式接口引入的注解,使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。
//定义函数式接口
@FunctionalInterface
interface MyFunctionalInterface {
void doSomething();
}
3.函数式接口的作用
-
作为方法的参数。当将函数式编程接口作为方法的参数时,在调用方法时使用方法引用来传入具体的实现,这个方法引用相当于一个实现了函数式编程接口中抽象方法的匿名内部类的对象
-
在创建匿名内部类时,如果匿名内部类是只有一个抽象方法的函数式接口,在花括号中可以使用Lambda表达式代替方法。
4.JDK中常用的函数式接口
Supplier接口
java.util.function.Supplier<T> 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定
类型的对象数据。由于这是一个函数式接口,这也就意味着对应的 Lambda 表达式需要 “ 对外提供 ” 一个符合泛型类型的对象数据。
Consumer接口
java.util.function.Consumer<T> 接口则正好与 Supplier 接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。Consumer 接口中包含抽象方法 void accept(T t) ,意为消费一个指定泛型的数据。基本使用如:
Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个 boolean 值结果。这时可以使用
java.util.function.Predicate<T> 接口。Predicate 接口中包含一个抽象方法: boolean test(T t) 。用于条件判断的场景:
Function接口
java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为
前置条件,后者称为后置条件。Function 接口中最主要的抽象方法为:R apply(T t) ,根据类型 T 的参数获取类型 R 的结果。
Function 源码
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* 它返回一个恒等函数,该函数接受一个参数并返回相同的参数。
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}
使用场景:以 String 类型转换为 Integer 类型为例,说明 Function 接口的使用场景。
1.2 Lambda表达式
1.什么是Lambda表达式
Lambda 表达式是简化函数式接口的代码写法。也就是说,如果接口中有多个抽象方法,则无法使用Lambda表达式。Lambda 表达式的主要作用有:
-
当我们用匿名内部类作为函数式接口的实现类时,匿名内部类花括号中的方法我们可以用 lambda 表达式的方式来书写。
-
Lambda 表达式可以作为方法的参数传入到方法中。
2.Lambda表达式的格式
(方法的形参列表) -> {方法体}
3.Lambda表达式的省略写法
-
在Lambda表达式的基础上继续简化
-
参数类型可以省略不写
-
如果只有一个参数,方法参数的括号也可以省略
-
如果Lambda表达式的方法体只有一行代码。可以省略大括号不写,同时要省略分号,如果这行代码是 return 语句,必须省略 return 不写,同时要省略分号。
1.3 方法引用
1.什么是方法引用
方法引用(Method Reference)是Java中的一种简洁的语法,用于直接引用现有类或对象的方法。它提供了一种对已有方法的重用的方式,使得代码更加简洁和可读。
方法引用可以看作是 Lambda 表达式的一种特殊简写形式,可以作为 Lambda 表达式的实现。通过方法引用,我们不需要重新编写 Lambda 表达式的实现逻辑,而是直接引用现有的方法。
2.方法引用的语法
类名::方法名
其中,类名可以是类的名称或对象的引用,方法名是需要引用的方法的名称。根据方法的不同,方法引用可以分为四种类型:
静态方法引用:使用类名来引用静态方法。
类名::静态方法名
实例方法引用:使用对象的引用来引用实例方法。
对象引用::实例方法名
特定类的任意对象的实例方法引用:使用特定类的任意对象的引用来引用实例方法。
类名::实例方法名
构造方法引用:使用类名来引用构造方法。
类名::new
下面是一个示例,展示了不同类型的方法引用:
import java.util.Arrays;
import java.util.List;
//在下述示例中,我们定义了一个静态方法staticMethod()和一个实例方法instanceMethod()。
//通过不同的方法引用语法,我们可以直接引用这些方法作为Lambda表达式的实现,并应用于集合的
//遍历、转换等操作中。
public class MethodReferenceExample {
public static void staticMethod(String s) {
System.out.println("Static method: " + s);
}
public void instanceMethod(String s) {
System.out.println("Instance method: " + s);
}
public static void main(String[] args) {
// 静态方法引用
List<String> list1 = Arrays.asList("A", "B", "C");
list1.forEach(MethodReferenceExample::staticMethod);
// 实例方法引用
MethodReferenceExample example = new MethodReferenceExample();
List<String> list2 = Arrays.asList("D", "E", "F");
list2.forEach(example::instanceMethod);
// 特定类的任意对象的实例方法引用
List<String> list3 = Arrays.asList("G", "H", "I");
list3.forEach(String::toUpperCase);
// 构造方法引用
List<Integer> list4 = Arrays.asList(1, 2, 3);
list4.stream().map(Integer::new).forEach(System.out::println);
}
}
进行方法引用的类里可以有多个方法
二.可变长参数
可变长参数是一种语法糖,在编译后实际上是一个对应类型的数组。可变参数让方法在接收参数时非常灵活。可以接收一个参数、多个参数,不接收参数、一个数组。其格式为:
public void 方法名(数据类型...参数名称){
}