概述
函数式接口
只含有一个抽象方法的接口,称为函数式接口。lambda表达式可以赋值并且仅可以赋值给函数式接口的变量。实际上编译器往往需要根据函数式接口推断lambda表达式的参数类型和返回值,比如: Comparator<String> comp = (first, second) -> Integer.compare(first.length(), second.length())
。实际上,你甚至无法将一个lambda表达式赋值给一个Object类型的对象。
java.util.function包定义了各种常用的函数式接口,不过identity函数接口由Function类的静态方法提供。Runnable和Callable也是常见的函数接口。可以给函数式接口添加@FunctionalInterface标记,便于编译器检查。
lambda表达式语法
(String first, String second) -> { ...; return 0;}
(String first, String second) -> Integer.compare(first.length(), second.length())
//单条语句省略大括号(first, second) -> Integer.compare(first.length(), second.length())
//如果类型可推断() -> { doWork();}
//如果无参数event -> System.out.println("button clicked")
//只有一个参数且类型可推断,省略参数括号
函数引用
对象::实例方法
button.setOnAction(System.out::println)
等价于 button.setOnAction(event -> System.out.println(event)
。对象可以是this或super,比如 this::equals
等价于 x -> this.equals(x)。
类::静态方法
Math::pow
等价于 (x,y) -> Math.pow(x,y)
。
类::实例方法
会在lambda表达式的第一个参数上调用该方法,比如 String::CompareTo
等价于 (x,y) -> x.compareTo(y)
。
构造函数引用
Button::new
等价于 x -> new Button(x)
。int[]::new
等价于 x -> new int[x]
。可以避免泛型数组的限制,如Button[] btns = stream.toArray(Button[]::new);
作用域
lambda表达式方法体与嵌套代码块有着相同的作用域。实际上,如果方法体里引用了this,就和在嵌套块里引用this是一样的,指向的并不是lambda表达式对象。方法体里如果使用了外部的局部变量,则该变量必须是“有效的final”变量(即初始化之后不会再赋值,即便没有用final关键字修饰)。内部类原先的final约束也放宽为“有效final”。
默认方法
接口可以通过default关键字提供方法的默认实现(注意只能是接口)。
默认方法冲突的解决规则 1. 类优先。class Student extends Person implements Named {} 如果父类Person和接口Named具有同名方法,则继承父类的。2. 接口冲突。如果父类没有该方法,但是多个接口有同名方法,且至少一个接口提供了默认实现,则必须提供具体实现。
函数式接口与泛型
考虑List作为函数参数,如果函数只需要从List里面读取Person数据,那么参数可以定义为List<? extends Person>,这样传递一个List<Student>参数也没问题。如果函数只需要往List里面写入Student数据,参数可以定义为<? super Student>,这样传递一个List<Person>参数也没问题。一般来讲,读取是协变的(covariant,可以接受子类型),写入是逆变的(contravariant,可以接受父类型)。函数式接口也要遵守此惯例,比如Stream<T>的如下方法:
void forEach(Consumer<? super T> action)
Stream<T> filter(Predicate<? super T> predicate)
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
也存在协变和逆变互相抵消的情况,这时就不需要通配符,比如 T reduce(T identity, BinaryOperator<T> accumulator)
。
一般来讲,你只需要在所有不是返回类型的参数类型上加上? super,并且在所有不是参数类型的返回类型上加上? extends。(simply add ? super to any argument type that is not also a return type, and ? extends to any return type that is not also an argument type.)
最后
以上就是安静汽车为你收集整理的《写给大忙人看的java SE8》笔记 -- 1. lambda表达式的全部内容,希望文章能够帮你解决《写给大忙人看的java SE8》笔记 -- 1. lambda表达式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复