上一篇文章 Java 8之stream介绍和使用 中讲解了stream
的定义和用法,简单介绍几个最基本最经常使用的方法,其实stream
还有更强大的功能,这篇文章就会给你们介绍stream
的进阶用法。segmentfault
在上一篇文章中咱们介绍了使用filter
方法来筛选元素,filter
方法接受一个Predicate
类型的参数,咱们能够传入一个Lamada表达式或者方法引用,原理在 Java 8之方法引用和Lambda表达式 中已经将结果。咱们其实是传入了一个条件,而后筛选出符合条件的元素,例以下面的这行代码就是筛选出年龄大于20的人。数组
List<Person> list = peoples.stream().filter(person -> person.getAge()>20).collect(toList());
实际上stream
还有别的方法能够进行筛选,下面咱们来介绍几个经常使用的。函数
distinct
,这个方法能够帮助咱们去重code
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);
limit
,这个方法可让咱们只取stream中的前几个,值得注意的是当咱们用Set集合来存储元素时,由于Set是无序的,因此每次咱们取到的前几个元素也会是无序的。对象
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream().limit(3).forEach(System.out::println);
skip
,这个方法可让咱们跳过元素,跳过多少个元素由咱们指定。ip
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream().skip(3).forEach(System.out::println);
咱们常常遇到从对象中抽取本身须要的元素放入一个新的类型的集合中的状况,这就是映射操做,而stream
在这方面也提供了很是强大的支持。字符串
map
,这个方法接受一个Lambda表达式,它会遍历整个流把这个函数做用到每一个元素上,而后把输出的结果放到一个新流中。get
// 获取每一个元素的name属性放入一个新流中,而后把这个流转为List类型。 List<Person> names = peoples.stream().map(Person::getName).collect(toList()); // 获取每一个元素的字符串长度放入新流中,而后转为List类型。 List<String> words = Arrays.asList("AA", "B", "CCC", "DDDDDD"); List<Integer> wordLengths = words.stream().map(String::length).collect(toList());
flatmap
,这个方法比较特殊,它的做用是把多个相同类型的流连成一个流,咱们看下面的代码,目的是为了把集合中的字符串都拆成单个字符而后放到一个集合,可是若是直接用map
方法的话返回的List
是String[]
类型的,这是由于word.split("")
返回的结果就是这个类型的。string
List<String> words = Arrays.asList("Hello", "world"); List<String[]> list = words.stream().map(word -> word.split("")).collect(toList());
在这里要提到Arrays.stream()
这个方法,它的做用是接受一个数组,而后把这个数组里的元素转为一个流,因此咱们能够尝试使用这个方法来改进下上面的代码。可是咱们发现仍是有问题,返回集合类型是Stream<String>
,由于map(Arrays::stream)
把数组里的每一个元素都弄成了一个流。it
List<String> words = Arrays.asList("Hello", "world"); List<Stream<String>> list = words.stream().map(word -> word.split("")) .map(Arrays::stream).collect(toList());
如今flatmap
的做用就出来了,咱们把代码改进下,改为使用flatmap
接受Arrays::stream
,它的做用正是在上面map(Arrays::stream)
的基础上把集合里的流里面的元素合并成一个流,因此返回的List
类型就是String
类型的。
List<String> words = Arrays.asList("Hello", "world"); List<String> list = words.stream().map(word -> word.split("")) .flatmap(Arrays::stream).collect(toList());
stream一样也提供了不少方法来检查集合中是否包含了某个指定的值。注意,这些方法都属于 终端操做 ,也就是说调用了这些方法就会关闭流。
allMatch
List<String> numbers = Arrays.asList("Hello", "World"); boolean flag = numbers.stream().allMatch(string -> string.contains("z")); System.out.println(flag);
anyMatch
,这个方法会检查流中是否至少有一个元素匹配给定的值,返回一个boolean值。
List<String> numbers = Arrays.asList("Hello", "World"); boolean flag = numbers.stream().anyMatch(string -> string.contains("z")); System.out.println(flag);
noneMatch
,这个方法则是和allMatch
方法作相反的操做。
List<String> numbers = Arrays.asList("Hello", "World"); boolean flag = numbers.stream().noneMatch(string -> string.contains("z")); System.out.println(flag);
对于集合的操做最重要的就是从中查找符合条件的数据了,咱们来看下面的方法。
findAny
,这个方法须要配合filter
方法使用,返回把筛选出来的第一个元素。注意,这里返回的是Optional
类型的对象,这个对象是Java 8新增的专门为了防止返回数据的时候遇到null
的状况,后续再做详细了解,目前只须要知道它有个isPresent
方法来判断元素是否为空,get
方法用来取值。
List<String> numbers = Arrays.asList("Hello", "World"); Optional<String> optional= numbers.stream().filter(string -> string.contains("l")).findAny(); if(optional.isPresent()){ System.out.println(optional.get()); }
findFirst
,这个方法是用来取流中第一个元素的,目前看来好像没什么用,可是有时候咱们可能会对流进行复杂的筛选,再选取筛选后的流中第一个元素。
List<String> numbers = Arrays.asList("Hello", "World"); Optional<String> optional= numbers.stream().findFirst(); System.out.println(optional.toString());
归约就是把整个流归约成一个值的操做,好比求集合中最大的元素、全部元素值的和之类的操做。
reduce
,这个方法就是用来对元素的值进行操做的,咱们这里作加法运算。它接受两个参数,第一个是初始值,就是开始计算前就已经有一个数值了。第二个参数是一个Lambda表达式,用来对各个元素作计算。
List<Integer> list = Arrays.asList(1,2,3,4,5); int sum = list.stream().reduce(0,(a,b) -> a - b); System.out.println(sum);
在Java 8中Integer
中新增了一个sum
方法,它的做用和上面的Lambda表达效果同样,因此咱们可使用这个方法的方法引用来简化代码。
List<Integer> list = Arrays.asList(1,2,3,4,5); int sum = list.stream().reduce(0,Integer::sum); System.out.println(sum);
咱们还能够用这个方法来求最大值和最小值,在Integer
中还新增了min
、max
方法,等同于(x, y) -> x < y ? x : y
、(x, y) -> x > y ? x : y
,这样咱们就能够求出流中的最大值和最小值了。
Optional<Integer> min = numbers.stream().reduce(Integer::min); Optional<Integer> min = numbers.stream().reduce(Integer::max);
以上就是stream的筛选、查找、匹配和归约操做中比较经常使用的方法了,下面还会介绍分组、分区等功能。