“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。html
Lambda表达式的语法由参数列表、箭头符号->和函数体组成。函数体既能够是一个表达式,也能够是一个语句块。java
好比:express
(int x, int y) -> x + y;
具体的Lambda表达式的介绍能够看这篇博客,写得挺详细的。编程
下面就用一些例子来体验一下Lambda表达式。编程语言
好比咱们如今要遍历一个List:ide
List<String> list = Arrays.asList("Hello", "JDK8", "and", "Lambda");
JDK8以前的写法:函数式编程
for (String s : list) { System.out.println(s); }
用Lambda表达式写法:函数
list.forEach(s -> System.out.println(s));
能够看到,不管是代码量和可读性都获得了提升。线程
在此基础上还能够再用隐式表达式进行简化:设计
list.forEach(System.out::println);
在Java中不少时候咱们要用到匿名类,好比线程Runnable、FileFilter和Comparator等等。
而匿名类型最大的问题就在于其冗余的语法。
这里用Comparator作例子。
好比咱们有一个Cat类,表示猫,有名字、高度和重量这些属性。
package com.fengyuan.model; import lombok.AllArgsConstructor; import lombok.Data; public @Data @AllArgsConstructor class Cat { private String name; private double height; private double weight; }
咱们建立3只猫,存到List中:
List<Cat> catList = new ArrayList<>(); // 请无视这些数据的合理性,我乱写的 catList.add(new Cat("cat1", 10.3, 3.6)); catList.add(new Cat("cat2", 9.3, 4.6)); catList.add(new Cat("cat3", 9.5, 4.0));
而后咱们如今要对这个List进行排序,可是如今不知道是要怎么排,因此咱们要定义一个比较器,指定用高度或者是重量来排序。
JDK8以前的写法:
// 指定用高度来排序 Collections.sort(catList, new Comparator<Cat>() { @Override public int compare(Cat o1, Cat o2) { if (o1.getHeight() > o2.getHeight()) { return 1; } else if (o1.getHeight() < o2.getHeight()) { return -1; } else { return 0; } } });
而用Lambda,能够这样写:
Collections.sort(catList, (o1, o2) -> { if (o1.getHeight() > o2.getHeight()) { return 1; } else if (o1.getHeight() < o2.getHeight()) { return -1; } else { return 0; } });
继续用方法引用,能够简写到极致:
// 指定用重量排序 catList.sort(Comparator.comparing(Cat::getWeight));
// 要逆向排列也很简单 catList.sort(Comparator.comparing(Cat::getWeight).reversed());
到最后这种写法,已经简写到极致,并且可读性很是高。
JDK8增长了一个新的包:java.util.function,它里面包含了经常使用的函数式接口,好比Predicate<T>、Consumer<T>,Function<T, R>等等。
接下来就体验一下Predicate和Consumer的用法。
咱们如今有一个订单类,有id,金额,运费这些属性。这个订单有一个折扣方法,咱们但愿可以根据营销活动,动态修改优惠方案。
Order类:
package com.fengyuan.model; import java.util.function.Consumer; import java.util.function.Predicate; import lombok.AllArgsConstructor; import lombok.Data; public @Data @AllArgsConstructor class Order { private long id; private double payment; private double freight; // 优惠政策 public Order discount(Order order, Predicate<Order> predicate, Consumer<Order> consumer) { // 知足Predicate的条件,返回true if (predicate.test(order)) { // 接收订单对象,对订单对象进行处理 consumer.accept(order); } return order; } }
其中
Predicate<T>:接收T对象并返回boolean。
Consumer<T>:接收T对象,没有返回值。
而后经过函数式编程,咱们能够动态传入咱们的优惠方案,好比99包邮:
// 新建一个订单,506.5的金额,10.0的运费 Order order = new Order(123, 506.5, 10.0); // 知足金额>=99的条件,则设置运费为0 order.discount(order, o -> o.getPayment() >= 99, o -> o.setFreight(0));
这样一来,就能根据营销活动,修改咱们的优惠方案。
除此以外,Predicate对象之间还能运用与或非这些逻辑操做,好比:
predicate1.and(predicate2); predicate1.or(predicate2);
这里的Stream和I/O流不一样,它更像具备Iterable的集合类。
Stream API引入的目的在于弥补Java函数式编程的缺陷,让java也支持map()、reduce()等函数式编程语言。
map(映射),将传入的函数依次做用到序列的每一个元素。
好比说,有一个字符串列表,咱们如今给列表里每一个字符串调用toLowerCase()方法,转成小写字母。
List<String> list = Arrays.asList("Hello", "JDK8", "and", "Lambda");
转成小写,用collect()把Stream再转回List,返回新的列表:
List<String> newList = list.stream().map(s -> s.toLowerCase()).collect(Collectors.toList());
也能够返回一个字符串,指定链接符,我这里是用空格链接的:
String str = list.stream().map(s -> s.toLowerCase()).collect(Collectors.joining(" "));
也能够用隐式函数,String::toLowerCase来实现:
String str = list.stream().map(String::toLowerCase).collect(Collectors.joining(" "));
reduce(归约),将集合中全部值结合起来。
将一个整型List,先进行map:每一个数都翻一倍,再进行reduce:全部数加起来,获得结果:
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50); int result = numbers.stream().map(num -> num * 2).reduce((r, num) -> r += num).get();
一个简单的例子,算出一个集合中最大值、最小值、平均值等等。
集合:
List<Integer> numbers = Arrays.asList(4, 6, 65, 3, 44, 2, 17, 19);
计算:
int max = numbers.stream().mapToInt(x -> x).max().getAsInt(); int min = numbers.stream().mapToInt(x -> x).min().getAsInt(); long count = numbers.stream().mapToInt(x -> x).count(); double avg = numbers.stream().mapToInt(x -> x).average().getAsDouble(); int sum = numbers.stream().mapToInt(x -> x).sum();
也能够用IntSummaryStatistics类来获得统计结果:
IntSummaryStatistics stat = numbers.stream().mapToInt(x -> x).summaryStatistics(); int max = stat.getMax(); int min = stat.getMin(); long count = stat.getCount(); double avg = stat.getAverage(); long sum = stat.getSum();
虽然平时项目的开发中仍是比较少用到Lambda表达式,可是在以上这些体验中,确实是感觉到了它的魅力。