Java8新特性3:Stream流

回顾之前《JavaSE-23.2》:
https://www.cnblogs.com/yppah/p/14900824.html
https://www.cnblogs.com/yppah/p/14900829.html
https://www.cnblogs.com/yppah/p/14900834.html
https://www.cnblogs.com/yppah/p/14900837.html
https://www.cnblogs.com/yppah/p/14900847.html


1 什么是stream流

Stream 是JDK1.8 中处理集合的关键抽象概念,Lambda 和 Stream 是JDK1.8新增的函数式编程最有亮点的特性了,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL执行的数据库查询。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

image-20221025164432309

2 创建stream流

// 创建stream流的两种方式
userList.stream(); //并行流,采用多线程执行,数据量比较少的时候
userList.parallelStream(); //串行流,采用单线程执行,数据量比较大的时候

// parallelStream效率比Stream高
//原理:Fork join 将一个大的任务拆分n多个小的子任务并行执行,最后在统计结果,有可能会非常消耗cpu的资源,确实可以提高效率。
//注意:数据量比较少的情况下,不要使用并行流。

3 Stream将list转换为Set

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/25 16:47
 */
public class Test01 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("amy", 22)); //对象的属性值重复;但两个对象不相等
        User user = new User("sam", 23);
        userList.add(user);
        userList.add(user); //对象(存储地址)重复;可去重

        /*// 创建stream流的两种方式
        userList.stream(); //并行流,采用多线程执行
        userList.parallelStream(); //串行流,采用单线程执行
        // parallelStream效率比Stream要高*/

        //利用stream将list转为set
        Stream<User> userStream = userList.stream();
        Set<User> userSet = userStream.collect(Collectors.toSet());
        userSet.forEach(t -> System.out.println(t));
    }
}

image-20221026084650164

4 set集合去重底层原理剖析[经典面试题]

set集合的底层去重原理 - 小杜打醋尢买布 - 博客园 (cnblogs.com)

list集合去重_谈谈Java中Set集合去重的原理 - 记性这么差 - 博客园 (cnblogs.com)

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/26 8:45
 */
public class Test01_2 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("jack", 19));
        userList.add(new User("jack", 19));

        System.out.println("list未去重:");
        userList.forEach(user -> System.out.println(user));

        System.out.println("set以下为去除重复后:");
        Stream<User> userStream = userList.stream();
        Set<User> userSet = userStream.collect(Collectors.toSet());
        userSet.forEach(t -> System.out.println(t));
    }
}

image-20221027135828279


package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.HashMap;
import java.util.HashSet;

/**
 * @Author: haifei
 * @Date: 2022/10/27 13:57
 */
public class Test01_3 {

    public static void main(String[] args) {
        /*
        Object类中equals()默认是比较两者内存地址是否相等
        此处自定义的User类并未重写equals(),则直接比较两对象的地址
        String类重写了equals()
         */
        User user1 = new User("jack", 19);
        User user2 = new User("jack", 19);
        System.out.println("user1.equals(user2): " + user1.equals(user2)); //false
        System.out.println("user1==user2: " + (user1==user2)); //false

        String str1 = "jack";
        String str2 = "jack";
        System.out.println("str1.equals(str2): " + str1.equals(str2)); //true
        System.out.println("str1==str2: " + (str1==str2)); //true

        /*
        set集合底层依赖于map集合实现防重复key
        map集合底层基于equals比较防重复key,结合hashcode
         */
        HashSet<String> strHashSet = new HashSet<>();
        strHashSet.add(str1);
        strHashSet.add(str2);
        HashMap<Object, Object> objectHashMap = new HashMap<>();
        objectHashMap.put(user1, "a");
        objectHashMap.put(user2, "b");
        //此时map会装两个不同的key,因为两个对象地址不同,即为两对象不相等
        objectHashMap.forEach((k,v)-> System.out.println("k:" + k + ", v:" + v));

        //此处,若User类中重写了equals()和hashcode(),则两对象相等,map中只存储一个key
        //因此,上一.java中则会实现去重
    }
}

image-20221027142018077


image-20221027141624287

image-20221027141602372

image-20221027141705112

image-20221027141746763

image-20221027141814219

image-20221027141851189

image-20221027141918529

5 Stream将list转换为Map

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/26 16:50
 */
public class Test02 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));

        Stream<User> userStream = userList.stream();
        /*Map<String, User> userMap = userStream.collect(Collectors.toMap(
                new Function<User, String>() {
                    @Override
                    public String apply(User user) {
                        return user.getUserName(); //键
                    }
                },
                new Function<User, User>() {
                    @Override
                    public User apply(User user) {
                        return user; //值
                    }
                })
        );
        userMap.forEach(new BiConsumer<String, User>() {
            @Override
            public void accept(String s, User user) {
                System.out.println(s + "," + user);
            }
        });*/

        /*Map<String, User> userMap = userStream.collect(Collectors.toMap(
                user -> {
                    return user.getUserName(); //键
                },
                user -> {
                    return user; //值
                })
        );*/
        Map<String, User> userMap = userStream.collect(Collectors.toMap(user -> user.getUserName(), user -> user));
        userMap.forEach((s, user) -> System.out.println(s + "," + user));
    }
}

image-20221026170830077

6 通过reduce求和

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Stream;

/**
* @Author: haifei
* @Date: 2022/10/26 17:35
*/
public class Test03 {

   public static void main(String[] args) {
       Stream<Integer> stream = Stream.of(10, 50, 30, 10);
//        Optional<Integer> reduce = stream.reduce(new BinaryOperator<Integer>() {
//            @Override
//            public Integer apply(Integer i1, Integer i2) {
//                return i1 + i2;
//            }
//        });
       Optional<Integer> reduce = stream.reduce((i1, i2) -> i1 + i2);
       System.out.println(reduce.get()); //100


       List<User> userList = new ArrayList<>();
       userList.add(new User("lili", 16));
       userList.add(new User("tom", 26));
       userList.add(new User("amy", 22));
       userList.add(new User("sam", 23));
       Stream<User> userStream = userList.stream();
       /*Optional<User> sumAge = userStream.reduce(new BinaryOperator<User>() {
           @Override
           public User apply(User u1, User u2) {
               User user = new User("sumAge", u1.getAge() + u2.getAge());
               return user;
           }
       });*/
       Optional<User> sumAge = userStream.reduce((u1, u2) -> {
           User user = new User("sumAge", u1.getAge() + u2.getAge());
           return user;
       });
       System.out.println(sumAge.get().getAge()); // 87
   }
}

image-20221026191234466

7 Max和Min

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/26 19:13
 */
public class Test04 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("sam", 23));

        Stream<User> userStream = userList.stream();
        /*Optional<User> max = userStream.max(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge() - o2.getAge();
            }
        });*/
        Optional<User> max = userStream.max((o1, o2) -> o1.getAge() - o2.getAge());

        //java.lang.IllegalStateException: stream has already been operated upon or closed
        //记得要重新创建流再求min,要是接着上面的userStream用会报错
        Stream<User> userStream2 = userList.stream();
        /*Optional<User> min = userStream2.min(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge() - o2.getAge();
            }
        });*/
        Optional<User> min = userStream2.min((o1, o2) -> o1.getAge() - o2.getAge());
        System.out.println("max age:" + max.get().getAge());
        System.out.println("min age:" + min.get().getAge());
    }
}

image-20221026192324507

8 Match匹配

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/26 19:24
 */
public class Test05 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("sam", 23));

        Stream<User> stream = userList.stream();
        /*boolean isAnyMatch = stream.anyMatch(new Predicate<User>() {
            @Override
            public boolean test(User user) {
                return "tom".equals(user.getUserName());
            }
        });*/
        boolean isAnyMatch = stream.anyMatch(user -> "tom".equals(user.getUserName()));
        System.out.println(isAnyMatch); //只要匹配一条记录就是true,一条也没有则false

        Stream<User> stream2 = userList.stream();
        /*boolean isAllMatch = stream2.allMatch(new Predicate<User>() {
            @Override
            public boolean test(User user) {
                return "tom".equals(user.getUserName());
            }
        });*/
        boolean isAllMatch = stream2.allMatch(user -> "tom".equals(user.getUserName()));
        System.out.println(isAllMatch); //只有每条记录都匹配才是true,否则为false
    }
}

image-20221026193213136

9 Fliter过滤器

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/26 19:34
 */
public class Test06 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("lili", 20));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("sam", 23));

        //where userName="lili" and age > 18
        Stream<User> stream = userList.stream();
        /*stream.filter(new Predicate<User>() {
            @Override
            public boolean test(User user) {
                return "lili".equals(user.getUserName()) && user.getAge() > 18;
            }
        }).forEach(user -> System.out.println(user));*/
        stream.filter(user -> "lili".equals(user.getUserName()) && user.getAge() > 18)
                .forEach(user -> System.out.println(user));
    }
}

image-20221026194343765

10 Limit和Skip

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/26 19:51
 */
public class Test07 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("sam", 23));
        userList.add(new User("jack", 30));

        Stream<User> stream = userList.stream();
        stream.limit(2).forEach(user -> System.out.println(user)); //limit(0,2),[从第0条往后]取前两条
        System.out.println("===========================");
        Stream<User> stream2 = userList.stream();
        stream2.skip(2).limit(3).forEach(user -> System.out.println(user)); //limit(2,3),从第2条后取3条
    }
}

image-20221027093011285

11 Sorted排序

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/27 9:31
 */
public class Test08 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("sam", 23));
        userList.add(new User("jack", 30));

        Stream<User> stream = userList.stream();
        /*stream.sorted(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o2.getAge()-o1.getAge(); //前o1-后o2升序;后o2-前o1降序
            }
        }).forEach(user -> System.out.println(user.toString()));*/
        stream.sorted(
                (o1, o2) -> (o2.getAge()-o1.getAge())
        ).forEach(
                user -> System.out.println(user.toString())
        );
    }
}

image-20221027093933249

12 Stream综合案例

package com.yppah.myStream;

import com.yppah.myLambda.p6.User;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * @Author: haifei
 * @Date: 2022/10/27 9:40
 */
public class Test09 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("lili", 16));
        userList.add(new User("tom", 26));
        userList.add(new User("amy", 22));
        userList.add(new User("sam", 23));
        userList.add(new User("sam", 16));
        userList.add(new User("sam", 35));
        userList.add(new User("sam22", 23));
        userList.add(new User("sam33", 30));
        userList.add(new User("jack", 30));

        // 需求:对数据流的数据实现降序排列、且名称为sam、获取前两位进行打印
        Stream<User> stream = userList.stream();
        /*stream.sorted(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o2.getAge()-o1.getAge();
            }
        }).filter(new Predicate<User>() {
            @Override
            public boolean test(User user) {
                return "sam".equals(user.getUserName());
            }
        }).limit(2).forEach(user -> System.out.println(user));*/
        stream.sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .filter(user -> "sam".equals(user.getUserName()))
                .limit(2)
                .forEach(user -> System.out.println(user)); //forEach是终止操作,其之后当前stream流不再可用
    }
}

image-20221027095125998

13 并行流底层实现原理

package com.yppah.myStream;

import java.time.Duration;
import java.time.Instant;
import java.util.OptionalLong;
import java.util.function.LongBinaryOperator;
import java.util.stream.LongStream;

/**
 * @Author: haifei
 * @Date: 2022/10/27 10:46
 */
public class Test10 {

    public static void main(String[] args) {

        // 单线程:13330ms  13290ms   13s左右
        Instant start = Instant.now();
        long sum = 0;
        for (long i=0; i<=50000000000L; i++) {
            sum += i;
        }
        System.out.println(sum);
        Instant end = Instant.now();
        System.out.println("五百亿求和花费时间:" + Duration.between(start, end).toMillis());


        // 并行流: 11035ms   11636ms   11s左右
        Instant start2 = Instant.now();
        LongStream longStream = LongStream.rangeClosed(0, 50000000000L);
        /*OptionalLong reduce = longStream.parallel().reduce(new LongBinaryOperator() {
            @Override
            public long applyAsLong(long left, long right) {
                return left + right;
            }
        });*/
        OptionalLong reduce = longStream.parallel().reduce((left, right) -> left + right);
        System.out.println(reduce.getAsLong());
        Instant end2 = Instant.now();
        System.out.println("五百亿求和花费时间:" + Duration.between(start2, end2).toMillis());
        /*
        原理:
            底层是多线程
            处理大的任务拆分成n多小任务,最后将计算结果合并
         */
    }
}


单线程

image-20221027115232147

多线程

image-20221027115255007

posted @ 2022-10-27 14:26  yub4by  阅读(40)  评论(0编辑  收藏  举报