Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
1.如何书写Lambda的表达式
MyInterface接口(提供show方法):
public interface MyInterface {
void show();
}
测试类:
public class MyTest {
public static void main(String[] args) {
// Lambda 表达式,是JDK1.8之后,提供一种语法风格,你可以认为他是匿名内部类的一种进行形式,他可以作为参数进行传递
//匿名内部类
MyInterface myInterface = new MyInterface() {
@Override
public void show() {
System.out.println("这是show方法");
}
};
//针对上面的匿名内部类的写法,我们可以使用 Lambda 表达式 进行简化
MyInterface myInterface2 = () -> {
System.out.println("这是show方法");
};
}
}
2.Lambda的表达式的近一步简写
public class MyTest2 {
public static void main(String[] args) {
//Lambda 表达式,的语法
//引入一个箭头符号 ->
// 箭头 -> 把 Lambda 表达式 分成左右两部分
// 箭头左边是 接口中抽象方法的 形参列表
// 箭头右边是,抽象方法的具体重写逻辑
// 匿名内部类的写法
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a - b;
}
};
//第一步简写:
Comparator<Integer> comparator2 = (Integer a, Integer b) -> {
return a - b;
};
//形参的数据类型,可以省略不写,因为有泛型可以推断出形参的数据类型
Comparator<Integer> comparator3 = (a, b) -> {
return a - b;
};
//还能再简化
//如果你的重写逻辑只有一行代码,那么{} return 都可以省略不写
Comparator<Integer> comparator4 = (a, b) -> a - b;
}
}
3.匿名内部类有参数传递时Lambda的表达式的写法
Iiterface接口:
public interface Iinterface {
int test(int num);
}
测试类:
public class MyTest2 {
public static void main(String[] args) {
Iinterface iinterface = new Iinterface() {
@Override
public int test(int num) {
return num + 10;
}
};
Lambda 表达式,简写了匿名内部类 ,如果形参只有一个 ()可以省略不写
Iinterface iinterface2 = x -> x += 10;
}
}
4.匿名内部类做为参数传递和Lambda表达式作为参数来传递
public class MyTest3 {
public static void main(String[] args) {
TreeSet<String> strings = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String a, String b) {
return 0;
}
});
TreeSet<String> strings2 = new TreeSet<>((a, b) -> a.compareTo(b));
//可以alt+enter 选择替换成 Lmabda表达式
TreeSet<String> strings3 = new TreeSet<>((a, b) -> a.compareTo(b));
}
}
5.函数式接口的定义是: 只包含一个抽象方法的接口,称为函数式接口。
任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口.
下面代码加上注解就会报错:
//@FunctionalInterface 加上就报错
public interface HeHe {
void aa();
void bb();
}
函数式接口:
@FunctionalInterface //这个注解就表明了,这是一个函数式接口
public interface HaHa {
void test();
}
测试类:
public class MyTest {
public static void main(String[] args) {
//Lambda 表达式 他需要函数式接口的支持,换句话说,就是只有函数式接口,才能使用Lambda写出来
// 函数式接口:就是接口中,只有一个抽象方法,有个注解 @FunctionalInterface 可以检测该接口是不是函数式接口
HeHe heHe = new HeHe() {
@Override
public void aa() {
}
@Override
public void bb() {
}
};
HaHa haHa = new HaHa() {
@Override
public void test() {
}
};
HaHa haHa2 = () -> System.out.println("aaaa");
}
}
6.Java中提供的4大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
Consumer<T> 消费型接口 | T | void | 对类型为T的对象应用操 |
Supplier<T> 供给型接口 | 无 | T | 返回类型为T的对象,包 |
Function<T, R> 函数型接口 | T | R | 对类型为T的对象应用操 |
Predicate<T> 断言型接口 | T | boolean | 确定类型为T的对象是否 |
其他函数式接口:
函数式接口 | 参数类型 | 返回类型 | 用途 |
BiFunction<T,U,R> | T U | R | 对类型为 T, U 参数应用 |
UnaryOperator<T> (Function的子接口) | T | T | 对类型为T的对象进行一 |
BinaryOperator<T> (BiFunction的子接口) | T T | T | 对类型为T的对象进行二 |
BiConsumer<T,U> | T U | void | 对类型为T, U 参数应用 |
ToIntFunction<T> | T | int | 分 别 计 算 int 、 long 、 |
IntFunction<R> | int | R | 参数分别为int、 long、 |
7.方法引用:
方法引用:方法引用其实是Lambda表达式的另一种写法,
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用.
注意:实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
方法引用:使用操作符 “ ::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况:对象::实例方法
类::静态方法
类::实例方法
public class MyTest {
public static void main(String[] args) {
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("abc");
Consumer<String> consumer2 = s -> System.out.println(s);
consumer2.accept("hello");
//你对 Consumer接口 中的 public void accept(String s) 这抽象方法的重写逻辑 System.out.println(s)
//注意观察:accept(String s) 这抽象方法,没有返回值,有一个参数
//再来观察:我们的重写逻辑
//PrintStream out = System.out;
//out.println("abc");
//调用的这个println("abc") 他的返回值类型和形参列表,跟 accept(String s) 方法的返回值类型和形参列表是一致的,如果有这种巧合就可以简写成下面的 实例对象::方法
Consumer<String> consumer3 = System.out::println;
System.out.println("==========================");
BinaryOperator<Double> binaryOperator = new BinaryOperator<Double>() {
@Override
public Double apply(Double x, Double y) {
return Math.max(x, y);
}
};
//第一次简写
BinaryOperator<Double> binaryOperator2 = (x, y) -> Math.max(x, y);
//最终简写,因为又有巧合重写
//观察: BinaryOperator 中的 apply抽象方法,有一个返回值,有两个参数
//观察我们的重写逻辑 Math.max(x, y); 调用 的max方法,有一个返回值,有两个参数,能和apply抽象方法对应上
//最终简写,类名::静态方法
BinaryOperator<Double> binaryOperator3 = Math::max;
System.out.println("==============================================");
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String a, String b) {
//第一个参数作为了调用者,第二个参数,作为传入值
return a.compareTo(b);
}
};
//第一步简写
Comparator<String> comparator2 = (a, b) -> a.compareTo(b);
//最终简写:第一个参数作为了调用者,第二个参数,作为传入值
Comparator<String> comparator3 = String::compareTo;
System.out.println("=========================================");
BiFunction<String, String, Boolean> biFunction = new BiFunction<String, String, Boolean>() {
@Override
public Boolean apply(String x, String y) {
return x.equals(y);
}
};
BiFunction<String, String, Boolean> biFunction2 = (x, y) -> x.equals(y);
//最终简写
BiFunction<String, String, Boolean> biFunction3 = String::equals;
}
}
8.构造器引用:
格式:ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致!
Student类:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类:
public class MyTest2 {
public static void main(String[] args) {
Supplier<Student> supplier = new Supplier<Student>() {
@Override
public Student get() {
return new Student();
}
};
Supplier<Student> supplier2 = () -> new Student();
//最终简写 观察:构造方法,和接口中的抽象方法get() 方法的返回值和形参列表能对应上,就可以用构造引用简写
Supplier<Student> supplier3 = Student::new;
System.out.println("==================================================");
BiFunction<String, Integer, Student> biFunction = new BiFunction<String, Integer, Student>() {
@Override
public Student apply(String name, Integer age) {
return new Student(name, age);
}
};
Student wangwu = biFunction.apply("wangwu", 25);
//第一次简写
BiFunction<String, Integer, Student> biFunction2 = (name, age) -> new Student(name, age);
Student s0 = biFunction2.apply("lisi", 24);
//最终简写:
BiFunction<String, Integer, Student> biFunction3 = Student::new;
Student s = biFunction3.apply("张三", 23);
}
}