Stream API——Java8新特性

    科技2022-07-29  130

    StreamAPI

    Java8API中添加了新的抽象称为流Stream,把真正的函数式编程风格引入到Java中,可以让你以一种声明的方式处理数据,Stream使用一种类似SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象,StreamAPI极大简化了集合框架的处理,这种风格将需要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如:筛选、排序、聚合。

    Stream流有一些新特性:

    Stream流不是一种数据类型,不保存数据,他只是在原数据集上定义了一组操作这些操作是惰性的,即每当访问到这个流中的一个元素时,才会在此元素上执行这一系列的操作Stream流不保存数据,所以一个Stream流只能使用一次元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果: 中间操作:返回结果都是Stream,所以中间操作可以叠加最终操作:返回我们最终需要的数据,只能有一个最终操作

    使用Stream流,可以清楚地知道我们要对一个数据集做何操作,可读性强。而且可以很轻松地获取并行化Stream流,不用自己编写多线程代码,可以更加专注于业务逻辑。默认情况下,从有序集合、生成器、迭代器产生的流或者通过调用Stream.sorted产生的流都是有序流,有序流在并行处理时会在处理完成后恢复原顺序。无限流的存在侧面说明了流是惰性的,即每当用到一个元素时,才会在这个元素上执行这一系列操作。

    使用Stream流的基本操作:

    创建Stream转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(可以进行多次转换)对Stream进行聚合操作,获得想要的结果

    流的创建

    通过集合创建

    Java8中Collection接口被扩展,提供了两个获取流的方法:

    default Stream stream();返回一个顺序流default Stream parallelStream();返回一个并行流

    通过数组创建

    Java8中的Arrays的静态方法stream()可以获取数组流

    public staticStream staram(T[] array);返回一个流public static IntStream stream(int[] array);返回一个整型的数据流public static LongStream stream(long[] array);返回一个长整形的数据流public static DoubleStream stream(double[] array);返回一个浮点型数据流

    通过Stream创建

    1、可以调用Stream类静态方法of(),通过显示值创建一个流,它可以接收任务数量的参数。

    public static Stream of(T …values);返回一个顺序流

    2、静态方法concat(),将两个流连接起来

    public static Stream concat(Stream<? extends T> a, Stream<? extends T> b);

    创建无限流

    可以使用Stream中的静态方法Stream.iterate()和Stream.generate(),创建一个无限流

    public static Stream iterate(final T seed,final UnaryOperatorf);返回一个无限流public static Stream generate(Supplier s);返回一个无限流

    中间操作

    返回值方法名说明Streamfilter(Predicate p)筛选,接收Lambda,从流中排除某些元素Streamdistinct()筛选,通过流所生成元素的equals()去除重复元素Streamlimit(long maxSize)截断,使流中元素不超过指定maxSizeStreamskip(long n)切片,跳过元素,返回一个扔掉了n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补Streampeek(Consumer action)消费,接收Lambda,对流中每一个数据执行Lambda体操作Streamsorted()排序,产生一个新流,其中按自然顺序排序Streamsorted(Comparator com)排序,产生一个新流,其中按给定比较器顺序排序Streammap(Function f)映射,接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素StreamflatMap(Function f)映射,接收一个函数作为参数,将流中的每一个值都替换为另一个流,然后把所有流连接成一个流DoubleStreammapToDouble(ToDoubleFunction f)映射,接收一个函数作为参数,该函数会被应用到每一个元素上,产生一个新的DoubleStreamIntStreammapToInt(ToIntFunction f)映射,接收一个函数作为参数,该函数会被应用到每一个元素上,产生一个新的IntStreamLongStreammapToLong(ToLongFunction f)映射,接收一个函数作为参数,该函数会被应用到每一个元素上,产生一个新的LongStream

    中间操作:筛选和切片

    ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1001,"张三",3000)); list.add(new Employee(1002,"李四",5500)); list.add(new Employee(1003,"王五",8000)); list.add(new Employee(1004,"赵六",6000)); list.add(new Employee(1004,"赵六",6000)); list.add(new Employee(1004,"赵六",6000)); list.stream() .filter((x)->x.getSalary()>5000)//过滤掉工资小于5000的元素 .limit(4)//只留下前四个元素 .skip(1)//去掉第一个元素 .distinct()//去掉重复元素,需要自定义类Employee重写equals和hashCode方法 .forEach(System.out::println);

    中间操作:消费

    List<String> list2 = Arrays.asList("a","bb","c","d"); list2.stream() .peek(System.out::println)//消费这个流中的元素,打印每一个元素 //注意,这是中间操作,所以需要在下面增加一个终止操作,上面的中间操作才会执行 .collect(Collectors.toList());

    中间操作:排序

    List<String> list1 = Arrays.asList("dd","b","aaa","cccc"); list1.stream() .sorted()//自然排序,使用String类中的compareTo方法实现排序(Comparable) .forEach(System.out::println); System.out.println("-----------------------------------------"); list1.stream() .sorted((a,b)-> { if (a.length() > b.length()){ return 1; }else { return -1; } })//定制排序,按字符串长度排序 .forEach(System.out::println);

    中间操作:映射

    String[] strs = {"java","lambda","stream","map","flatmap"}; Arrays.stream(strs) .map((str)->str.split(""))//将每一个字符串都转换为一个字符串数组流 .forEach(System.out::println);//打印的字符串数组 Arrays.stream(strs) .map((str)->str.split("")) .flatMap(Arrays::stream)//将得到的每一个字符串数组流扁平化,在构成一个总流 .forEach(System.out::println);//打印总流中的每一个字符

    终结操作

    终结操作是会从流的流水线生成结果,其结果可以是任何不是流的值,如List、Integer、void也可以。流进行了终止操作后,就不能再次使用。

    返回值方法名说明booleanallMatch(Predicate p)接收一个Predicate函数,当流中每个元素都符合该断言时,才会返回true,否则返回falsebooleannoneMatch(Predicate p)接收一个Predicate函数,当流中每一个元素都不符合该断言时才返回true,否则返回falsebooleananyMatch(Predicate p)接收一个Predicate函数,当流中有一个元素满足该断言则返回true,否则返回falseOptionalfindFirst()返回流中的第一个元素OptionalfindAny()返回流中的任意一个元素longcount()返回流中元素的总个数Optionalmax(Comparator c)返回流中元素的最大值Optionalmin(Comparator c)返回流中元素的最小值voidforEach(Consumer c)遍历操作,对此流的每个元素执行操作Treduce(T iden,BinaryOperator b)规约操作,使用提供的身份值和 associative累积函数对此流的元素执行reduction,并返回减小的值。Ureduce(BinaryOperator b)规约操作,使用提供的身份,积累和组合功能,对此流的元素执行reductionRcollect(Collector c)收集操作,收集一个Collector实例,将流中元素收集成另一个数据结构

    终结操作:查找

    ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1001,"张三",3000)); list.add(new Employee(1002,"李四",5500)); list.add(new Employee(1003,"王五",8000)); list.add(new Employee(1004,"赵六",6000)); boolean b1 = list.stream() .allMatch(e -> e.getSalary()>3000); System.out.println("员工工资是否都大于3000:"+b1); boolean b2 = list.stream() .anyMatch(e -> e.getSalary()>7000); System.out.println("员工工资是否有大于7000的:"+b2); boolean b3 = list.stream() .noneMatch(e -> e.getSalary()>10000); System.out.println("员工工资是否都不大于一万:"+b3); //因为得到的值有可能为空,所以返回的对象是一个Optional Optional<Employee> op = list.stream() .sorted(Comparator.comparingDouble(Employee::getSalary)) .findFirst(); System.out.println("工资最低的员工:"+op.get()); //随机返回一个工资大于五千的员工信息 Optional<Employee> op1 = list.parallelStream() .filter(e->e.getSalary()>5000) .findAny(); System.out.println("工资大于5000的任意一个员工:"+op1.get());

    终结操作:匹配

    long count = list.stream() .count(); System.out.println("员工总数为:"+count); //返回流中的最大值 Optional<Employee> op3 = list.stream() .max(Comparator.comparingDouble(Employee::getSalary)); System.out.println("工资最高的员工:"+op3.get()); //返回流中的最小值 Optional<Double> op4 = list.stream() .map(Employee::getSalary) .min(Double::compare); System.out.println("最低工资为:"+op4.get());
    Processed: 0.009, SQL: 8