对核心类库的改进主要包括集合类的API和新引入的流(Stream)。
流使得我们可以在更高的抽象层次对集合进行操作
通常,以前,我们是这样使用for循环计算来自London的人数:
int count = 0;
for (Artist artist : allArtists) {
if (artist.isFrom("London")) {
count++;
}
}
背后原理,其实是用for循环封装了迭代的语法糖(外部迭代):
int count = 0;
Iterator iterator = allArtists.iterator();
while (iterator.hasNext()) {
Artist artist = iterator.next();
if (artist.isFrom("London")) {
count++;
}
}
java8中使用stream(),返回的是内部迭代的接口:Stream。
long count=allArtists.stream()
.filter(artist->artist.isForm("London"))
.count();
stream()方法是Collection接口里面的default方法
default Stream stream() {
return StreamSupport.stream(spliterator(), false);
}
惰性求值,如下运行不会输出任何信息:
allArtists.stream()
.filter(artist -> {
System.out.println(artist.getName());
return artist.isFrom("London");
});
只有加上count(),才会输出:
long count = allArtists.stream()
.filter(artist -> {
System.out.println(artist.getName());
return artist.isFrom("London");
})
.count();
判断一个操作是惰性求值还是及早求值:只需看它的返回值,如果返回的是Stream,那么是惰性求值;如果返回值是另一个值或者为空,那么就是及早求值。
跟建造者模式有点类似,最后调用一个build()方式时,才会创建对象。
常用的流操作
collect(toList())
List<String> collected = Stream.of("a", "b", "c") // <1>
.collect(Collectors.toList()); // <2>
assertEquals(Arrays.asList("a", "b", "c"), collected); // <3>
map
List<String> collected = Stream.of("a", "b", "hello")
.map(string -> string.toUpperCase()) // <1>
.collect(toList());
assertEquals(asList("A", "B", "HELLO"), collected);
传给map的Lambda表达式是函数式接口Function的一个实例:
<R> Stream<R> map(Function super T, ? extends R> mapper);
其中Function 部分源码:
public interface Function {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
filter
使用老的for循环
List beginningWithNumbers = new ArrayList<>();
for (String value : asList("a", "1abc", "abc1")) {
if (isDigit(value.charAt(0))) {
beginningWithNumbers.add(value);
}
}
函数式风格:
List together = Stream.of("a", "1abc", "abc1")
.filter(value->isDigit(value.charAt(0)))
.collect(toList());
assertEquals(asList(1, 2, 3, 4), together);
其中filter()接收的是一个叫predicate的函数接口
flatMap
List together = Stream.of(asList(1, 2), asList(3, 4))
.flatMap(numbers -> numbers.stream())
.collect(toList());
assertEquals(asList(1, 2, 3, 4), together);
这个不怎么好理解,flatMap规定lambda返回的是Stream类型。而作用是拆解原来的流,然后组合成一个新的流。
max,min
List
使用以前的方法:
tracks.sort(new Comparator
然后再从tracks里面取出最小的。
或者可以直接用Collections.min()
Collections.min(tracks, new Comparator
但还是java8的好看
整合起来的操作:
List beginningWithNumbers
= Stream.of("a", "1abc", "abc1")
.filter(value -> isDigit(value.charAt(0)))
.collect(toList());
assertEquals(asList("1abc"), beginningWithNumbers);