学习记录《写给大忙人的java_SE8》。
先上一个我们平时用到的集合排序:这里提供了4种方法
List<String> list = new ArrayList<>();
list.add("new world");
list.add("hello");
//匿名内部类
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(), o2.length());
}
});
//常规lambda
Collections.sort(list, (s1, s2) -> s1.compareToIgnoreCase(s2));
//lambda方法引用
Collections.sort(list, String::compareToIgnoreCase);
//Comparator接口静态方法+方法引用
Collections.sort(list, Comparator.comparing(String::length));
list.forEach(System.out::println);
1.1 语法
参数+箭头+表达式
例如:
Comparator<? super String> com=(String s1,String s2)->Integer.compare(s1.length(),s2.length());
a,如果没有参数,使用()
b,如果不是一个简单表达式可以解决的,用{}将表达式代码包裹起来
c,参数有时可以省略类型(见上图),程序会自动推断类型,建议还是写上,方便阅读
d,参数可以使用final等修饰,也可以使用注解修饰
1.2 函数式接口
定义:只含一个【抽象】方法的接口。任何一个lambda表达式都可以转换成使用的API中对应的函数式接口。
对象和类的管理完全依赖于如何实现,比传统的内部类效率高。
虽然Object是所有类的基类,但它不是函数式接口。
1.3 方法引用
a,类::静态方法
b,对象::实例方法
上面2种等价于使用参数的lambda表达式
c,类::实例方法
上面第一个参数成为调用方法的对象如String::compareToIgnoreCase等价于x.compareToIgnoreCase(y)
1.4 构造器引用
格式:类名::new
List<String> labels = new ArrayList<>();
Stream<Button> stream = labels.stream().map(Button::new);
Button[] buttons = stream.toArray(Button[]::new);
如上,数组构造器引用可以绕过java中的一个限制:不能使用(new)泛型数组(泛型擦除)
可以看到,传入Button数组构造器引用,返回一个Button数组,而用list.toArray等方法返回的是Object数组
1.5 变量作用域
lambda表达式构成:一段代码;参数;【自由变量的值】:自由指的是不是参数又没有在表达式中定义的变量
lambda表达式可以捕获闭包(含有自由变量的代码块)中的变量值,需要遵守一个约束:被引用的变量的值不可以被更改(线程安全考虑)
java8之前,内部类只允许访问final的局部变量,为了适应lambda表达式,规则放宽为:可以访问任何【有效】final的局部变量,即值不会发生改变的变量(应该是编译期检查)
同时注意,不要指望编译器捕获所有并发访问错误,不可变约束只作用在局部变量上,如果是实例或静态变量,编译器不会报错。
lambda表达式中的this关键词和其他地方意义一样。
1.6 默认方法
如果一个类有多个父类/实现接口,而父类/接口中的方法名和参数冲突
a,如果父类提供具体实现,实现的接口中默认方法会被忽略(类优先原则,向后兼容性)
b,如果只实现2个或多个接口,它们的某个方法的方法名和参数都冲突。如果一个接口提供的是默认方法,不管其他接口是抽象还是默认方法,此类必须覆盖这个方法;
1.7 静态方法
java8也开启了接口静态方法的大门。比如Collections的nCopies方法如果放进List中,就可以使用List直接调用此方法,而不用Collections了。
前面提到过静态方法,如
Comparator.comparing(String::length)
这种方式返回一个比较器是很简洁的。