文章目录
什么是Lambda?
有一种数学模型天生适合做并行化,即Lambda表达式。
这个数学模型后来在计算机领域衍生成另一种编程范式,即函数式编程(Function Programming)
lambda表达式允许我们将行为传到函数里
传统集合缺点
- Java的for循环是串行的,而且必须按照集合中元素的顺序进行一次处理
- 集合框架无法堆控制流进行优化,例如通过排序 并行 短路(short-circuiting)求值以及惰性求值改善性能
lambda优势
划分:内部迭代 外部迭代
之前外部迭代 职责:做什么 (业务需求),怎么做 (如何遍历)
之后内部迭代 职责:做什么
怎么做则交给类库
为什么要学习Lambda?
更好理解函数式,其允许用函数式风格写代码
方便用于对列表(Lists) 和 集合(Collections)数据进行提取,过滤和排序。
需要学习哪些点?
- Lambda表达式
- 函数式接口
- 流API
举例
用lambda表达式实现Runnable
主要用于
匿名类
时候。
// 之前,通常使用:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("not use lambda");
}
}).start();
// 使用lambda后:
new Thread( () -> System.out.println("use lambda")).start();
语法:
左边为预期输入,右边为预期输出
- (params) -> expression
- (params) -> statement
- (params) -> { statements }
即用() -> {}
代替整个匿名类
比如不传参:
() -> System.out.println("hello lambda!")
接受参数:
(int even, int odd) -> even + odd
用lambda表达式对列表进行迭代
更容易做迭代和对集合元素进行并行处理
List<String> features = Arrays.asList("lambdas", "default", "stream api");
// 之前:
for (String feature : features) {
System.out.println(feature);
}
// lambda 之后:
features.forEach(item -> System.out.println(item));
// 更简洁:
features.forEach(System.out::println);
使用lambda表达式和函数式接口Predicate
java.util.function.Predicate
函数式接口,可以向API方法添加逻辑,用更少的代码支持更多的动态行为。
Predicate
接口适用于做过滤
public void testPredicate() {
List<String> languages = Arrays.asList("Java", "JavaScript", "Scala", "C++", "Haskell");
System.out.println("Language which starts with J: ");
filter(languages, (str) -> str.startsWith("J"));
// OR after
filter2(languages, (str) -> str.startsWith("J"));
}
private void filter(List<String> names, Predicate<String> condition) {
for (String name: names) {
if (condition.test(name)) {
System.out.println(name + " ");
}
}
}
private void filter2(List<String> names, Predicate<String> condition) {
names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
System.out.println(name + " ");
});
}
Predicate
接口允许进行多重条件的测试:
可以将两个或者多个 Predicate
合成一个。即 and()
or()
xor()
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
languages.stream().filter(startsWithJ.and(fourLetterLong))
.forEach((n) -> System.out.println("Name, which starts with 'J' and four letter long is : " + n ));
lambda表达式 Map 示例
map
允许将对象(或 值) 进行转换,流中每一个元素都将进行转换。
List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
for (Integer cost : costBeforeTax) {
double price = cost + .12 * cost;
System.out.println(price);
}
// 使用lambda表达式
costBeforeTax.stream().map((cost) -> cost + .12 * cost)
.forEach(System.out::println);
lambda表达式 Reduce 示例
reduce()
又为折叠操作, 可以将所有值合并成一个。
在 SQL 中类似 sum()
avg()
count()
聚合函数,实际上就是 reduce 操作。
接受多值,并返回一个值。
List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double total = 0;
for (Integer cost : costBeforeTax) {
double price = cost + .12 * cost;
total = total + price;
}
System.out.println("Total : " + total);
// 之后
double bill = costBeforeTax.stream().map((cost) -> cost + .12 * cost)
.reduce((sum, cost) -> sum + cost)
.get();
System.out.println("Bill : " + bill);
通过过滤创建一个String列表
lambda 表达式过滤 Java 集合
List<String> strList = Arrays.asList("English", "Chinese", "French", "KaKoa");
List<String> filtered = strList.stream().filter(x -> x.length() > 2).collect(Collectors.toList());
System.out.printf("Original List : %s, filtered list : %s", strList, filtered);
流(stream)
在类库中议添加新的 流java.util.stream.Stream
以便进行聚集(aggregation)操作
其中,Stream<T>
代表对象引用,此外还有一系列特化(specialization)流,比如IntStream
代表整形数字流
流的操作可以被组合成 流水线(pipeline)
例如:
shapes.stream()
.filter(s -> s.getColor() == BLUE)
.forEach(s -> s.setColor(RED));
在 Collection
上调用 stream()
会生成该集合元素的流视图(stream view);
filter()
过滤,产生只包含蓝色的流;
forEach()
遍历,并操作设置为红色。
流水线既可以串行执行也可以并行执行,并行或串行是流的属性。
除非显示要求使用并行流,否则JDK总会返回串行流。(串行流可以通过parallel()
方法被转化为并行流)