java8新特性-Lambda表达式-Stream API
Java8中有两个最为重要的改变。第一个是 Lambda 表达式,第二个就是Stream API (java.util.stream.*)。
Stream(流) 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
流(Stream)到底是什么呢?
流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。集合讲的是数据,流讲的是计算。
注意:
- Stream 它自己不会存储元素。
- Stream 不会改变源对象。它会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的(惰性求值)。它会等到需要结果的时候才执行(终止操作时一次性全部处理)。
Stream的操作(三个步骤)
-
创建Stream
一个数据源(如:集合、数组),获取一个流。
-
中间操作
一个中间操作链,对数据源的数据进行处理
-
终止操作(终端操作)
一个终止操作,执行中间操作链,产生结果。

- 创建Stream
@Test
public void test1(){
//创建Stream
//1. 可以通过Collection系列集合提供的stream()或parallelStream()获取流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2. 通过Arrays中的静态方法stream()获取流
Integer[] arr = new Integer[10];
Stream<Integer> stream2 = Arrays.stream(arr);
//3. 通过Stream类中的静态方法 of() 获取流
Stream<String> stream3 = Stream.of("f", "j", "h");
//4. 创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println); //limit取前十条
//生成
Stream.generate(Math::random).limit(5).forEach(System.out::println);
}

- 中间操作
-
筛选与切片
filter——接收Lambda,从流中排除某些元素。
limit(n)——截断流,使其元素不超过给定数量。
skip(n)——跳过元素,返回一个去掉前n个元素的流,若流中元素不足n个,则返回一个空流。
distinct——去重,通过流所生成元素的hashCode()和equals()去除重复元素。
@Test public void test2(){ List<Animal> animals = Arrays.asList( new Animal("cat",1), new Animal("dog",2), new Animal("bird",3), new Animal("fish",4), new Animal("fish",4) ); //中间操作:不会执行任何操作 //内部迭代,迭代操作由StreamAPI完成 System.out.println("----filter----"); Stream<Animal> stream = animals.stream().filter((x) -> x.getAge() > 2); //终止操作:一次性执行全部内容 stream.forEach(System.out::println); System.out.println("----limit----"); animals.stream().limit(1).forEach(System.out::println); System.out.println("----skip----"); animals.stream().skip(2).forEach(System.out::println); System.out.println("----distinct----"); //切记实体类需要重写hashcode()和equals()方法 animals.stream().distinct().forEach(System.out::println); }![]()
-
映射
map——接收Lambda,讲元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
例如{{a,b,c},{d,e,f}} ->{a,b,c,d,e,f},类似于List的add和addAll方法。
@Test public void test3(){ List<String> list = Arrays.asList("aa","bb","cc"); List<Animal> animals = Arrays.asList( new Animal("cat",1), new Animal("dog",2), new Animal("bird",3), new Animal("fish",4), new Animal("fish",4) ); list.stream().map((x)->x.toUpperCase()).forEach(System.out::print); System.out.println(); animals.stream().map(Animal::getName).distinct().forEach(System.out::println); System.out.println("--------flatMap---------"); Stream<Stream<Character>> streamMap = list.stream().map(TestStreamAPI::filterCharacter);//流中流 streamMap.forEach((sm)->{ sm.forEach(System.out::print); }); //下面代码与上面等价 System.out.println(); Stream<Character> streamFlatMap = list.stream().flatMap(TestStreamAPI::filterCharacter); streamFlatMap.forEach(System.out::print); } public static Stream<Character> filterCharacter(String str){ List<Character> list = new ArrayList<>(); for (Character ch : str.toCharArray()){ list.add(ch); } return list.stream(); }![]()
-
排序
sorted()——自然排序(Comparable)
sorted(Comparator comparator)——定制排序(Comparator)
@Test public void test4(){ List<String> list = Arrays.asList("dd","aa","bb","cc"); list.stream().sorted().forEach(System.out::print); System.out.println(); System.out.println("-------自定义比较-------"); List<Animal> animals = Arrays.asList( new Animal("cat",1), new Animal("fish",4), new Animal("dog",2), new Animal("bird",3), new Animal("fish",4) ); animals.stream().sorted((x,y)->{ if (x.getAge() == y.getAge()){ return x.getName().compareTo(y.getName()); }else{ return Integer.compare(x.getAge(),y.getAge()); } }).forEach(System.out::println); }![]()
- 终止操作
-
查找与匹配
allMatch——检查是否匹配所有元素。
anyMatch——检查是否至少匹配一个元素。
noneMatch——检查是否所有元素都不匹配。
findFirst——返回第一个元素。
findAny——返回当前流中任意元素。
count——返回流中元素的总个数。
max——返回流中最大值。
min——返回流中最小值。
@Test public void test5(){ //查找与匹配 List<Animal> animals = Arrays.asList( new Animal("cat",1), new Animal("dog",2), new Animal("bird",3) ); System.out.println("--------allMatch--------"); boolean b1 = animals.stream().allMatch((x) -> x.getName().equals("cat")); System.out.println("是否匹配所有元素:"+b1); System.out.println("--------anyMatch--------"); boolean b2 = animals.stream().anyMatch((x) -> x.getName().equals("cat")); System.out.println("是否至少有一个是匹配的:"+b2); System.out.println("--------noneMatch--------"); boolean b3 = animals.stream().noneMatch((x) -> x.getName().equals("cat")); System.out.println("是否所有元素都不匹配:"+b3); System.out.println("--------findFirst--------"); Optional<Animal> first = animals.stream().findFirst(); System.out.println("第一个元素是"+first.get()); System.out.println("--------findAny--------"); Optional<Animal> any = animals.parallelStream().findAny(); System.out.println("任意的一个元素是"+any.get()); System.out.println("--------count--------"); long count = animals.stream().count(); System.out.println("流中元素的总个数是"+count); System.out.println("--------max--------"); Optional<Animal> max = animals.stream().max((x,y)->{ if (x.getAge()==y.getAge()){ return x.getName().compareTo(y.getName()); } return Integer.compare(x.getAge(), y.getAge()); }); System.out.println("流中最大值是"+max.get()); System.out.println("--------min--------"); Optional<Integer> min = animals.stream().map(Animal::getAge).min(Integer::compareTo); System.out.println("流中最小值是"+min.get()); }![]()
-
归约与收集
归约:T reduce(T identity, BinaryOperator
accumulator) Optional
reduce(BinaryOperator accumulator) indentity起始值,BinaryOperator二元运算,可以将流中元素反复结合起来,得到一个值。
收集:
R collect(Supplier supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner); <R, A> R collect(Collector<? super T, A, R> collector)
将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到List,Set,Map)
Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例。
@Test public void test6(){ //归约 List<Integer> list = Arrays.asList(1,2,3,4,5,6); // identity->x , 流中元素->y,结果->x,下一个流中元素->y Integer sum = list.stream().reduce(0, (x, y) -> x + y); System.out.println("list总和:"+sum); Optional<Integer> op = animals.stream().map(Animal::getAge).reduce(Integer::sum); System.out.println("animals年龄总和:"+op.get()); //收集 //Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到List,Set,Map) //Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例。 List<String> collectList = animals.stream().map(Animal::getName).collect(Collectors.toList()); System.out.println(collectList); HashSet<String> collectHashSet = animals.stream().map(Animal::getName).collect(Collectors.toCollection(HashSet::new)); System.out.println(collectHashSet); String str = animals.stream().map(Animal::getName).collect(Collectors.joining(",")); System.out.println(str); Double collectAverage = animals.stream().collect(Collectors.averagingDouble(Animal::getAge));//年龄平均值 System.out.println(collectAverage); }![]()
并行流与顺序流
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
Stream API 可以声明性的通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。
可以对比ForkJoin,ForkJoin编码较为复杂。






浙公网安备 33010602011771号