Stream API

引例:

1         List<String> strList = Arrays.asList("zhaojigang","nana","tianya","nana");
2         Stream<String> streamList = strList.stream();//集合转为stream
3         strList = streamList.distinct().filter(str->!str.equals("tianya")).sorted(String::compareTo).collect(Collectors.toList());
4         strList.forEach(System.out::println);

说明:

  • 第一行:创建数组并转为List
  • 第二行:根据List创建stream
  • 第三行:对该stream进行去重-->选择-->排序-->stream转为List
  • 第四行:遍历该List

以上代码显示了stream API的方便。当然,上边的代码可以更为简洁,如下改为一行:

Arrays.asList("zhaojigang","nana","tianya","nana").stream().distinct().filter(str->!str.equals("tianya")).sorted(String::compareTo).collect(Collectors.toList()).forEach(System.out::println);

以上代码有一个易错点:filter是选择而不是过滤,即filter是选择满足条件的元素

一、创建Stream

三种常用API:

  • 集合-->Stream:stream()
  • 数组-->Stream:Stream.of(T t)或者Arrays.stream(T[] t)
  • 任意元素-->Stream:Stream.of(T... values)

 1         List<String> strList = Arrays.asList("zhaojigang","nana","tianya","nana");
 2         Stream<String> streamList = strList.stream();//集合转为stream
 3
 4         String[] strArray = {"java","c++","c"};
 5         Stream<String> streamArray = Stream.of(strArray);//数组转为Stream
 6         Stream<String> streamArray2 = Arrays.stream(strArray);//数组转为Stream
 7
 8         Stream<String> streamPartArray = Arrays.stream(strArray, 0, 2);//转换部分数组,范围:[0,2)
 9
10         Stream<String> streamSelf = Stream.of("python","basic","php");//任意元素

还有一种:用于产生无限流的,Stream.generate(Supplier<T> s)。

二、Stream 2 array/collection/String/map

1、stream2array

1         Stream<String> strStream = Stream.of("java","c++","c","python");
2         Object[] objectArray = strStream.toArray();//只能返回Object[]
3         String[] strArray = strStream.toArray(String[]::new);//构造器引用(类似于方法引用),可以返回String[]

说明:

通过构造器引用(类似于方法引用),可以构造出具体类型的数组。

2、stream2collection

1         List<String> strList = strStream.collect(Collectors.toList());//返回List
2         Set<String> strSet = strStream.collect(Collectors.toSet());//返回set
3         ArrayList<String> strArrayList = strStream.collect(Collectors.toCollection(ArrayList::new));//收集到指定的List集合,例如收集到ArrayList

说明:

通过构造器引用,可以构造出具体类型的集合。

3、将stream中的元素拼接起来(joining()、joining(","))

1         Stream<String> strStream = Stream.of("java","c++","c","python");
2         String str = strStream.collect(Collectors.joining());//将所有字符串拼接起来,结果:javac++cpython
3         System.out.println(str);
4
5         String str2 = strStream.collect(Collectors.joining(","));//将所有字符串拼接起来,中间用","隔开,结果:java,c++,c,python
6         System.out.println(str2);

4、stream2map(toMap、toConcurrentMap)

 1         Stream<String> strStream = Stream.of("java","c++","c","python");
 2         Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), (x)->0));
 3         //Function.identity()-->返回strStream中的元素,toMap方法的我两个参数都是Function接口型的,所以第二个参数即使只放0,也不能直接写作0,可以使用如上的方式进行操作
 4
 5         for(String key : map1.keySet()){
 6             System.out.println("key:"+key+"->"+"value:"+map1.get(key));
 7         }
 8         //结果
 9         /*
10         key:python->value:0
11         key:c++->value:0
12         key:c->value:0
13         key:java->value:0
14          */

说明:

  • toMap-->stream转为map
  • Function.identity()-->返回stream中的元素

如果key重复的话,这时就会出现问题"duplicate key",采用如下方式解决(增加第三个参数):

1         Stream<String> strStream = Stream.of("java","c++","c","python","java");
2         Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), //key
3                                                                         (x)->0,             //value
4                                                                         (existingValue, newValue) -> existingValue));//如果key重复,取旧值

需要指定返回map的具体类型(增加第四个参数)。

1         Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), //key
2                                                                         (x)->0,             //value
3                                                                         (existingValue, newValue) -> existingValue,//如果key重复,取旧值
4                                                                         TreeMap::new));//返回TreeMap

注意:每一个toMap就会对应一个相应的toConcurrentMap

5、groupingBy partitioningBy

 1         /***************************groupingBy partitioningBy**************************/
 2         Stream<Locale> localeStream = Stream.of(Locale.getAvailableLocales());
 3         Map<String, List<Locale>> country2localeList = localeStream.collect(Collectors.groupingBy(Locale::getCountry));//根据国家分组,groupBy的参数是分类器
 4         List<Locale> locales = country2localeList.get("CH");
 5
 6         Map<String, Set<Locale>> country2localeSet = localeStream.collect(Collectors.groupingBy(Locale::getCountry, Collectors.toSet()));//根据国家分组,groupBy的参数是分类器,返回set
 7         Set<Locale> localeSet = country2localeSet.get("CH");
 8
 9         Map<Boolean, List<Locale>> country2locales = localeStream.collect(Collectors.partitioningBy(locale->locale.getLanguage().equals("en")));//分成两组,一组为true(即语言是en的),一组为false(即语言不是en的)
10         List<Locale> trueLocale = country2locales.get(true);

三、filter(Predicate p)

注意:是选择而非过滤

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2         streamSelf.filter(str->str.startsWith("p")).forEach(System.out::println);

注意:

  • stream也是可以foreach的,没必要一定要转化成集合再foreach

更好的写法可能是下边这种:

1         Predicate<String> startCondition = str->str.startsWith("p");
2         streamSelf.filter(startCondition).forEach(System.out::println);

说明:将条件(通常是lambda表达式)抽取出来。这种方式在多个条件的情况下比较清晰。

注意:函数式接口 = lambda表达式 (即lambda表达式只能返回为函数式接口)

1         Stream<String> s = Stream.of("java1","java3","java","php12");
2         Predicate<String> condition1 = str->str.length()==5;//条件1
3         Predicate<String> condition2 = str->str.startsWith("j");//条件2
4         s.filter(condition1.and(condition2)).forEach(System.out::println);//and条件

说明:

多条件运算:and or

四、map(Function mapper)

作用:对流中的每一个元素进行操作。

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2         streamSelf.map(String::toUpperCase).forEach(System.out::println);

说明:将流内的每一个String全部转换为了大写。

五、reduce 

作用:对stream中的每一个元素做聚合操作。

1         Stream<Integer> reduceStream = Stream.of(1,2,3,4,5);
2         Optional<Integer> sumOption = reduceStream.reduce((x,y)->x+y);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算(注意:如果stream为null的话,就会产生无效的结果,需要使用Optional接收)
3         //Optional<Integer> sumOption = reduceStream.reduce(Integer::sum);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算
4
5         Integer result = reduceStream.reduce(0, Integer::sum);//0为标识值,即计算:0+1+2+。。+5,如果整个stream为null,就返回标识值。
6         System.out.println(result);

注意:以上是reduce的简单形式,即内联函数是(T,T)->T,即返回值和参数类型是一样的,返回值和参数类型不同的场景需要自己编写函数(用的较少)

六、Optional

两种用法:

  • ifPresent(xxx):存在的就执行xxx,不存在就什么都不执行
  • orElse(xxx):存在就返回存在的值,不存在就返回xxx(可以理解为是默认值)

1         Stream<String> optionalStream = Stream.of("java","python","basic");
2         Optional<String> optionValue = optionalStream.filter(str->str.startsWith("p")).findFirst();
3         optionValue.ifPresent(str->System.out.println(str));//if optionalValue为true,即str存在,则输出str,当然也可以使用如下
4         String str = optionValue.orElse("xxx");//如果optionValue为false,即不存在以p开头的字符串时,使用"xxx"来替代
5         System.out.println(str);

七、limit skip contact

1、limit(long size)

作用:截取stream的前size个元素。

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2         streamSelf.limit(2).forEach(System.out::println);//截取前两个

2、skip(long size)

作用:跳过stream的钱size个元素

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2         streamSelf.skip(2).forEach(System.out::println);//跳过前两个

3、contact(Stream<T>,Stream<T>)

作用:拼接两个stream

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2         Stream<String> streamSelf2 = Stream.of("python2","basic2","php2");
3         Stream.concat(streamSelf, streamSelf2).forEach(System.out::println);

八、聚合函数 count max min findFirst findAny anyMatch allMatch noneMatch

1         Stream<String> streamSelf = Stream.of("python","basic","php","b");
2         System.out.println(streamSelf.count());//计算流中的元素个数
3         Optional<String> largest = streamSelf.max(String::compareToIgnoreCase);//寻找最大值
4         if(largest.isPresent()){
5             System.out.println(largest.get());
6         }

说明:min函数也一样。

注意:Optional的使用,上边的是最差的一种形式,见"六"。

 1         Optional<String> firstMatch = streamSelf.filter(str->str.startsWith("b")).findFirst();//寻找第一个符合条件的元素
 2         firstMatch.ifPresent(System.out::println);//这是Optional的第一种用法
 3
 4         Optional<String> anyMatch = streamSelf.parallel().filter(str->str.startsWith("b")).findAny();//返回集合中符合条件的任意一个元素,对于并行处理非常好(因为多个线程只要有一个线程找到了,整个计算就会结束)
 5         if(anyMatch.isPresent()){
 6             System.out.println(anyMatch.get());//这里的结果可能是b,有可能是basic
 7         }
 8
 9         boolean isAnyMatch = streamSelf.parallel().anyMatch(str->str.startsWith("c"));//集合中是否有一个满足条件
10         System.out.println(isAnyMatch);
11
12         Stream<String> streamSelf3 = Stream.of("basic","b");
13         boolean isAllMatch = streamSelf3.parallel().allMatch(str->str.startsWith("b"));//集合中是否所有元素都满足条件
14         System.out.println(isAllMatch);
15
16         boolean isAllNotMatch = streamSelf.parallel().noneMatch(str->str.startsWith("p"));//集合中是否没有一个元素满足条件
17         System.out.println(isAllNotMatch);

注意:

  • optional的最佳用法:ifPresent()-->如果有就输出,如果没有,什么都不做
  • parallel():将stream转为并行流,并行流的使用一定要注意线程安全

九、原始类型流

  • IntStream:int、short、char、byte、boolean
  • LongStream:long
  • DoubleStream:double、float
时间: 2024-10-05 04:04:53

Stream API的相关文章

Java 8新特性之旅:使用Stream API处理集合

在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda表达式增强方法”中,我已经深入解释并演示了通过lambda表达式和方法引用来遍历集合,使用predicate接口来过滤集合,实现接口的默认方法,最后还演示了接口静态方法的实现. 源代码都在我的Github上:可以从 这里克隆. 内容列表 使用流来遍历集合. 从集合或数组创建流. 聚合流中的值. 1.

Java 8: Lambdas和新的集合Stream API

Lambda是Java8的主要特色,Java 8: Lambdas & Java Collections | zeroturnaround.com一文介绍了使用Lambda集合处理大量数据的方法. 首先Java集合引入了内部遍历,原来 LambdaJ下面这种方法也可以在Java8中实现: List<Person> persons = asList(new Person("Joe"), new Person("Jim"), new Person(&

Atitit 实现java的linq 以及与stream api的比较

1.1. Linq 和stream api的关系,以及主要优缺点1 1.2. Linq 与stream api的适用场景1 1.3. Java中的linq1 Linq来源于sql,而我们知道在数据查询领域,sql是标准化的一个dsl.. 1.1. Linq 和stream api的关系,以及主要优缺点 Stream更加的通用化,linq比较专一化,专注于数据查询的dsl..Linq就是特殊化的stream.. 此外,linq更加的dsl ,更加方便简洁.. stream相对底层一些,更加灵活,但

第二章 Stream API

引例: 1 List<String> strList = Arrays.asList("zhaojigang","nana","tianya","nana"); 2 Stream<String> streamList = strList.stream();//集合转为stream 3 strList = streamList.distinct().filter(str->!str.equals(&

Java8 Stream API

Stream是Java8中,操作集合的一个重要特性. 从iteration到Stream操作 当你操作一个集合的时候,你通常的做法是迭代每一个元素,然后处理你想要的事情.举个例子: String contents = new String(Files.readAllBytes( Paths.get("alice.txt")), StandardCharsets.UTF_8); // 读取文件到字符串中 List<String> words = Arrays.asList(c

PHP Stream API初探

和SPL一样,在PHP手册里面,流被划为"other basic extensions"里面,是PHP开发中一个容易被忽视的函数系列.但其实在C++/Java中,流是一个很重要的概念.流的概念源于UNIX中的管道,管道是一条不间断的字节流,用来实现程序和进程间通信,或者读写外设,外部文件等. 流的概念是在php 4.3.0中被引入的.我们知道,文件操作,网络操作,数据压缩操作等具有一定的共性,比如线性的读/写或者随机定位,流就是用来把这些操作抽象出一个统一的接口以供开发者们使用,因此&

Java8新特性Stream API与Lambda表达式详解(1)

1 为什么需要Stream与Lambda表达式? 1.1  为什么需要Stream Stream作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream.Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggr

Java 8 Stream API具体解释

Java 8 Stream API具体解释 一.Stream API介绍 Java 8引入了全新的Stream API,此Stream与Java I/O包里的InputStream和OutputStream是全然不同的概念,它不同于StAX对XML解析的Stream,也不同于Amazon Kinesis对大数据实时处理的Stream.Stream API更像具有Iterable的集合类,但行为和集合类又有所不同,它是对集合对象功能的增强.专注于对集合对象进行各种非常便捷.高效的聚合操作或大批量数

Upgrading to Java 8——第四章 The Stream API

在这章中我们将学习Stream API,在JDK 8 中的一项新的特性.为了理解这一章的主题,你需要知道如何使用Lambda表达式和java.util.function里的预定义的函数式接口. 一个Stream 类似于一个管道,但它里面运输的不是水和石油,而是把数据从源头运输到目的地.根据传递的方式,一个stream可以是并行和并发的.并行的stream运行在多核的CPU的机器上会很有用. 乍一看,一个stream就像是一个集合容器,但是,它不是一个数据结构用来存储对象,它只是负责移动对象,所以