0
点赞
收藏
分享

微信扫一扫

开始使用流


  • Java 8 中的 Stream 俗称为流,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念
  • Stream 用于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作
  • Stream API 借助于 Lambda 表达式,极大的提高编程效率和程序可读性
  • 同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势
  • 通过下面的例子我们可以初步体会到使用 Stream 处理集合的便利性


初探Stream


  • 有如下一个 List 集合,现要从中筛选出以​​J​​ 开头的元素,然后转换为大写,最后输出结果
  • Java 8之前我们是这样做的:


/**
 * @author BNTang
 **/
public class Demo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("Java", "JavaScript", "python", "PHP", "C#", "Golang", "Swift");
        List<String> filterList = new ArrayList<>();
        for (String str : list) {
            if (str.startsWith("J")) {
                filterList.add(str.toUpperCase());
            }
        }
        for (String str : filterList) {
            System.out.println(str);
        }
    }
}


  • 为了筛选集合我们进行了两次外部迭代,并且还创建了一个用来临时存放筛选元素的集合对象
  • 借助Java 8中的Stream我们可以极大的简化这个处理过程:


/**
 * @author BNTang
 **/
public class Demo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("Java", "JavaScript", "python", "PHP", "C#", "Golang", "Swift");
        list.stream()
                .filter(s -> s.startsWith("J"))
                .map(String::toUpperCase)
                .forEach(System.out::println);
    }
}

是不是很方便?上面的例子中,集合使用 ​​stream​​​ 方法创建了一个流,然后使用 ​​filter​​​ 和 ​​map​​ 方法来处理这个集合,它们统称为 中间操作。中间操作都会返回另一个流,以便于将各种对集合的操作连接起来形成一条流水线。最后我们使用了 ​​forEach​​ 方法迭代筛选结果,这种位于流的末端,对流进行处理并且生成结果的方法称为 终端操作

总而言之,流的使用一般包括三件事情:


  • 一个数据源(如集合)来执行一个查询
  • 一个中间操作链,形成一条流的流水线
  • 一个终端操作,执行流水线,并能生成结果


下表列出了流中常见的中间操作和终端操作:

操作

类型

返回类型

使用的类型 / 函数式接口

函数描述符

filter

中间

Stream<T>

Predicate<T>

T -> boolean

distinct

中间

Stream<T>

skip

中间

Stream<T>

long

limit

中间

Stream<T>

long

map

中间

Stream<R>

Function<T, R>

T -> R

flatMap

中间

Stream<R>

Function<T, Stream<R>>

T -> Stream<R>

sorted

中间

Stream<T>

Comparator<T>

(T, T) -> int

anyMatch

终端

boolean

Predicate<T>

T -> boolean

noneMatch

终端

boolean

Predicate<T>

T -> boolean

allMatch

终端

boolean

Predicate<T>

T -> boolean

findAny

终端

Optional<T>

findFirst

终端

Optional<T>

forEach

终端

void

Consumer<T>

T -> void

collect

终端

R

Collector<T, A, R>

reduce

终端

Optional<T>

BinaryOperator<T>

(T, T) -> T

count

终端

long


  • 下面详细介绍这些操作的使用
  • 除了特殊说明,使用下面这个集合作为演示:


List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);

中间操作

filter


  • Streams 接口支持​​filter​​​ 方法,该方法接收一个​​Predicate<T>​​​,函数描述符为​​T -> boolean​​,用于对集合进行筛选,返回所有满足的元素:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter(s&nbsp;-&gt;&nbsp;s.contains(&quot;#&quot;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 结果输出​​C#​


distinct


  • ​distinct​​​ 方法用于​​排除​​ 流中重复的元素,类似于 SQL 中的 distinct 操作
  • 比如筛选中集合中所有的偶数,并排除重复的结果:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt;&nbsp;numbers&nbsp;=&nbsp;Arrays.asList(1,&nbsp;2,&nbsp;1,&nbsp;3,&nbsp;3,&nbsp;2,&nbsp;4);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numbers.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter(i&nbsp;-&gt;&nbsp;i&nbsp;%&nbsp;2&nbsp;==&nbsp;0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.distinct()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 结果输出​​2 4​


skip


  • ​skip(n)​​​ 方法用于跳过流中的​​前n个元素​​,如果集合元素小于n,则返回空流
  • 比如筛选出以​​J​​ 开头的元素,并排除第一个:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter(s&nbsp;-&gt;&nbsp;s.startsWith(&quot;J&quot;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.skip(1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 结果输出​​JavaScript​


limit


  • ​limit(n)​​​ 方法返回一个长度不超过​​n​​​ 的流,比如下面的例子将输出​​Java JavaScript python​​:
  • 例如你输入的 3,返回的就是3,不会超过3


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.limit(3)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

map


  • ​map​​ 方法接收一个函数作为参数
  • 这个函数会被应用到每个元素上,并将其映射成一个新的元素
  • 如:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.map(String::length)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 结果输出​​4 10 6 3 2 6 5 3 4​



  • ​map​​​ 还支持将流特化为指定的原始类型的流,如通过​​mapToInt​​​,​​mapToDouble​​​ 和​​mapToLong​​​ 方法,可以将流转换为​​IntStream​​​,​​DoubleStream​​​ 和​​LongStream​
  • 特化后的流支持​​sum​​​,​​min​​​ 和​​max​​ 方法来对流中的元素进行计算
  • 比如:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt;&nbsp;numbers&nbsp;=&nbsp;Arrays.asList(1,&nbsp;2,&nbsp;1,&nbsp;3,&nbsp;3,&nbsp;2,&nbsp;4);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IntStream&nbsp;intStream&nbsp;=&nbsp;numbers.stream().mapToInt(a&nbsp;-&gt;&nbsp;a);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(intStream.sum());
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 也可以通过下面的方法,将​​IntStream​​​ 转换为​​Stream​​:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt;&nbsp;numbers&nbsp;=&nbsp;Arrays.asList(1,&nbsp;2,&nbsp;1,&nbsp;3,&nbsp;3,&nbsp;2,&nbsp;4);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IntStream&nbsp;intStream&nbsp;=&nbsp;numbers.stream().mapToInt(a&nbsp;-&gt;&nbsp;a);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stream&lt;Integer&gt;&nbsp;s&nbsp;=&nbsp;intStream.boxed();
&nbsp;&nbsp;&nbsp;&nbsp;}
}

flatMap


  • ​flatMap​​ 用于将多个流合并成一个流,俗称流的扁平化
  • 这么说有点抽象,举个例子,比如现在需要将 list 中的各个元素拆分为一个个字母,并过滤掉重复的结果,你可能会这样做:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.map(s&nbsp;-&gt;&nbsp;s.split(&quot;&quot;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.distinct()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 输出结果如下:


[Ljava.lang.String;@58372a00
[Ljava.lang.String;@4dd8dc3
[Ljava.lang.String;@6d03e736
[Ljava.lang.String;@568db2f2
[Ljava.lang.String;@378bf509
[Ljava.lang.String;@5fd0d5ae
[Ljava.lang.String;@2d98a335
[Ljava.lang.String;@16b98e56
[Ljava.lang.String;@7ef20235


  • 这明显不符合我们的预期
  • 实际上在​​map(s -> s.split(""))​​​ 操作后,返回了一个​​Stream<String[]>​​​ 类型的流,所以输出结果为每个数组对象的句柄,而我们真正想要的结果是​​Stream<String>​​!
  • 在 Stream 中,可以使用​​Arrays.stream()​​ 方法来将数组转换为流,改造上面的方法:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.map(s&nbsp;-&gt;&nbsp;s.split(&quot;&quot;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.map(Arrays::stream)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.distinct()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 输出结果如下:


java.util.stream.ReferencePipeline$Head@568db2f2
java.util.stream.ReferencePipeline$Head@378bf509
java.util.stream.ReferencePipeline$Head@5fd0d5ae
java.util.stream.ReferencePipeline$Head@2d98a335
java.util.stream.ReferencePipeline$Head@16b98e56
java.util.stream.ReferencePipeline$Head@7ef20235
java.util.stream.ReferencePipeline$Head@27d6c5e0
java.util.stream.ReferencePipeline$Head@4f3f5b24
java.util.stream.ReferencePipeline$Head@15aeb7ab


  • 因为上面的流经过​​map(Arrays::stream)​​​ 处理后,将每个数组变成了一个新的流,返回结果为流的数组​​Stream<String>[]​​,所以输出是各个流的句柄
  • 我们还需将这些新的流连接成一个流,使用​​flatMap​​ 来改写上面的例子:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.map(s&nbsp;-&gt;&nbsp;s.split(&quot;&quot;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.flatMap(Arrays::stream)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.distinct()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(s&nbsp;-&gt;&nbsp;System.out.print(s&nbsp;+&nbsp;&quot;&nbsp;&quot;));
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 输出结果如下:


J a v S c r i p t y h o n P H C # G l g w f + R u b


  • 和​​map​​​ 类似,​​flatMap​​​ 方法也有相应的原始类型特化方法,如​​flatMapToInt​​ 等


终端操作

anyMatch


  • ​anyMatch​​​ 方法用于判断流中是否有符合判断条件的元素,返回值为​​boolean类型​
  • 比如判断 list 中是否含有​​SQL​​ 元素:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.anyMatch(s&nbsp;-&gt;&nbsp;&quot;SQL&quot;.equals(s)));
&nbsp;&nbsp;&nbsp;&nbsp;}
}

allMatch


  • ​allMatch​​​ 方法用于判断流中是否所有元素都满足给定的判断条件,返回值为​​boolean类型​
  • 比如判断 list 中是否所有元素长度都不大于10:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.allMatch(s&nbsp;-&gt;&nbsp;s.length()&nbsp;&lt;=&nbsp;10));
&nbsp;&nbsp;&nbsp;&nbsp;}
}

noneMatch


  • ​noneMatch​​​ 方法用于判断流中是否所有元素都不满足给定的判断条件,返回值为​​boolean类型​
  • 比如判断 list 中不存在长度大于10的元素:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.noneMatch(s&nbsp;-&gt;&nbsp;s.length()&nbsp;&gt;&nbsp;10));
&nbsp;&nbsp;&nbsp;&nbsp;}
}

findAny


  • ​findAny​​ 方法用于返回流中的任意元素的 Optional 类型
  • 例如筛选出 list 中任意一个以​​J​​ 开头的元素,如果存在,则输出它:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter(s&nbsp;-&gt;&nbsp;s.startsWith(&quot;J&quot;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.findAny()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.ifPresent(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

findFirst


  • ​findFirst​​ 方法用于返回流中的第一个元素的 Optional 类型
  • 例如筛选出 list 中长度大于 5 的元素,如果存在,则输出第一个:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter(s&nbsp;-&gt;&nbsp;s.length()&nbsp;&gt;&nbsp;5)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.findFirst()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.ifPresent(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

reduce


  • ​reduce​​函数从字面上来看就是压缩,缩减的意思,它可以用于数字类型的流的求和,求最大值和最小值。如对numbers中的元素求和:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt;&nbsp;numbers&nbsp;=&nbsp;Arrays.asList(1,&nbsp;2,&nbsp;1,&nbsp;3,&nbsp;3,&nbsp;2,&nbsp;4);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(numbers.stream().reduce(0,&nbsp;Integer::sum));
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • ​reduce​​​ 函数也可以不指定初始值,但这时候将返回一个​​Optional​​ 对象,比如求最大值和最小值:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt;&nbsp;numbers&nbsp;=&nbsp;Arrays.asList(1,&nbsp;2,&nbsp;1,&nbsp;3,&nbsp;3,&nbsp;2,&nbsp;4);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numbers.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.reduce(Integer::max)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.ifPresent(System.out::println);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numbers.stream()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.reduce(Integer::min)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.ifPresent(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

forEach


  • ​forEach​​ 用于迭代流中的每个元素,最为常见的就是迭代输出,如:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.stream().forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

count


  • ​count​​ 方法用于统计流中的元素的个数,比如:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(list.stream().count());
&nbsp;&nbsp;&nbsp;&nbsp;}
}

collect


  • ​collect​​​ 方法用于收集流中的元素,并放到不同类型的结果中,比如​​List​​​、​​Set​​​ 或者​​Map​
  • 举个例子:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;list&nbsp;=&nbsp;Arrays.asList(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;python&quot;,&nbsp;&quot;PHP&quot;,&nbsp;&quot;C#&quot;,&nbsp;&quot;Golang&quot;,&nbsp;&quot;Swift&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;filterList&nbsp;=&nbsp;list.stream().filter(s&nbsp;-&gt;&nbsp;s.startsWith(&quot;J&quot;)).collect(Collectors.toList());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(filterList);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 如果需要以​​Set​​​ 来替代​​List​​​,只需要使用​​Collectors.toSet()​​ 就好了


流的构建


  • 除了使用集合对象的​​stream​​ 方法构建流之外,我们可以手动构建一些流


数值范围构建


  • ​IntStream​​​ 和​​LongStream​​​ 对象支持​​range​​​ 和​​rangeClosed​​ 方法来构建数值流
  • 这两个方法都是第一个参数接受起始值,第二个参数接受结束值
  • 但​​range​​​ 是不包含结束值的,而​​rangeClosed​​ 则包含结束值
  • 比如对 1 到 100 的整数求和:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(IntStream.rangeClosed(1,&nbsp;100).sum());
&nbsp;&nbsp;&nbsp;&nbsp;}
}

由值构建


  • 静态方法​​Stream.of​​ 可以显式值创建一个流
  • 它可以接受任意数量的参数
  • 例如,以下代码直接使用​​Stream.of​​ 创建了一个字符串流:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stream&lt;String&gt;&nbsp;s&nbsp;=&nbsp;Stream.of(&quot;Java&quot;,&nbsp;&quot;JavaScript&quot;,&nbsp;&quot;C++&quot;,&nbsp;&quot;Ruby&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 也可以使用​​Stream.empty()​​ 构建一个空流:


Stream&lt;Object&gt;&nbsp;emptyStream&nbsp;=&nbsp;Stream.empty();

由数组构建


  • 静态方法​​Arrays.stream​​ 可以通过数组创建一个流
  • 它接受一个数组作为参数
  • 例如:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int[]&nbsp;arr&nbsp;=&nbsp;{1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5};
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IntStream&nbsp;intStream&nbsp;=&nbsp;Arrays.stream(arr);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

由文件生成流


  • ​java.nio.file.Files​​ 中的很多静态方法都会返回一个流
  • 例如​​Files.lines​​ 方法会返回一个由指定文件中的各行构成的字符串流
  • 比如统计一个文件中共有多少个字:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;wordCout&nbsp;=&nbsp;0L;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;(Stream&lt;String&gt;&nbsp;lines&nbsp;=&nbsp;Files.lines(Paths.get(&quot;file.txt&quot;),&nbsp;Charset.defaultCharset()))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wordCout&nbsp;=&nbsp;lines.map(l&nbsp;-&gt;&nbsp;l.split(&quot;&quot;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.flatMap(Arrays::stream)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.count();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;ignore)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(wordCout);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

由函数构造


  • Stream API 提供了两个静态方法来从函数生成流:​​Stream.iterate​​​ 和​​Stream.generate​
  • 这两个操作可以创建所谓的无限流
  • 比如下面的例子构建了 10 个偶数:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stream.iterate(0,&nbsp;n&nbsp;-&gt;&nbsp;n&nbsp;+&nbsp;2)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.limit(10).forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • ​iterate​​ 方法接受一个初始值(在这里是0)还有一个依次应用在每个产生的新值上的 Lambda(UnaryOperator类型)
  • 这里,我们使用 Lambda​​n -> n + 2​​,返回的是前一个元素加上 2
  • 因此,​​iterate​​ 方法生成了一个所有正偶数的流:流的第一个元素是初始值0
  • 然后加上 2 来生成新的值 2,再加上 2 来得到新的值 4,以此类推



  • 与​​iterate​​​ 方法类似,​​generate​​ 方法也可让你按需生成一个无限流
  • 但​​generate​​ 不是依次对每个新生成的值应用函数,比如下面的例子生成了 5 个 0 到 1 之间的随机双精度数:


/**
 * @author BNTang
 **/
public&nbsp;class&nbsp;Demo&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stream.generate(Math::random)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.limit(5)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);
&nbsp;&nbsp;&nbsp;&nbsp;}
}


  • 输出结果如下:


0.4477477019693912
0.8866972547736678
0.6893219838296453
0.3768607796229386
0.9647978867306028

举报

相关推荐

0 条评论