1.collect(toList())
collect(toList())方法由stream里的值生成一个列表,是一个及早求值的操作。
List<String> collectd = Stream.of("a","b","c")
.collect(Collectors.toList());
2.map
如果有一个函数可以将一种类型转换成另一种类型,map就可以
Stream.of("a","b","c").map(String -> String.toUpperCase())
.collect(Collectors.toList());
3.filter
若要重构遗留代码,for循环中的if条件语句就是一个很强的信号,可用filter代替
Stream.of("a","bdd","cde").filter(value -> isDigit(value.charAt(0)))
.collect(Collectors.toList());
4.flatMap
flatMap方法可用Stream替换值,然后将多个stream连接成一个Stream.
Stream.of(asList(1,2),asList(3,4))).flatMap(number ->numbers.stream())
.collect(Collectors.toList());
5.max和min
Stream上最常用的操作之一就是求最大值和最小值。
List<Track> tracks = asList(new Track("a",524),
new Track("b",378),new Track("c",451));
tracks.stream().min(Comparator.comparing(track -> track.getLength()))
.get()
java8提供了一个新的静态方法comparing,使用它可以方便的实现一个比较器。此外,还可以调用空Stream的max方法,,返回optional对象,它代表一个可能存在也可能不存在的值。如果stream为空,该值不存在,非空,存在。通过get方法可以取出optional对象的值。
6.reduce
reduce操作可以实现从一组值中生成一个值。
Stream.of(1,2,3).reduce(0,(acc,element)->acc + element);
assertEquals(6,count)
传入stream中的当前元素和acc,将两个参数相加,acc是累加器,保存着当前的累加结果。
7.整合操作
1、找出专辑上的所有表演者
2、分辨出哪些表演者是乐队
3、找出每个乐队的国籍
4、将找出的国籍放入一个新的集合
整合:
1.Album类有个getMusicians方法,返回一个stream对象,包含整张专辑重的所有表演者
2、使用filter方法对表演者进行过滤,只保留乐队
3、使用map方法将乐队映射为所属国家
4、使用collect(Collectors.toList())方法将国籍放入一个列表
代码如下:
album.getMusicians().filter(artList -> artList.getName().startWith("the"))
.map(artList -> artList.getNationality()).collect(Collectors.toList());
多次调用流和流的链式调用相比有如下缺点
1、代码可读性差,样本代码太多,隐藏了真正的业务逻辑
2、效率差,每一步都要对流的及早求值,生成新的集合
3、代码充斥一堆垃圾变量,它们只用来保存中间结果,除此之外毫无用处
4、难于自动化并行处理
7.optional
optional<String> a = Optional.of("a");
assertEquals("a",a.get())
a.isPresent()检查optional对象是否有值,orElse方法,当optional对象为空时,该方法提供了一个备选值。如果该备选值在计算上太过繁琐,则可使用orElseGet()
optional emptyOptional = Optional.empty()
assertEquals("a",emptyOptional.orElse("a"));
assertEquals("b",emptyOptional.orElseGet(()->"c"));
8.元素顺序
直观上看,流是有序的,因为流中的元素都是按顺序处理的。
一个有序集合中创建一个流时,流中的元素就会按出现顺序排列。
如果集合本身有序的,生成的流也是有序的,集合本身无序,生成的流也是无序的。有些集合是无序的,但某些操作有时会产生顺序
Set<Integer> numbers = new HashSet<>(asList(4,3,2,1));
List<Integer> sameOrder = numbers.stream().sorted().collect(toList());
assertEquals(asList(1,2,3,4),sameOrder);
9.数据分块
一个常用的流操作是将一个集合拆分成两个集合,如果分两次filter,会产生两个流。
我们可以使用partitioningBy收集器,它接受一个流,并将其拆分成两部分。
public Map<Boolean,List<Artist>> bandsAndSoloRef(Stream<Artist> artists)
{
return artists.collect(partitioningBy(Artist::isSolo));
}
10.数据分组
public Map<Boolean,List<Album>> albumByArtist(Stream<Album> albums)
{
return albums.collect(partitioningBy(albums::getMainMusician));
}
11.字符串
有一个集合列表,期望输出为"[a,b,c,d,e,f]",以前可能使用for循环,使用stringBuilder来拼接数据,现在流中:
artists.stream().map(Artist::getName)
.collect(Collectors.joining(",","[","]"));
12 调试
- 使用foreach记录中间值,这种方式有点幼稚
album.getMusicians().filter(artist -> artist.getName().startWith("The"))
.map(artist->artist.getNationality())
.forEach(nationality -> System.out.printLn("Fount" + nationality));
- 使用peek
Set<String> nationalities = album.getMusicians().filter(artist -> artist.getName().startWith("The"))
.map(artist->artist.getNationality())
.peek(nation -> System.out.printLn("Fount" + nation))
.collect(Collectors.<String>toSet());
使用peek还能以同样的方式,将输出结果定向到现有的日志系统中,比如log4j,slf4j;