lambda对的演进及书写
-
演进
以Comparator接口为例。 代码调用Collections.sort方法对集合进行排序,其中第二个参数是一个匿名内部类,sort方法调用内部类中的compare方法对list进行位置交换,因为java中的参数类型只能是类或者基本数据类型,所以虽然传入的是一个Comparator类,但是实际上可以理解成为了传递compare方法而不得不传递一个Comparator类 ,这种方式显得比较笨拙,而且大量使用的话代码严重冗余,这种情况在java8中通过使用lambda表达式来解决。匿名内部类形式:
Collections.sort(studentList, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return Double.compare(o1.getScore(),o2.getScore()); } });
lambda表达式形式:
Collections.sort(studentList,(s1,s2)-> Double.compare(s1.getScore(),s2.getScore()));
-
多参数
(1). lambda表达式的基本格式为(x1,x2)->{表达式…};
(2). 在上式中,lambda表达式带有两个参数,此时参数类型可以省略,但两边的括号不能省略
(3). 如果表达式只有一行,那么表达式两边的花括号可以省略
例子:Collections.sort(studentList,(s1,s2)-> Double.compare(s1.getScore(),s2.getScore()));
-
对于没有参数的情况
(1).参数的括号不能省略,
(2).其他语法同多参数new Thread(()-> System.out.println("hello, i am thread!")).start();
-
对于一个参数的情况
(1).可以省略参数的括号和类型
(2).其他语法同多参数// item -> !(item instanceof MappingJackson2XmlHttpMessageConverter) List<HttpMessageConverter<?>> converters = messageConverters.stream() .filter(item -> !(item instanceof MappingJackson2XmlHttpMessageConverter)) .collect(Collectors.toList());
lambda表达式内可以使用方法引用
lambda表达式内可以使用方法引用,仅当该方法不修改lambda表达式提供的参数。本例中的lambda表达式可以换为方法引用,因为这仅是一个参数相同的简单方法调用。
list.forEach(n -> System.out.println(n));
// 使用方法引用
list.forEach(System.out::println);
然而,若对参数有任何修改,则不能使用方法引用,而需键入完整地lambda表达式,如下所示:
list.forEach((String s) -> System.out.println("*" + s + "*"));
lambda变量的使用
public static void main(String[] args) {
List<Integer> primes = Arrays.asList(new Integer[]{2, 3, 5, 7});
// 局部变量被lambda表达式引用时为隐式的final变量。
int factor = 2; // 基本类型不能修改值
ArrayList<Integer> testList = new ArrayList<>(); // 引用类型不能修改引用,但是可以修改内容
primes.forEach(element -> {
testList.add(element); // 引用类型的局部变量可以修改内容
System.out.println(factor + 2); // 基本类型,只能使用,不能改变值
// 【注意】 编译会报'java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量'
// factor ++;
// 【注意】编译会报'java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量'
// testList = new ArrayList<>();
});
System.out.println(testList);
}
lambda当做方法参数传递
惰性求值方法
lists.stream().filter(f -> f.getName().equals("p1"))
如上示例,这行代码并未做什么实际性的工作,filter只是描述了Stream,没有产生新的集合。
及早求值方法
// f -> f.getName().equals("p1") 这个lambda表达式只是作为一个方法当参数传递,并没有这正的执行,在collect时才会执行
List<Person> list2 = lists.stream().filter(f -> f.getName().equals("p1")).collect(Collectors.toList());
如上示例,collect最终会从Stream产生新值,拥有终止操作。
理想方式是形成一个惰性求值的链,最后用一个及早求值的操作返回想要的结果。与建造者模式相似,建造者模式先是使用一系列操作设置属性和配置,最后调用build方法,创建对象。