JAVA8新特性_04 Stream流的案例

 直接上代码(所有案例):

public class StreamMethod extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

    }

    /**
     *  以下是Stream流的常用方法!
     **/



    /**
     * limit()方法,获取Stream流中指定的数量的数据
     * */
    @Test
    void limitTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        integerStream.limit(4).forEach(System.out::println);
    }

    /**
     * skip()方法 ,跳过Stream流中指定的数量的数据
     * */
    @Test
    void skipTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        integerStream.skip(4).forEach(System.out::println);
    }

    /**
     * filter()方法 ,根据条件过滤数据
     * */
    @Test
    void filterTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        integerStream.filter(s -> s>5).forEach(System.out::println); //过滤Stream中大于5的数据
    }

    /**
     * foreach()方法,遍历Stream流
     * */
    @Test
    void foreachTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        integerStream.forEach(System.out::println);
    }

    /**
     * count()方法,计算Stream流数据的总数
     * */
    @Test
    void countTest(){
         Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        long count = integerStream.count();
        System.out.println(count);
    }

    /**
     * distinct()方法,去除重复
     * */
    @Test
    void distinctTest(){
        Stream<Integer> integerStream = Stream.of(1, 2,2, 3, 4, 55, 656, 12323,55,55,656);
        integerStream.distinct().forEach(System.out::println);
    }

    /**
     * distinct()方法,去除自定义的实体类对象的重复
     * 需要重写实体类的hashcode和equlse方法
     * */
    @Test
    void distinctClassTest(){
       Stream<Person> integerStream = Stream.of(
                new Person("张三","18"),
                new Person("李四","18"),
                new Person("王五","18"),
                new Person("张三","18")
        );
        integerStream.distinct().forEach(System.out::println);
    }


    /**
     * sorted()方法,排序
     * */
    @Test
    void sortedTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        /*
        * sorted() 无参是正序排序
        **/
        //integerStream.sorted().forEach(System.out::println);

        /*
         * sorted() 有参,可以根据条件排序  此案例是倒序
         **/
        integerStream.sorted((a1,a2) -> a2-a1).forEach(System.out::println);
    }


    /**
     * map()方法,可以把数据换类型并返回
     * */
    @Test
    void mapTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        integerStream.map(s -> s.toString())
                .forEach(System.out::println);
    }


    /**
     * match()方法 根据要求判断Stream流中数据是否符合要求
     * */
    @Test
    void matchTest(){
         Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);

        //allMatch 如果Stream流的数据都大于55,才返回true,否则返回false
        /*boolean b = integerStream.allMatch(s -> s > 55);
        System.out.println(b);*/

        //anyMatch 如果Stream流的数据其中有一个满足条件,就返回true
        /*boolean b1 = integerStream.anyMatch(s -> s > 55);
        System.out.println(b1);*/


        //noneMatch 如果Stream流的数据都不满足指定条件,才返回true
        boolean b2 = integerStream.noneMatch(s -> s ==999);
        System.out.println(b2);

    }


    /**
     * find()方法,找到流的首个元素
     * */
    @Test
    void findTest(){
       Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        //Optional<Integer> first = integerStream.findFirst(); //找到Stream流中第一个元素
        // System.out.println(first.get());

        // 特地查了一下这两个方法有什么区别,findany不一定会返回首个元素
        // 可以去看这个链接的解释 https://blog.csdn.net/huanghanqian/article/details/102807972
        Optional<Integer> first1 = integerStream.findAny(); //找到Stream流中第一个元素,但并行流的情况下不一定返回首个
         System.out.println(first1.get());
    }


    /**
     * max()方法,排序并返回最大的值
     * */
    @Test
    void maxTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        Optional<Integer> max = integerStream.max((a1, a2) -> a1 - a2);
        System.out.println(max.get());
    }

    /**
     * min()方法,排序并返回最小的值
     **/
    @Test
    void minTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        Optional<Integer> min = integerStream.min((a1, a2) -> a1 - a2);
        System.out.println(min.get());
    }

    /**
     * reduce()方法  将流中数据总结起来并返回
     * T reduce(T identity, BinaryOperator<T> accumulator);
     *         T identity:默认值  初始值
     *         BinaryOperator<T> accumulator  : 对数据的处理方式
     **/
    @Test
    void reduceTest(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
        Integer reduce = integerStream.reduce(0, (m1, m2) -> {
            System.out.println("m1: "+m1+",m2: "+m2);
            return m1 + m2;
        });
        System.out.println("reduce:"+reduce);


        System.out.println("--------------s-----------------------------");
        // 也可以用作取出最大值
        Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4);
        Integer reduce1 = integerStream1.reduce(0, (m1, m2) -> m1 > m2 ? m1 : m2);
        System.out.println(reduce1);
    }


    /**
     * map结合reduce用法
     **/
    @Test
    void reduceAndmapTest(){
        // 求出所有person对象的年龄总和
        int reduce = Stream.of(
                new Person("张三", "18"),
                new Person("李四", "18"),
                new Person("王五", "18"),
                new Person("张三", "18")
        ).map(s -> Integer.parseInt(s.getAge()))
                .reduce(0, Integer::sum);  //Integer类有个sum求和方法
        System.out.println("年龄之和:"+reduce);

        // 求出所有person对象的年龄最大的是多少岁
        int reduce1 = Stream.of(
                new Person("张三", "15"),
                new Person("李四", "10"),
                new Person("王五", "18"),
                new Person("张三", "16")
        ).map(s -> Integer.parseInt(s.getAge()))
                .reduce(0,Math::max);
        System.out.println("最大年龄是:"+reduce1);


        // 取出所有person类的名字并用逗号间隔
        String reduce2 = Stream.of(
                new Person("张三", "15"),
                new Person("李四", "10"),
                new Person("王五", "18"),
                new Person("马云", "16")
        ).map(s -> s.getName())
                .reduce("", (x, y) -> x = x + y + ",");
        System.out.println("姓名为:"+reduce2);


        // 查询1的个数
        Integer reduce3 = Stream.of(1, 2, 3, 2, 5, 1, 1, 1, 1, 1).map(s -> s == 1 ? s : 0)
                .reduce(0, Integer::sum);
        System.out.println("1的个数是:"+reduce3);
    }

    /**
     * maptoInt()方法
     *  在Stream流中,正常操作的整数类都是包装类
     * Integer类型比int占用内存大,在Stream流中会自动装箱和拆箱
     *
     **/
    @Test
    void maptoIntTest(){
        //输出大于55的数字
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        integerStream.filter(s -> s>55).forEach(System.out::println);

        // 返回的是IntStream
        // 这样的好处就是运行速度快,节省了装箱拆箱的步骤,节省了内存空间
        Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        IntStream intStream = integerStream1.mapToInt(s -> s.intValue());
        intStream.filter(s -> s>55).forEach(System.out::println);

    }

    /**
     * concatTest()方法,这个方法是Stream流的静态方法,上面的案例全都是Stream流的对象方法
     *  将两个流合并成一个流
     **/
    @Test
    void concatTest(){
        Stream integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);
        Stream integerStream2 = Stream.of("1", "2", "3", "4", "55", "656","12323");

        Stream concat = Stream.concat(integerStream1, integerStream2);
        concat.forEach(s ->{
            System.out.println(s.getClass()+":"+s);
         });
    }


    /**
     * 收集Stream流的数据到list或set
     **/
    @Test
    void stream_To_List_Set(){
        Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);

        //将Stream收集到List集合中
//        List<Integer> collect = integerStream1.collect(Collectors.toList());
//        System.out.println(collect);

        //将Stream收集到Set集合中
//        Set<Integer> collect = integerStream1.collect(Collectors.toSet());
//        System.out.println(collect);

        //将Stream收集到指定的ArrayList集合中
//        ArrayList<Integer> collect = integerStream1.collect(Collectors.toCollection(ArrayList::new));
//        System.out.println(collect);

        //将Stream收集到指定的HashSet集合中
        HashSet<Integer> collect = integerStream1.collect(Collectors.toCollection(HashSet::new));
        System.out.println(collect);
    }

    /**
     * 收集Stream流的数据到数组中
     **/
    @Test
    void stream_To_Array(){
        Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);

       /* Object[] objects = integerStream1.toArray();

        for (Object object : objects) {
            System.out.println(object);
        }*/

        Integer[] Integers = integerStream1.toArray(Integer[]::new);
        for (Integer integer : Integers) {
            System.out.println(integer);
        }

    }

    /**
     * 对流中数据进行聚合运算
     **/
    @Test
    void streamTest(){
        Stream<Person> personStream = Stream.of(
                new Person("张三", "15"),
                new Person("李四", "10"),
                new Person("王五", "18"),
                new Person("张三", "16"));

        // 求出年龄最大的人
//        Optional<Person> collect = personStream.collect(Collectors.maxBy((o1, o2) -> Integer.parseInt(o1.getAge()) - Integer.parseInt(o2.getAge())));
//        System.out.println(collect.get());

        // 求出年龄最小的人
        /*Optional<Person> collect = personStream.collect(Collectors.maxBy((o1, o2) -> Integer.parseInt(o2.getAge()) - Integer.parseInt(o1.getAge())));
        System.out.println(collect.get());*/

        // 求出年龄平均值
//        Double collect = personStream.collect(Collectors.averagingInt(value -> Integer.parseInt(value.getAge())));
//        System.out.println(collect);

        // 求出共有几个人
//        Long collect1 = personStream.collect(Collectors.counting());
//        System.out.println(collect1);

        // 求出年龄总和
//        Integer collect = personStream.collect(Collectors.summingInt(value -> Integer.parseInt(value.getAge())));
//        System.out.println(collect);

    }

    /**
     * 对流中数据进行分组
     **/
    @Test
    void streamGroupTest(){
        Stream<Person> personStream = Stream.of(
                new Person("张三", "15"),
                new Person("李四", "15"),
                new Person("王五", "18"),
                new Person("张三", "20"));
        //对年龄进行分组
        //Map<String, List<Person>> collect = personStream.collect(Collectors.groupingBy(s -> s.getAge()));

        //对年龄进行分组,但是加个条件   成年和未成年
        Map<String, List<Person>> collect = personStream.collect(Collectors.groupingBy(s ->
                Integer.parseInt(s.getAge())<18 ? "未成年" : "成年"
        ));

        //遍历
        collect.forEach((k,v)->{
            System.out.println(k+"="+v);
        });
    }

    /**
     * 对流中数据进行多级分组
     **/
    @Test
    void streamGroupsTest(){
        Stream<Person> personStream = Stream.of(
                new Person("张三", "15","60"),
                new Person("李四", "15","59"),
                new Person("王五", "18","99"),
                new Person("张三", "18","40"));
        Map<String, Map<String, List<Person>>> collect = personStream.collect(Collectors.groupingBy(Person::getAge, Collectors.groupingBy(s ->
                Integer.parseInt(s.getCore()) < 60 ? "不及格" : "及格"
        )));
        //遍历
        collect.forEach((k,v)->{
            System.out.println(k+"="+v);
        });
    }

    /**
     * 对流中数据进行分区
     * 对数据进行判断,true为一组,false为一组 分成两个区
     **/
    @Test
    void streamPartitioningByTest(){
        Stream<Person> personStream = Stream.of(
                new Person("张三", "15","60"),
                new Person("李四", "15","59"),
                new Person("王五", "18","99"),
                new Person("张三", "18","40"));
        Map<Boolean, List<Person>> collect = personStream.collect(Collectors.partitioningBy(person ->
                Integer.parseInt(person.getCore()) > 60
        ));
        //遍历
        collect.forEach((k,v)->{
            System.out.println(k+"="+v);
        });
    }


    /**
     * 对流中数据进行拼接
     **/
    @Test
    void streamJoiningTest(){
        Stream<Person> personStream = Stream.of(
                new Person("张三", "15","60"),
                new Person("李四", "15","59"),
                new Person("王五", "18","99"),
                new Person("张三", "18","40"));
        // Collectors.joining("__","**","++") 三个参数的,第一个参数是中间拼接的字符串,第二个参数是前缀,第三个参数是后缀。得到结果:**张三__李四__王五__张三++
//        String collect = personStream.map(Person::getName).collect(Collectors.joining("__","**","++"));

        // Collectors.joining("__") 1个参数的,参数是中间拼接的字符串 。得到结果:张三__李四__王五__张三
//        String collect = personStream.map(Person::getName).collect(Collectors.joining("__"));

        // Collectors.joining() 0个参数的 。得到结果:张三李四王五张三
        String collect = personStream.map(Person::getName).collect(Collectors.joining());
        System.out.println(collect);
    }

    /**小结
     * 收集Stream流中的结果
     * 到集合中:Collectors.toList(),Collectors.toSet(),Collectors.toCollection()
     * 到数组中:默认Object数组Collectors.toArray(), 指定类型的数组Collectors.toArray(int[]::new)
     * 聚合计算:最大值Collectors.maxBy(),最小值Collectors.minBy(),统计数量Collectors.counting(),求和Collectors.summingint(),平均值Collectors.averagingInt()
     * 分组:Collectors.groupingBy(),多级分组Collectors.groupingBy(Person::getAge,Collectors.groupingBy(Person::getCore))
     * 分区:Collectors.partitionBy()
     * 拼接:Collectors.joining()
     * */


    /**以上的流都是串行流,串行流是一个线程执行内容
     *
     *
     * 并行Stream流
     *
     * 并行流是多个线程同时执行内容
     *
     * */
    @Test
    void BingXingStreamTest(){
        List<String> list=Arrays.asList("张三","李四","王五","马六","田七");

        //并行Stream流的两种获取方式:

        // 第一种:直接获取并行流
        //list.parallelStream().filter(s -> {
        //    System.out.println(Thread.currentThread());
        //    return true;
        //}).count();;

        // 第二种:将串行流转成并行流  parallel()方法
        list.stream().parallel().filter(s -> {
            System.out.println(Thread.currentThread());
            return true;
        }).count();
    }




    /**
     * 串行流,并行流,for循环效率对比
     * */
    @Test
    void StreamTimeTest(){
       //*********************for 费时:123******************************
        /*long starttimie = System.currentTimeMillis();
        long time=500000000l;
        long sum=0;
        for (long i=1;i<=time;i++){
            sum+=i;
        }
        long endtimie = System.currentTimeMillis();
        System.out.println("费时:"+(endtimie-starttimie));*/
        //*********************for 时间:123******************************

        //*********************串行流 费时:209******************************
       /* long starttimie = System.currentTimeMillis();
        long time=500000000l;
        LongStream.rangeClosed(0, time).reduce(Long::sum);
        long endtimie = System.currentTimeMillis();
        System.out.println("费时:"+(endtimie-starttimie));*/
        //*********************串行流 费时:209******************************

        //*********************并行流 费时:97******************************
        long starttimie = System.currentTimeMillis();
        long time=500000000l;
        LongStream.rangeClosed(0, time).parallel().reduce(Long::sum);
        long endtimie = System.currentTimeMillis();
        System.out.println("费时:"+(endtimie-starttimie));
        //*********************并行流 费时:97******************************
    }


    /**
     * 并行流的线程安全问题
     * */
    @Test
    void anQuanTest(){
        // 不安全案例:得出结果list的size不是500, 按理说list的size应该是500,但并行流是多个线程同时运行 会造成数据安全问题
        /*List<Integer> list=new ArrayList<>();
        IntStream.rangeClosed(1,500).parallel().forEach(s->{
            list.add(s);
        });
        System.out.println(list.size());*/

        // 解决方案一,使用线程安全的集合
        /*Vector<Integer> vector=new Vector<>();
        IntStream.rangeClosed(1,500).parallel().forEach(s->{
            vector.add(s);
        });
        System.out.println(vector.size());*/

        // 解决方案二,加入同步代码块
       /* List<Integer> list=new ArrayList<>();
        Object ob=new Object();
        IntStream.rangeClosed(1,500).parallel().forEach(s->{
            synchronized (ob){
                list.add(s);
            }
         });
        System.out.println(list.size());*/


        // 解决方案三,使用线程安全的list   Collections.synchronizedList(list)会将一个list转成线程安全的List  也就是SynchronizedList 是List的子类
        List<Integer> list=new ArrayList<>();
        List<Integer> objects = Collections.synchronizedList(list);
         IntStream.rangeClosed(1,500).parallel().forEach(s->{
             objects.add(s);
         });
        System.out.println(objects.size());

        // 解决方案四,调用collect的toArray   boxed()方法返回一个该流元素组成的一个新流,只不过流中元素都转成了对应的包装类
        /*List<Integer> collect = IntStream.rangeClosed(1, 500).parallel().boxed().collect(Collectors.toList());
        System.out.println(collect.size());*/
    }


    /**小结
     *  并行流的内部采用的是ForkJoin框架
     *
     *  ForkJoin框架的核心和  分治法  任务窃取算法
     *  分治法,将大任务拆分成小任务由多个线程去执行,最后每个小任务的结果合并起来,融合成大结果,也就是最后结果并返回
     *
     *  任务窃取算法,是指执行任务的多个线程中只要一个线程先执行完,就去偷其他线程的任务队列中最后一个线程,然后偷过来继续执行
     * */
}

案例所需要的实体类:

 

import java.util.Objects;

public class Person {

    String name;
    String age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public Person(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(name, person.name) && Objects.equals(age, person.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}









下一篇:JAVA8新特性_05 Optional类的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值