当前位置:   article > 正文

JDK1.8新特性之StreamAPI_jdk1.8 stream常用api

jdk1.8 stream常用api

一,Stream

1. 集合处理数据的弊端

public class StreamTest01 {
    public static void main(String[] args) {
        //定义一个集合
        List<String> list = Arrays.asList("张三", "李四", "王五", "张飞吖", "柳先生");
        //1.获取所有性张的人
        List<String> arr1 = new ArrayList<>();
        for (String i : list) {
            if (i.startsWith("张")) {
                arr1.add(i);
            }
        }
        System.out.println(arr1);
        //2.获取性张的,名字长度为3的人
        List<String> arr2 = new ArrayList<>();
        for (String i : arr1) {
            if (i.length() == 3) {
                arr2.add(i);
            }
        }
        System.out.println(arr2);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

结果:

[张三, 张飞吖]
[张飞吖]
  • 1
  • 2

可以看出上面代码针对我们不同的需求,总是去循环遍历集合,这时我们希望有更加高效的处理方式。于是,JDK1.8中提供了Stream API来解决这种弊端。

public class StreamTest02 {
    public static void main(String[] args) {
        //定义一个集合
        List<String> list = Arrays.asList("张三", "李四", "王五", "张飞吖", "柳先生");
        list.stream()
                //1.获取所有性张的人
                .filter(s -> s.startsWith("张"))
                //2.获取性张的,名字长度为3的人
                .filter(s -> s.length() == 3)
                //3.输出
                .forEach(System.out::println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

可以看出上面StreamAPI代码的含义:获取流,根据条件过滤,最后逐一打印。相比之前,它更加的简洁直观。

2. Stream流式思想概述

Stream流式思想是一种将数据处理视为流式操作的编程方式。在Stream中,数据被看作是一个连续的流,通过一系列的中间操作,可以对数据进行转换、过滤、排序等操作,最终得到想要的结果。

Stream流式思想的主要特点是:

  • 延迟执行:Stream中的操作不会立即执行,只有当最终的结果需要被获取时才会执行。这样可以解决一次性处理大量数据带来的内存开销问题。

  • 可组合:Stream中的中间操作可以进行链式调用,形成一个操作流水线,每个操作都是上一个操作的输入,可以方便地组合操作。

  • 可并行:Stream中的操作可以利用多核处理器的特点进行并行处理,提高处理速度。

Stream流式思想广泛应用于Java 8及以上版本,可以在集合、数组等数据结构上进行操作。它使得数据处理更加简洁、高效,并且可以利用现代计算机的并行处理能力,提高程序性能。

注意:

  • Strean流和IO流没有任何关系。
  • Stream流不是一种数据结构,它不保存数据,只是对数据进行加工处理。

Stream API能让我们快速的完成许多复杂的操作,如筛选、切片、映射、查找、去重、统计、匹配和归纳。

3. Stream流的获取方法

3.1 根据Collection获取

首先,要知道jdk1.8后java.util.Collection中加入了默认方法Stream。
在这里插入图片描述
也就是说,Collection接口下的所有实现类都可以通过stream方法来获取Stream流。

public class StreamTest03 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.stream();
        HashSet<String> hashSet = new HashSet<>();
        hashSet.stream();
        Vector<String> vector = new Vector<>();
        vector.stream();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

但是,Map接口并没有实现Collection接口。

public class StreamTest03 {
    public static void main(String[] args) {
        HashMap<String, Object> map = new HashMap<>();
        map.keySet().stream();//key
        map.values().stream();//value
        map.entrySet().stream();//entry
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

根据Map获取对应的key value集合,从而获取stream流。

3.2 根据Stream的of方法

因为在实际开发中,我们无法避免对数组中数据的操作,由于数组对象不可能添加默认方法。所以,Stream接口中提供了静态方法of。

public class StreamTest03 {
    public static void main(String[] args) {
        //根据Stream的of方法
        String[] arr1 = {"a", "b", "c"};
        Stream<String> s1 = Stream.of(arr1);
        s1.forEach(System.out::println);
        
        int[] arr2 = {1, 2, 3};
        Stream<int[]> s2 = Stream.of(arr2);
        s2.forEach(System.out::println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

结果:

a
b
c
[I@214c265e
  • 1
  • 2
  • 3
  • 4

注意: 基本数据类型的数组是不行的。

4. 常用方法

Stream API提供的方法是非常丰富的。这些方法大致分为两类:

方法名方法作用
count统计个数
forEach逐一处理
filter过滤
limit取用前几个
skip跳过前几个
map映射
concat组合
reduce统计
max,min最值
sorted排序
distinct去重

终结方法: 返回值类型,不再是Stream类型的方法同时也不再支持链接式调用。
非终结方法: 返回值类型,仍然是Stream类型的方法同时仍然支持持链接式调用。

注意事项:

  • Stream对象只能操作一次。
  • Stream方法返回的是新的流。
  • Stream不调用终结方法,中间的方法是不会执行的。

4.1 forEach

用来遍历流中的数据。

void forEach(Consumer<? super T> action);

该方法接受一个Consumer接口,并将每一个流元素交给函数处理。

ublic class Method_forEach {
    public static void main(String[] args) {
        String[] arr1 = {"a", "b", "c"};
        Stream<String> s1 = Stream.of(arr1);
        s1.forEach(System.out::println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4.2 count

用来统计流中元素的个数。

long count();

该方法返回一个long值,代表个数。

public class Method_count {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "c"};
        long count = Stream.of(arr).count();
        System.out.println(count);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4.3 filter

用来过滤数据,返回符合条件的数据,通过此方法可以将一个流转换成另一个子集流。

Stream filter(Predicate<? super T> predicate);

该接口接收一个Predicate函数式接口参数作为筛选条件

public class Method_filter {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "c", "aa"};
        Stream<String> s = Stream.of(arr);
        s
           //筛选流元素中包含a的
           .filter(s1 -> s1.contains("a"))
           .forEach(System.out :: println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.4 limit

可以对流进行截取,只取前n个数据。

Stream limit(long maxSize);

参数是一个long类型的数值,如果集合长度大于参数就进行截取操作,反之不操作。

public class Method_limit {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "c", "aa"};
        Stream<String> s = Stream.of(arr);
        //填入的长度不能为负数
        s.limit(2).forEach(System.out :: println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4.5 skip

如果你希望跳过流前面的n个元素,可以使用skip方法获取一个新的流。

Stream skip(long n);

public class Method_skip {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "c", "aa"};
        Stream<String> s = Stream.of(arr);
        s.skip(2).forEach(System.out :: println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4.6 map

如果你希望将流中的元素映射到另一个流中, 可以使用该方法。

Stream map(Function<? super T, ? extends R> mapper);

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

public class Method_map {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
        stream
//                .map( x -> Integer.parseInt(x))
                .map(Integer :: parseInt)
                .forEach(System.out :: println);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.7 sorted

将数据进行排序。

Stream sorted();

public class Method_sorted {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(1, 5, 6, 3, 4, 2);
        stream
                .sorted((o1, o2) -> o2 - o1)//降序,不刻意要求就是升序
                .forEach(System.out :: println);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.8 distinct

用来去除重复的数据。

Stream distinct();

Stream流中distinct方法对于基本数据类型是可以直接去重的,但是对于自定义类型,我们需要去重写hashCod和equals方法来移除重复元素。

public class Method_distinct {
    public static void main(String[] args) {
        String[] arr = {"a", "a", "b", "b"};
        Stream.of(arr)
                .distinct()
                .forEach(System.out :: println);
        System.out.println("-----------------------------");
        Stream.of(
                new Person("MrLiu", 21),
                new Person("张三", 22),
                new Person("MrLiu", 21)
        ).distinct().forEach(System.out :: println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4.9 reduce

如果你希望将所有数据归纳得到一个数据,可以使用此方法。

T reduce(T identity, BinaryOperator accumulator);

public class Method_reduce {
    public static void main(String[] args) {
        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4);
        Integer sum = stream1
                //identity 默认值
                .reduce(0, (x, y) -> {
                    System.out.println("x = " + x + " y = " + y);
                    return x + y;
                });
        System.out.println(sum);
        System.out.println("---------------------------------------");
        Stream<Integer> stream2 = Stream.of(1, 2, 3, 4);
        Integer max = stream2
                //identity 默认值
                .reduce(0, (x, y)
                        -> x > y ? x : y
                );
        System.out.println(max);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4.10 map和reduce的组合

Stream map(Function<? super T, ? extends R> mapper);

public class Method_MapReduce {
    public static void main(String[] args) {
        //1.求出所有年龄的总和
        Integer sum = Stream.of(
                        new Person("MrLiu", 21),
                        new Person("张三", 22),
                        new Person("MrLiu", 23),
                        new Person("王五", 24)
                ).map(Person :: getAge)
                .reduce(0, Integer :: sum);
        System.out.println(sum);

        //2.求出所有年龄中的最大值
        Integer max = Stream.of(
                        new Person("MrLiu", 21),
                        new Person("张三", 22),
                        new Person("MrLiu", 23),
                        new Person("王五", 24)
                ).map(Person::getAge)
                .reduce(0, Math::max);
        System.out.println(max);

        //3.统计 1 出现的次数
        Integer count = Stream.of(1, 2, 3, 1, 2, 3, 1, 2, 3)
                .map(x -> x.equals(1) ? 1 : 0)
                .reduce(0, Integer::sum);
        System.out.println(count);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

4.11 mapToInt

如果需要将Stream中的Integer类型转换为int类型,可以使用此方法。

IntStream mapToInt(ToIntFunction<? super T> mapper);

public class Method_MapToInt {
    public static void main(String[] args) {
        //Integer占用的内存比int要多很多,在Stream流操作中会自动装箱和插箱操作。
        Integer arr[] = {1, 2, 3, 4};
        Stream<Integer> stream = Stream.of(arr);
        stream.filter(i -> i > 0).forEach(System.out :: println);
        //为了提高程序代码的效率,我们可以先将流中的Integer数据转换为int数据类型,再进行操作
        IntStream mapToInt = Stream.of(arr).mapToInt(Integer::intValue);
        mapToInt.filter(i -> i > 0).forEach(System.out :: println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4.12 concat

如果有两个流希望合并为一个流,就可以使用Stream接口的静态方法。

 public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);
        @SuppressWarnings("unchecked")
        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
        return stream.onClose(Streams.composedClose(a, b));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
public class Method_concat {
    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("a", "b", "c");
        Stream<String> stream2 = Stream.of("d", "e", "f");

        Stream<String> concat = Stream.concat(stream1, stream2);
        concat.forEach(System.out::println);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5.Stream流的并行串行

我们前面写的Stream流都属于串行,就是说在一个线程上执行。

5.1 串行

    /* @Author : MrLiu
     * @Date : 19:43 2023/6/15
     * 串行流
     */
    @org.junit.Test
    public void test01(){
        Stream.of(5,6,2,1,3,4)
                .filter(i -> {
                    System.out.println(Thread.currentThread().getName() + " " + i);
                    return i > 3;
                }).count();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
main 5
main 6
main 2
main 1
main 3
main 4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5.2 并行

parallelStream其实就是一个并行执行的游戏,它通过默认的ForkJoinPool,可以提高多线程任务的速度。

    /* @Author : MrLiu
     * @Date : 19:48 2023/6/15
     * 并行流
     */
    @org.junit.Test
    public void test02(){
        List<Integer> list = new ArrayList<>();
        //通过list接口直接获取并行流
        Stream<Integer> integerStream = list.parallelStream();
        //将已有的串行流转换为并行流
        Stream<Integer> parallel = Stream.of(1, 2, 3).parallel();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/629554
推荐阅读
相关标签
  

闽ICP备14008679号