Java的Lambda表达式和函数式接口
Lambda表达式
简介
Lambda 是一个 匿名函数,我们可以把 Lambda表达式理解为是 一段可以传递的 代码(将代码像数据一样进行传递)。可以替换匿名内部类,函数式接口。
Lambda 是jdk1.8后有的。
例如:匿名内部类 VS Lambda表达式
//原来使用匿名内部类 TreeSet<Person> ts = new TreeSet<Person>(new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }); //JDK1.8后可以使用Lambda Comparator<Person> com = (x,y)->x.getName().compareTo(y.getName()); TreeSet<Person> ts2 = new TreeSet<Person>(com);
//匿名内部类 Runnable r1 = new Runnable() { @Override public void run() { System.out.println("run..."); } }; //Lambda表达式 Runnable r2 = () -> System.out.println("run...");
语法
Lambda表达式:Java8以后,引入了“->”操作符
“->”左侧:参数列表
“->”右侧:所需要执行的功能,即Lambda体
语法格式一:无参数无返回值 ()-> System.out.println("Hello Lambda "); 语法格式二: 一个参数,无返回 //x表示变量,变量名x任意 (x) -> System.out.println(x); //只有一个参数时,()可以省略 x -> System.out.println(x); 语法格式三:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句 Comparator<Integer> com = (x, y) -> { System.out.println("函数式接口"); return Integer.compare(x, y); }; 语法格式四:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写 Comparator<Integer> com = (x, y) -> Integer.compare(x, y); 语法格式五:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断” (Integer x, Integer y) -> Integer.compare(x, y);
函数式接口
只包含一个抽象方法的接口,称为 函数式接口。
你可以通过 Lambda 表达式来创建该接口的对象。
可以在任意接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
自定义函数式接口
@FunctionalInterface public interface MyFun { public Integer getValue(Integer num); }
@FunctionalInterface public interface Myfunc<T> { public T getValue(T t); }
作为参数传递 Lambda 表达式,实参即Lambda表达式必须与函数接口的参数一致
@Test public void test07() { String s = toOperateString((x) -> x.toUpperCase(), "goodman"); System.out.println(s); String s2 = toOperateString((x)->x.toLowerCase(), s); System.out.println(s2); } //测试 作为参数传递 Lambda 表达式 public String toOperateString(Myfunc<String> fun, String origin) { String res = fun.getValue(origin); return res; }
内置的函数式接口
Java8 内置的四大核心函数式接口
Consumer<T> : 消费型接口
void accept(T t);
Supplier<T> : 供给型接口
T get();
Function<T, R> : 函数型接口
R apply(T t);
Predicate<T> : 断言型接口
boolean test(T t);
其他类型的一些函数式接口
除了上述得4种类型得接口外还有其他的一些接口供我们使用:
1)BiFunction<T, U, R>
参数类型有2个,为T,U,返回值为R,其中方法为 R apply(T t, U u)
2)UnaryOperator<T>(Function子接口)
参数为T,对参数为T的对象进行一元操作,并返回T类型结果,其中方法为 T apply(T t)
3)BinaryOperator<T>(BiFunction子接口)
参数为T,对参数为T得对象进行二元操作,并返回T类型得结果,其中方法为 T apply(T t1, T t2)
4)BiConsumer(T, U)
参数为T,U 无返回值,其中方法为 void accept(T t, U u)
5)ToIntFunction<T>、ToLongFunction<T>、ToDoubleFunction<T>
参数类型为T,返回值分别为int,long,double,分别计算int,long,double得函数。
6)IntFunction<R>、LongFunction<R>、DoubleFunction<R>
参数分别为int,long,double,返回值为R。
方法引用和构造器引用
方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况 :
对象 :: 实例方法
类 :: 静态方法
类 :: 实例方法
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
Consumer con = (x) -> System.out.println(x); //等价于 Consumer con2 = System.out::println; BinaryOperator<Double> bo = (x,y) -> Math.pow(x, y); //等价于 BinaryOperator<Double> bo2 = Math::pow;
注意:实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
构造器引用
格式: 类名::new
Function<Integer, MyClass> fun = (x) -> new MyClass(x); //等价于 Function<Integer, MyClass> fun2 = MyClass::new;
数组
Function<Integer, Integer[]> fun = (x) -> new Integer[x]; //等价于 Function<Integer, Integer[]> fun2 = Integer[]::new;
********************************
常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。