Lambda表达式是JDK1.8之后的一种语法,是一个匿名函数,是对匿名函数的简写形式,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升;
首先来看一下什么是Lambda表达式:
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
Integer[] ints = {98, 243, 35, 13, 57, 243};
List<Integer> list = Arrays.asList(ints);
//之前的排序
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
System.out.println(list);
//[243, 243, 98, 57, 35, 13]
//使用Lambda表达式
list.sort((o1,o2)->(o1-o2));
System.out.println(list);
//[13, 35, 57, 98, 243, 243]
}
}
通过上面的对比,发现Lambda表达式式书写起来更为简洁;
JDK1.8之后引入的一种语法,他的写法是使用一个->
符号,箭头将Lambda表达式分为左右两部分,左边写的是实现的这个接口中的抽象方法中的形参列表,右边就是对抽象方法的处理;
实现的这个接口中的抽象方法中的形参列表 -> 抽象方法的处理
因为Lambda表达式的核心就是实现的这个接口中的抽象方法中的形参列表 -> 抽象方法的处理
,因此根据形参列表与返回值的不同,Lambda表达式的具体写法也不相同;
public class MyTest1 {
public static void main(String[] args) {
MyInterface myInterface = new MyInterface() {
@Override
public void show(int a, int b) {
System.out.println(a + b);
}
};
myInterface.show(20, 30);//50
//简写1:方法名可以自己推断出来
MyInterface myInterface1 = (int a, int b) -> {
System.out.println(a + b);
};
myInterface1.show(20, 40);//60
//简写2:可以省略形参列表中的形参类型
MyInterface myInterface2 = (a, b) -> {
System.out.println(a + b);//70
};
myInterface2.show(20, 50);
//简写3:如果抽象方法中只有一行代码,可以省略方法体的大括号,当然,如果不止一行,就不能省略
MyInterface myInterface3 = (a, b) -> System.out.println(a + b);
myInterface3.show(20, 60);//80
}
}
public interface MyInterface {
public abstract void show(int a,int b);
}
public class MyTest2 {
public static void main(String[] args) {
MyInterface1 test1 = new MyInterface1() {
@Override
public int test(int a, int b) {
return a - b;
}
};
System.out.println(test1.test(90, 8));//82
//简写1:
MyInterface1 test2 = (int a, int b) -> {
return a - b;
};
System.out.println(test2.test(20, 10));//10
//简写2:
MyInterface1 test3 = (a, b) -> {return a - b;};
System.out.println(test3.test(30, 10));//20
//简写3:这个有返回值的方法,不能直接去掉大括号,还需要去掉return关键字
MyInterface1 test4 = (a, b) -> a - b;
System.out.println(test4.test(40, 10));//30
}
}
public interface MyInterface1 {
public abstract int test(int a,int b);
}
public class MyTest3 {
public static void main(String[] args) {
MyInterface2 myInterface = a -> a-20;
myInterface.show(20);
}
}
public interface MyInterface2 {
public abstract int show(int a);
}
import java.util.Arrays;
public class MyTest4 {
public static void main(String[] args) {
Integer[] ints = {89, 67, 23};
Arrays.sort(ints, (o1, o2) -> o1-o2);
System.out.println(Arrays.toString(ints));
//[23, 67, 89]
}
}
Lambda表达式也可以作为参数传递;
什么是函数式接口:
函数式接口的定义是: 只包含一个抽象方法的接口,称为函数式接口;
其实我们的Lambda表达式就是对函数式接口的一种简写方式,所以只有是函数式接口,我们才能用Lambda表达式;再换句话说,Lambda表达式需要函数式接口的支持,那函数式接口我们可以自己定义,当然JDK1.8也给我们提供了一些现成的函数式接口;
可以通过 Lambda 表达式来创建该接口的对象,我们可以在任意函数式接口上使用@FunctionalInterface 注解
,这样做可以检查它是否是一个函数式接口;
为什么只能有一个抽象方法,如果有多个抽象方法,这个接口不是函数式接口,简写的时候省略了方法名,IDEA不能知道到底重写的是哪一个方法,不能推断出来;
注解写在接口声明上面,如果不报错,就不是函数式接口;
JDK1.8之后,提供了很多函数式接口,作为参数传递;
先来看一下什么是方法引用:
注意: 实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
方法引用:使用操作符::
将方法名和对象或类的名字分隔开来,三种主要使用情况为:
对象::实例方法
类::静态方法
类::实例方法
import java.util.function.Consumer;
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("aaaaaaaaaaaaaa");
//aaaaaaaaaaaaaa
//简写1:
Consumer<String> consumer1 = (String s) -> {
System.out.println(s);
};
consumer1.accept("abc");
//abc
//简写2:
Consumer<String> consumer2 = (s) -> System.out.println(s);
consumer2.accept("bcd");
//bcd
//简写3:
Consumer<String> consumer3 = System.out::println;
consumer3.accept("abc");
//abc
}
}
为什么可以写成上述方式?
因为:System.out.println(s);与void accept(String s)一样,都是使用s作为参数,返回值是void,因此就可以简写为简写3;
import java.util.function.BinaryOperator;
public class MyTest1 {
public static void main(String[] args) {
BinaryOperator<Double> operator = new BinaryOperator<Double>(){
@Override
public Double apply(Double o, Double o2) {
return Math.max(o,o2);
}
};
System.out.println(operator.apply(2.13, 3.12));//3.12
BinaryOperator<Double> operator2 = (o, o2) -> Math.max(o,o2);
System.out.println(operator2.apply(2.13, 3.12));//3.12
BinaryOperator<Double> operator3 = Math::max;
Double max = operator3.apply(5.0, 20.0);
System.out.println(max);//20.0
}
}
因为Math.max()所需要的参数以及返回值与重写的accpet()一样,因此可以简写为
类::静态方法
;
import java.util.Comparator;
public class MyTest2 {
public static void main(String[] args) {
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println(comparator.compare(20, 12));//1
Comparator<Integer> comparator1 = Integer::compareTo;
System.out.println(comparator1.compare(20, 12));//1
}
}
import java.util.Comparator;
public class MyTest2 {
public static void main(String[] args) {
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
System.out.println(comparator.compare("20", "12"));//1
Comparator<String> comparator1 = String::compareTo;
System.out.println(comparator1.compare("20", "12"));//1
}
}
为什么可以这样写?、
传递过来的两个参数,一个作为调用者,一个作为参数,这时候,使用类::实例方法
简写;
格式:ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致!
import java.util.function.Supplier;
public class Mytest3 {
public static void main(String[] args) {
Supplier<Student> supplier = new Supplier<Student>() {
@Override
public Student get() {
return new Student();
}
};
Student student = supplier.get();
Supplier<Student> supplier1 = () -> new Student();
Student student1 = supplier1.get();
}
}
public class Mytest3 {
public static void main(String[] args) {
Supplier<Student> supplier = new Supplier<Student>() {
@Override
public Student get() {
return new Student("张三",23);
}
};
Student student = supplier.get();
System.out.println(student);
Supplier<Student> supplier1 = () -> new Student("李四",25);
Student student1 = supplier1.get();
System.out.println(student1);
}
}
public class MyTest4 {
public static void main(String[] args) {
Student student = new Student("张三", 23);
BiFunction<String, Integer, Student> function = new BiFunction<String, Integer, Student>() {
@Override
public Student apply(String s, Integer integer) {
return student;
}
};
BiFunction<String, Integer, Student> function1 = (s, integer) -> student;
BiFunction<String, Integer, Student> function2 = Student::new;
}
}
之所以可以这样简写,是因为构造方法的形参与返回值与重写的方法一样;