Java8新特性
- 首先Java8引入了两个编程概念,一个是流处理,指的是程序可以从输入流中一个一个读取数据项,然后以同样的方式将数据项写入输出流。基于这种思想添加了Stream API。另一个引入的编程概念是通过API传递代码,也就是用行为参数化这种思想将代码传递给方法,比如我们将代码块作为参数传递给一个方法,稍后再去执行它,那么这个方法的行为就基于那块代码被参数化了。Java8之前处理集合时,我们得自己去做迭代的过程,也就是用for-each循环一个个来迭代元素,然后处理元素,我们把这种迭代方法称为外部迭代。而Java8有了Stream API后,数据处理完全在库内部进行,我们就不用操心循环的事了,这种思想叫做内部迭代,它相比原先处理集合的方式,会更清晰和简洁。StreamAPI处理集合还有一个优点:以前我们通过多线程代码来利用并行,也就是通过Java中的Thread API来编写多线程代码,但这并不是一个简单的事,因为线程可能会同时访问并更新共享变量,如果没有协调同步好,就会出现问题,传统上是利用Synchronized关键字来解决。而Stream可以更好的方便我们利用CPU资源进行并行的处理。(parallelStream)
- Lambda表达式:可以传递匿名函数,它没有名称,但有参数列表,函数主体,返回类型,可能还有可抛出的异常列表。它可以作为参数传递给方法或存储在变量中,而无需像匿名类那样写很多模板代码。它的写法结构是 参数 + 箭头 + Lambda主体。
1. 行为参数化
指把一个行为(代码块)作为参数传入另一个方法。
代码实现步骤是:先创建一个接口,接口中有且仅有一个抽象方法,然后实现这个接口,建立不同的行为,接着将行为当做参数传入 filter 方法中,这种做法类似于策略设计模式。
import java.util.ArrayList;
import java.util.List;
public class sss {
public interface Predicate<T> {
boolean test(T t);
}
private static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for (T e : list) {
if (p.test(e)) {
result.add(e);
}
}
return result;
}
private List<Apple> list = new ArrayList<>();
List<Apple> redApples = filter(list, (Apple apple) -> "red".equals(apple.getColor()));
private List<Integer> numbers = new ArrayList<>();
List<Integer> even = filter(numbers, (Integer i) -> i % 2 == 0);
}
2. Lambda
-
Lambda表达式由 参数、箭头、主体 组成
-
在哪里可以使用Lambda?:可以在函数式接口上使用Lambda表达式,函数式接口就是只定义一个抽象方法的接口。
细节
- (String s) -> “beijing”
- (String s) -> { return “beijing”; }
- 函数式接口的概念:只定义了一个抽象方法的接口(比如 Comparator)(可以有默认方法)
- 目标引用 ::方法名称。比如 Apple::getWeight,表示引用Apple类中定义的getWeight方法,不需要括号,因为没有实际调用这个方法。它是 (Apple a) -> a.getWeight() 的快捷写法。
- List.forEach(System.out::println); 输出集合中的每一个元素
7.1号 《Java8函数式编程》
- 对于foreach循环里的函数式编程,可以将foreach替换为 flatmap
for循环版本:
public Set<String> findLongTracks(List<Album> albums) {
Set<String> trackNames = new HashSet<>();
for (Album album : albums) {
for (Track track : album.getTrackList()) {
if (track.getLength() > 60) {
String name = track.getName();
trackNames.add(name);
}
}
}
return trackNames;
}
函数式编程版本:
public Set<String> test(List<Album> albums) {
return albums.stream()
.flatMap(e -> e.getTracks())
.filter(t -> t.getLength() > 60)
.map(n -> n.getName())
.collect(toSet());
}
- 使用并行流时,forEach方法不能保证元素是按顺序处理的,可以使用 forEachOrdered 方法来实现。
并发和并行
- 并发:两个任务共享时间段,比如一个程序要运行两个任务,并且只有一个CPU给他们分配了不同的时间片,那么这就是并发,而不是并行。
- 并行:两个任务在同一时间发生,比如运行在多核CPU上。