Stream的一些常用操作

    由于最近换了工作,项目中是使用jdk1.8,所以有必要学习一些jdk1.8骚操作,此文章不断更新。

    如何理解Stream?在我看来,Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。简单来说,它的作用就是通过一系列操作将数据源(集合、数组)转化为想要的结果。

Stream有三点非常重要的特性:

  1. Stream 是不会存储元素的。
  2. Stream 不会改变原对象,相反,他们会返回一个持有结果的新Stream。
  3. Stream 操作是延迟执行的。意味着它们会等到需要结果的时候才执行。

Stream生成

//Collection系的 stream() 和 parallelStream()
List<String> list = new ArrayList<> ();
Stream<String> stream = list.stream();
Stream<String> stringStream = list.parallelStream();

 //通过Arrays.stram()
 Stream<String> stream1 = Arrays.stream(new String[10]);

//通过Stream.of()
Stream<Integer> stream2 = Stream.of(1, 2, 3,4,5,6,7,8,9,10);

//通过Stream.iterate()生成无限流
Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
iterate.limit(10).forEach(System.out::println);

//通过Stream.generate()
Stream<Double> generate = Stream.generate(() -> Math.random());

Stream中间操作

stream2.map(s -> s + 1) //映射
                .flatMap(s -> Stream.of(s)) //和map差不多,但返回类型为Stream,类似list.add()和list.addAll()的区别
                .filter(s -> s <=5 ) //过滤
                .limit(5) //限制
                .skip(1) //跳过
                .distinct() //去重
                .sorted() //自然排序
                .sorted(Integer::compareTo).forEach (System.out::println); //自定义排序*/

Stream的终止操作  (不能对同一个流一遍进行运行操作,一遍终止操作)

常用的终止API如下: 

 System.out.println (stream2.allMatch((x) -> x == 10));  // 检查是否匹配所有元素 boolean
 System.out.println(stream2.anyMatch(((x) -> x>5))); // 检查是否至少匹配一个元素
 System.out.println(stream2.noneMatch((x) -> x>500)); //检查是否没有匹配所有元素
 System.out.println (stream2.findFirst()); // 返回第一个元素Optional[1]
 System.out.println (stream2.findAny()); // 返回当前流中的任意一个元素;
 System.out.println (stream2.count()); // 返回流中元素的总个数);
 Optional<Integer> max = stream2.max(Integer::compareTo); // 返回流中最大值
 System.out.println("max "+max.get());
 Optional<Integer> min = stream2.min(Integer::compareTo);//返回流中最小值
 System.out.println("min "+min.get());

  reduce (归约):将流中元素反复结合起来得到一个值 

 Integer reduce = stream2.map(s -> (s + 1)).reduce(0, (integer1, integer2) -> integer1+integer2); 
//归约:0为第一个参数x的默认值,x是计算后的返回值,y为每一项的值。
 System.out.println(reduce);
 Optional<Integer> reduce1 = stream2.map(s -> (s + 1)).reduce((x, y) -> x + y);
// x是计算后的返回值,默认为第一项的值,y为其后每一项的值。 
 System.out.println(reduce1.get ());

collect(收集):将流转换为其他形式。需要Collectors类的一些方法

//collect(收集):将流转换为其他形式。需要Collectors类的一些方法。
Set<Integer> collect = stream2.collect(Collectors.toSet());
List<Integer> collect2 = stream2.collect(Collectors.toList());
HashSet<Integer> collect1 = stream2.collect(Collectors.toCollection(HashSet::new));
//分组 {group=[1, 2, 3, 4...]}
Map<String, List<Integer>> collect3 = stream2.collect(Collectors.groupingBy((x) -> "group"));//将返回值相同的进行分组
//分区 {false=[1, 2, 3, 4], true=[5, 6, 7, 8, 9, 10, 10]}
Map<Boolean, List<Integer>> collect5 = stream2.collect(Collectors.partitioningBy((x) -> x >= 5));
//汇总  最大值、最小值、平均值、个数
DoubleSummaryStatistics collect6 = stream2.collect(Collectors.summarizingDouble((x) -> x));
System.out.println(collect6.getMax());
System.out.println(collect6.getCount());

摘自: https://mp.weixin.qq.com/s/5UUD7N4Uxspnzcine_2AnA

工作常用示例

package JDK8常用特性;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Heian
 * @time 19/04/01 14:15
 * 用途:
 */
public class Demo1 {

    class Student{
        private int id;
        private String name;
        private int age;
        public Student(int id,String name,int age){
            this.id = id;
            this.name = name;
            this.age = age;
        }
        public int getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1 ();
        List<Student> list = new ArrayList<> ();
        list.add (demo1.new Student (1,"张三",18));
        list.add (demo1.new Student (2,"李四",20));
        list.add (demo1.new Student (3,"王二",22));
        list.add (demo1.new Student (4,"小明",19));
        list.add (demo1.new Student (5,"小红",17));
        list.add (null);
        //常用操作一:防空处理
        //Optional.ofNullable (list).orElse (Collections.emptyList ()).forEach (System.out::println);  会存在null
        list.stream ().filter (Objects::nonNull).forEach (student -> System.out.println (student));
        //常用操作二:集合变形  业务代码最为常见(假设我要取得某个集合中某个属性作为单独的一个集合)
        System.out.println ("=======================集合变形分割线===================");
        List<String> nameList = list.stream ().filter (Objects::nonNull).map (Student::getName).collect(Collectors.toList());
        nameList.forEach (System.out::println);//集合转化流--->filter过滤--->map对集合做业务操作(返回的仍然是Stream<R>)--->流转化为集合
        //limit 就像mysql的limit num 关键字  这里是查出前3条
        List<String> nameList2 = list.stream ().filter (Objects::nonNull).map (Student::getName).limit (3).collect(Collectors.toList());
        nameList2.forEach (s -> System.out.println ("limit" + s));
        //加上skip 类似于mysql分页 比如查看第1 到 10 条记录 select * from emp limit 0,9     这里也类似:这就是第2到第4条   也可以用于分页
        List<String> nameList3 = list.stream ().filter (Objects::nonNull).map (Student::getName).skip (1).limit (3).collect(Collectors.toList());
        nameList3.forEach (s -> System.out.println ("skip  limit" + s));
        List<Integer> list2 = Arrays.asList(1,2,3);
        //不改变原有元素
        list2.forEach(i -> i = i*2);
        list2.forEach(integer -> System.out.println ("不改变原有元素"+integer));
        //改变对象
        list2.stream().map(i -> i * 2).forEach(integer -> System.out.println ("改变原有元素"+integer));
        //常用操作三:list转map
        System.out.println ("=======================list转map分割线===================");
        Map<Integer,Student> map = list.stream ().filter (Objects::nonNull).collect (Collectors.toMap (Student::getId,student -> student));
        for (Map.Entry<Integer, Demo1.Student> entrySet: map.entrySet ()){
            System.out.println (entrySet.getKey () +":"+ entrySet.getValue ());
        }
        System.out.println ("=======================排序后分割线===================");
        //常用操作四:集合排序
        //方法1:利用Comparable 接口实现排序 String和Integer都是实现了此接口,需要覆写其
        List<Student> notNullList = list.stream ().filter (Objects::nonNull).collect (Collectors.toList ());
        Collections.sort (notNullList,(o1, o2) -> {
            return Integer.compare (o1.age,o2.age);
        });
        //利用Comparator 接口实现排序
        Collections.sort (notNullList,Comparator.comparing (o -> o.age));
        notNullList.forEach (student -> System.out.println (student));

        //当然觉得性能差 可以用并行方式输出,但结果不一定是顺序执行 1234...9
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        numbers.parallelStream().forEach(System.out::println);
        numbers.parallelStream ().forEachOrdered (System.out::println);//顺序执行
    }

}

猜你喜欢

转载自blog.csdn.net/qq_40826106/article/details/88964794