13jdk1.8 Collection新特性Stream流

目标

  • Function<T, R>函数式接口

  • Predicate<T>函数式接口

  • 流与集合相比的优点

  • 流的延迟执行特点

  • 集合、映射或数组获取流

  • 常用的流操作

  • 流进行并发操作:并行流

  • 流中内容收集到集合中

collect
  • 将流中内容收集到数组中

toArray();

主要内容

  • Predicate接口

  • Function接口

  • Stream流

第1章 常用函数式接口

1.1 Predicate接口

1.1.1 概述

需要对某种类型的数据进行判断,从而得到一个boolean值结果。则可以使用java.util.function.Predicate<T>接口。

1.1.2 抽象方法:test

boolean test(T t)  根据参数t执行判断,返回true或false
  • test方法示例:

    • 定义方法:参数是Predicate接口类型,返回值是boolean类型

    • main方法调用方法判断字符串长度是否大于5

public class PredicateDemo01 {
    public static void main(String[] args){
        // 使用匿名内部类调用
        testPredicate(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length() > 5;
            }
        });
        // 使用lambda表达式简化
        testPredicate(s -> s.length()>5);
    }
​
    public static void testPredicate(Predicate<String> predicate){
        boolean b = predicate.test("helloworld");
        System.out.println(b);
    }
}

1.1.3 默认方法:and

条件判断,则存在与、或、非三种常见逻辑关系。将两个Predicate条件使用“与”逻辑连接起来实现“and”效果时,可以使用default方法and。其JDK源码为:

default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
}
  • and方法演示示例

    • 判断一个字符串包含大写“H”,且包含大写“W”

public class PredicateDemo02 {
    public static void main(String[] args) {
        // 定义字符串
        String str = "HelloWorld";
        // 条件1:判断是否包含大写H
        Predicate<String> one = s -> s.contains("H");
        // 条件2:判断是否包含大写W
        Predicate<String> two = s -> s.contains("W");
        // 判断字符串是否同时满足条件1和条件2
        // System.out.println(one.test(str) && two.test(str));
        // 简化版
        boolean b = one.and(two).test(str);
        System.out.println(b);
    }
}

1.1.4 默认方法:or

and的“与”类似,默认方法or实现逻辑关系中的“”。JDK源码为:

default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}
  • or 方法演示示例

    • 判断一个字符串包含大写H或者包含大写W”

public class PredicateDemo03 {
    public static void main(String[] args) {
        // 定义字符串
        String str = "helloworld";
        // 条件1:判断是否包含大写H
        Predicate<String> one = s -> s.contains("H");
        // 条件2:判断是否包含大写W
        Predicate<String> two = s -> {
            System.out.println("执行了吗");
            return s.contains("W");
        };
        // 判断字符串是否满足条件1和条件2的其中一个
        boolean  b = one.or(two).test(str);
        System.out.println(b);
    }
}

1.3.5 默认方法:negate

默认方法negate的JDK源代码为:

default Predicate<T> negate() {
    return (t) -> !test(t);
}

negate ! : 执行test方法之后,对结果boolean值进行“!”取反。要在test方法调用之前调用negate方法,

andor方法一样:

import java.util.function.Predicate;
​
public class Demo17PredicateNegate {
​
   private static void method(Predicate<String> predicate) {
      boolean veryLong = predicate.negate().test("HelloWorld");
      System.out.println("字符串很长吗:" + veryLong);
   }
​
   public static void main(String[] args) {
      method(s -> s.length() < 5);
   }
​
}

1.3.6 集合信息筛选

1. 需求说明

数组中有多条“姓名+性别”的信息如下,通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList

满足两个条件:

  1. 必须为女生;

  2. 姓名为4个字。

public class DemoPredicate {
​
    public static void main(String[] args) {
        String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
    }
​
}

2. 代码实现

public class PredicateDemo05 {
    public static void main(String[] args) {
        String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
​
        // 条件1:必须是女生
        // boolean test(String t)
        Predicate<String> one = s -> s.split(",")[1].equals("女");
        // 条件2:姓名为4个字
        Predicate<String> two = s -> s.split(",")[0].length() == 4;
​
        // 遍历数组
        for (String str : array) {
            // 判断str是否同时满足条件1和条件2
            if(one.and(two).test(str)){
                System.out.println(str);
            }
        }
    }
}

1.2 Function接口

1.2.1 概述

java.util.function.Function<T,R>`接口用于根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有进有出,所以称为“函数Function”。

1.2.2 抽象方法:apply

R apply(T t)   将参数t的类型从T类型转换为R类型。
  • apply方法示例:将String类型转换为Integer类型。

public class FunctionDemo01 {
    public static void main(String[] args){
        // 字符串数字
        String str = "100";
        // 将字符串数字转换为整型数字
        Function<String,Integer> f = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        };
        int num = f.apply(str);
        System.out.println(num);
​
        // 使用lambda简化匿名内部类
        // Integer apply(String t)
        Function<String,Integer> f1 = s -> Integer.parseInt(s);
        System.out.println(f1.apply("200"));
​
        // 使用方法引用简化lambda表达式
        Function<String,Integer> f2 = Integer::parseInt;
        System.out.println(f2.apply("300"));
​
    }
}

1.2.3 默认方法:andThen

Function接口中有一个默认的andThen方法,用来进行组合操作。JDK源代码如:

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
}
  • andThen方法示例:第一个操作是将字符串解析成为int数字,第二个操作是乘以10。两个操作按照前后顺序组合到一起。

public class FunctionDemo02 {
    public static void main(String[] args){
        // 字符串
        String str = "250";
        // 操作1:将字符串转换基本数据类型:"250" ==> 250
        Function<String,Integer> one = Integer::parseInt;
        // 操作2:将操作1执行的结果乘以10
        Function<Integer,Integer> two = num -> num * 10;
​
        // 执行操作1和操作2
       /* int num = one.apply(str);
        int result = two.apply(num);*/
​
        // 执行操作1和操作2:将前一个操作执行的结果作为后一个操作的参数
        int result = one.andThen(two).apply(str);
        System.out.println(result);
    }
}

1.2.4 自定义函数模型拼接

1. 需求说明

使用Function进行函数模型拼接,按照顺序需要执行的多个函数操作为:

  1. 将字符串赵丽颖,20截取数字年龄部分,得到字符串;

  2. 将上一步的字符串转换成为int类型的数字;

  3. 将上一步的int数字累加100,得到结果int数字。

2. 代码实现

public class FunctionDemo03 {
    public static void main(String[] args){
        // 字符串
        String str = "赵丽颖,20";
​
        // 操作1:"赵丽颖,20" ==> "20"
        Function<String,String> one = s -> s.split(",")[1];
        // 操作2:"20" ==> 20
        Function<String,Integer> two = Integer::parseInt;
        // 操作3:20 ==> 120
        Function<Integer,Integer> three = num ->{
            System.out.println("执行了吗");
            return  num + 100;
        };
​
        // 按顺序执行三个操作
        int result = one.andThen(two).andThen(three).apply(str);
​
        // int result = three.compose(two).compose(one).apply(str);
        System.out.println(result);
    }
}

1.3 总结:延迟方法与终结方法

常用函数式接口中,方法可分为两种:

  • 延迟方法:在拼接Lambda函数模型的方法,并不立即执行得到结果。

  • 终结方法:根据拼好的Lambda函数模型,立即执行得到结果值的方法。

通常情况下,常用的函数式接口中唯一的抽象方法为终结方法,而默认方法为延迟方法。但这并不是绝对的。

表格中进行方法分类的整理:

接口名称方法名称抽象/默认延迟/终结
Supplierget抽象终结
Consumeraccept抽象终结
 andThen默认延迟
Predicatetest抽象终结
 and默认延迟
 or默认延迟
 negate默认延迟
Functionapply抽象终结
 andThen默认延迟
 compose默认延迟

备注:JDK中更多内置的常用函数式接口,请参考java.util.function包的API文档。

第2章 Stream流

1.1 引言

​ JDK1.8更新最大的亮点除lamada表达式之外,还有极其惊艳的Stream。但Stream不是IO里面的OutputStream或InputStream之类,而是对java中Collection类功能的增强。Stream API配合lamada表达式,极大的提升了编程效率和程序可读性。Stream中支持并行和串行两种方式。

1.2 Stream流引入案例

  • 有如下集合

List<String> list = new ArrayList<>(); 
list.add("张无忌");
list.add("周芷若");
list.add("赵敏"); 
list.add("张强"); 
list.add("张三丰");
  • 按要求执行以下三个操作

    • 首先筛选所有姓张的人。

    • 然后筛选名字有三个字的人。

    • 最后进行对结果进行打印输出。

1.2.1 JDK1.8之前的实现方式

public class StreamDemo01 {
    public static void main(String[] args){
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
​
        List<String> oneList = new ArrayList<>();
        // 使用jdk1.8之前的方式实现
        for (String str : list) {
            // 判断是否是姓张的
            if(str.startsWith("张")){
                oneList.add(str);
            }
        }
​
        List<String> twoList = new ArrayList<>();
        for (String name : oneList) {
            // 判断是否是三个字
            if (name.length() == 3){
                twoList.add(name);
            }
        }
​
       /* // 打印输出twoList集合的元素
        for (String name : twoList) {
            System.out.println(name);
        }
*/
    }
}

jdk1.8前:

对集合中的元素进行操作的时,总需要对集合进行多次循环。尤其是:使用线性循环时,意味着只能遍历一次。如果希望再次遍历,只能再使用另一个循环从头开始。

jdk1.8后:

Lambda的衍生物Stream可直接遍历独个循环,未使用到的循环遍历可延迟执行.

1.2.2 Stream流的demo

public class StreamDemo02 {
    public static void main(String[] args){
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
​
        // 使用Stream流实现
        list.stream()
                .filter(s->{
                    return s.startsWith("张");
                })
                .filter(s->{
                    return s.length() == 3;
                })
                .forEach(System.out::println);
    }
}

直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印。

1.3 获取流的方式

java.util.stream.Stream<T>是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。)

获取一个流

常用方式:

  • 所有的Collection集合都可以通过stream默认方法获取流;

  • Stream接口的静态方法of可以获取数组对应的流。

1.5.1 根据Collection获取流

java.util.Collection接口中加入了default方法stream用来获取流,所以其所有实现类均可获取流。

调用集合对象的stream()方法获得Stream对象

1.5.2 根据Map获取流

java.util.Map接口不是Collection`的子接口,且其K-V数据结构不符合流元素的单一特征,所以获取对应的流需要分key、value或entry等情况:

// 获得键对应Stream流对象
Stream<String> keyStream = map.keySet().stream();
// 获得值对应Stream流对象
Stream<String> valueStream = map.values().stream();
// 获得Entry对象对应Stream流对象
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();

1.5.3 根据数组获取流

如果使用的不是集合或映射而是数组,由于数组对象不添加默认方法.

所以Stream接口中提供静态方法of:

使用Demo:

 * 通过Stream接口的静态方法of来获得
 // 字符串数组
 String[] strs = {"a"};
 // 获得流关联数组
 Stream<String> arrayStream = Stream.of(strs);

1.5.4 示例代码

public class StreamDemo01 {
    public static void main(String[] args){
        // 创建List集合
        List<String> list = new ArrayList<>();
        // 获得流对象
        Stream<String> stream01 =  list.stream();
​
        // 创建Set集合
        Set<String> set = new HashSet<>();
        Stream<String> stream02 = set.stream();
​
        // 创建Map集合
        Map<String,String> map = new HashMap<>();
        // 获得键对应Stream流对象
        Stream<String> keyStream = map.keySet().stream();
        // 获得值对应Stream流对象
        Stream<String> valueStream = map.values().stream();
        // 获得Entry对象对应Stream流对象
        Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
​
        // 字符串数组
        String[] strs = {"a"};
        // 获得流关联数组
        Stream<String> arrayStream = Stream.of(strs);
        // 直接创建流对象
        Stream<String> a = Stream.of("a", "b");
    }
}

1.4 Stream常用方法

流操作常用方法

分成两种:

  • 终结方法

  • 非终结方法

1.4.1 过滤:filter

1.4.1.1 方法声明

Stream<T> filter(Predicate<T> predicate)
    * 将流中满足条件的元素添加到另一个流中,返回新的流

1.4.1.2 Predicate接口

java.util.stream.Predicate函数式接口,其中唯一的抽象方法为:

boolean test(T t);

该方法将会产生一个boolean值结果,判断指定的条件是否满足。条件结果为true,则Stream流的filter方法将留用元素;条件结果为false,则filter方法将会舍弃元素。

1.4.1.3 基本使用

Stream流中的filter方法基本使用代码如:

public class StreamDemo02 {
    public static void main(String[] args){
        // 创建流对象
        Stream<String> stream01 = Stream.of("abc", "bbxx", "abcde");
        // Predicate函数式接口的抽象方法:boolean test(T t)
        Stream<String> stream02 = stream01.filter(s -> s.length() >= 4);
        // 获得流的元素个数并输出
        System.out.println(stream02.count());
    }
}

1.4.2 统计个数:count

1.4.2.1 方法声明如下

long count()
    * 获得流中元素的个数

1.4.2.2 基本使用

Stream流中的count方法基本使用代码如:

public class StreamDemo02 {
    public static void main(String[] args){
        // 创建流对象
        Stream<String> stream01 = Stream.of("abc", "bbxx", "abcde");
        // Predicate函数式接口的抽象方法:boolean test(T t)
        Stream<String> stream02 = stream01.filter(s -> s.length() >= 4);
        // 获得流的元素个数并输出
        System.out.println(stream02.count());
    }
}

1.4.3 获取前几个:limit

1.4.3.1 方法声明如下

Stream<T> limit(long maxSize)
    * 将流中前maxSize个元素获取到另一个流中
    * maxSize等于零,则会获取一个空流。
    * maxSize大于当前流中元素个数,则会将当前流的所有元素获取到另一个流中
    * maxSize必须大于等于0

1.4.3.2 基本使用

Stream流中的limit方法基本使用代码如:

public class StreamDemo03 {
    public static void main(String[] args){
        // 创建流对象
        Stream<String> stream01 = Stream.of("abc", "dbc", "dde","abe");
       // 获取前2个元素放到另一个流中
        Stream<String> stream02 = stream01.limit(5);
        System.out.println(stream02.count());
    }
}

1.4.4 跳过前几个:skip

1.4.4.1 方法声明如下

Stream<T> skip(long n)
    * 跳过当前流中的前n个元素,将前n个元素后的所有元素添加到另一流中,返回新流。
    * n必须大于等于0
    * n大于当前流中的元素个数,则会产生一个空流。

1.4.4.2 基本使用

public class StreamDemo04 {
    public static void main(String[] args){
        // 创建流对象
        Stream<String> stream01 = Stream.of("abc", "dbc", "dde","abe");
        // 跳过当前流中的前1个元素,
        Stream<String> stream02 = stream01.skip(5);
        System.out.println(stream02.count());
    }
}

1.4.5 映射:map

使用map操作遍历集合中的每个对象,并对遍历结果进行处理,map之后用.collect(Collectors.toList())会得到操作后的集合。方法声明如下

* Stream<R> map(Function<T,R> mapper)
    * 将当前流中元素的类型从T类型转换为R类型,存储到另一个流中返回

该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。

1.4.5.1 Function接口

java.util.stream.Function函数式接口,其中唯一的抽象方法为:

R apply(T t);

将一种T类型转换成为R类型,而这转换的过程,则称为“映射”。

1.4.5.2 基本使用

Stream流中的map方法基本使用的代码如:

public class StreamDemo05 {
    public static void main(String[] args){
        // 创建流对象
        Stream<String> stream01 = Stream.of("aaa", "456", "789","12345");
      
        // 将流中的字符串都转换为整型存储到另一个流中
        // Function函数式接口的抽象方法:R apply(T t)
        Stream<Integer> stream02 = stream01.map(str -> {
            System.out.println(str);
            return Integer.parseInt(str);
        });
        System.out.println(stream02.count());
    }
}

1.4.6 组合:concat

1.4.6.1 方法声明如下

concat方法的声明如下:
    * static <T> Stream<T>  oncat(Stream<T> a, Stream<T> b)
        * 将流a和流b合并为一个流

1.4.6.2 基本使用

public class StreamDemo06 {
    public static void main(String[] args){
        // 创建流对象
        Stream<String> streamA = Stream.of("aaa", "456", "789","12345");
        Stream<String> streamB = Stream.of("aaa", "456", "789","12345");
​
        // 合并流中元素产生新的流
        Stream<String> streamC = Stream.concat(streamA, streamB);
        // 将流中的元素传递给消费者逐一处理
        streamC.forEach(System.out::println);
    }
}

1.4.7 逐一处理:forEach

1.4.7.1 方法声明如下

 void forEach(Consumer c);
     * 将流中的元素传递给消费者逐一处理

1.4.7.2 基本使用

public class StreamDemo07 {
    public static void main(String[] args){
        // 创建流对象
        Stream<String> streamA = Stream.of("aaa", "456", "789","12345");
        // 将流中的元素传递给消费者逐一处理
        streamA.forEach(System.out::println);
    }
}

方法引用System.out::println便是一个Consumer`函数式接口的实例。

1.5 小结:非终结方法与终结方法

在上述介绍的各种方法中,凡是返回值仍然为Stream接口的为非终结方法(函数拼接方法),它们支持链式调用;而返回值不再为Stream接口的为终结方法,不再支持链式调用。如下表所示:

方法名方法作用方法种类是否支持链式调用
count统计个数终结
forEach逐一处理终结
filter过滤函数拼接
limit取用前几个函数拼接
skip跳过前几个函数拼接
map映射函数拼接
concat组合函数拼接

1.6 案例

  • 案例说明

现在有两个ArrayList集合存储队伍当中的多个成员姓名

两个队伍(集合)的代码如下:

import java.util.ArrayList;
import java.util.List;
​
public class DemoArrayListNames {
​
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");
​
        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");
        // ....
    }
}

Person类的代码如下

public class Person {
​
    private String name;
​
    public Person() {}
​
    public Person(String name) {
        this.name = name;
    }
​
    @Override
    public String toString() {
        return "Person{name='" + name + "'}";
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
}

要求如下:

  1. 使用传统的for循环(或增强for循环)依次进行以下若干操作步骤

  2. 使用Stream方式依次进行以下若干操作步骤

1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前3个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前2个人;
5. 将两个队伍合并为一个队伍;
6. 根据姓名创建Person对象;
7. 打印整个队伍的Person对象信息。

1.6.1 Stream流方式

public class StreamDemo01 {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");
​
        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");
        // ....
​
        // 1. 第一个队伍只要名字为3个字的成员姓名;
        // 2. 第一个队伍筛选之后只要前3个人;
        Stream<String> oneStream = one.stream()
                .filter(s -> s.length() == 3)
                .limit(3);
​
        // 3. 第二个队伍只要姓张的成员姓名;
        // 4. 第二个队伍筛选之后不要前2个人;
        Stream<String> twoStream = two.stream()
                .filter(s -> s.startsWith("张"))
                .skip(2);
​
        // 5. 将两个队伍合并为一个队伍;
        // 6. 根据姓名创建Person对象;
        // 7. 打印整个队伍的Person对象信息。
        Stream.concat(oneStream, twoStream)
                .map(Person::new)
                .forEach(System.out::println);
    }
}
​

1.7 收集Stream结果

对流操作完成之后,则需要将其结果进行收集.

1.7.1 收集到集合中

Stream流提供collect方法,其参数需要一个java.util.stream.Collector<T,A, R>接口对象来指定收集到哪种集合中。java.util.stream.Collectors 类提供一些方法,可以作为Collector`接口的实例:

public static <T> Collector<T, ?, List<T>> toList():转换为List集合。
public static <T> Collector<T, ?, Set<T>> toSet():转换为Set集合。

基本使用

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
​
public class Demo15StreamCollect {
​
   public static void main(String[] args) {
      Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
      List<String> list = stream.collect(Collectors.toList());
      Set<String> set = stream.collect(Collectors.toSet());
   }
}

1.7.2 收集到数组中

Stream提供toArray方法来将结果放到一个数组中,由于泛型擦除的原因,返回值类型是Object[]的:

Object[] toArray();

基本使用

import java.util.stream.Stream;
​
public class Demo16StreamArray {
​
   public static void main(String[] args) {
      Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
      Object[] objArray = stream.toArray();
   }
}

解决泛型数组问题

有了Lambda和方法引用之后,可以使用toArray方法的另一种重载形式传递一个IntFunction<A[]>的函数,继而从外面指定泛型参数。方法声明如下:

<A> A[] toArray(IntFunction<A[]> generator);

上例代码中不再局限于Object[]结果,则可以得到String[]结果:

import java.util.stream.Stream;
​
public class Demo17StreamArray {
​
   public static void main(String[] args) {
      Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
      String[] strArray = stream.toArray(String[]::new);
   }
}

既然数组是有构造器的,则传递一个数组的构造器引用即可。

1.8 并发流

以上例子中使用的是串行流,即单线程执行的,其实Stream API中提供有并行流,即多线程执行操作。

java.util.Collection<E>新添加两个默认方法

  • default Stream stream() : 返回串行流

  • default Stream parallelStream() : 返回并行流

stream()parallelStream()方法返回的均是java.util.stream.Stream<E>类型的对象,则说明它们在功能的使用上是没差别的。唯一的差别就是单线程和多线程的执行。

1.8.1 串行流转换为并发流

Stream的父接口java.util.stream.BaseStream中定义一个parallel方法:

S parallel();

在流上调用一下无参数的parallel方法,则当前流即可改变成为支持并发操作的流,返回值仍然为Stream类型。例如:

import java.util.stream.Stream;
​
public class Demo13StreamParallel {
​
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50).parallel();
    }
​
}

1.8.2 直接获取并发流

在通过集合获取流时,可以直接调用parallelStream方法来直接获取支持并发操作的流。方法定义为:

    default Stream<E> parallelStream() {...}

应用代码为:

import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Stream;
​
public class Demo13StreamParallel {
​
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        Stream<String> stream = coll.parallelStream();
    }
}

1.8.3 并发流基本使用

/**
 * @author pkxing
 * @version 1.0
 * @description 并发流
 * @date 2018/3/5
 */
public class StreamDemo02 {
​
    @Test
    public void testStream() {
        List<Integer> list = new ArrayList<>();
        // 将1000-1存入list中
        for (int i = 1000; i >= 1; i--) {
            list.add(i);
        }
​
        // 使用串行流:不开线程执行,在当前线程执行
//        List<String> result = list.stream()
//                .map((i)-> {
//                    System.out.println("i = " +Thread.currentThread().getName());
//                    return String.valueOf(i);
//                }).collect(Collectors.toList());
​
        // 使用并发流:开多个线程执行
        List<String> result = list.parallelStream()
                .map((i)-> {
                    System.out.println("i = " +Thread.currentThread().getName());
                    return String.valueOf(i);
                }).collect(Collectors.toList());
​
        System.out.println(result);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值