Java8新特性之Stream的使用

流(Stream)的基本介绍

在这里插入图片描述

Stream的操作步骤

  • 创建Stream
    一个数据源(如:集合、数组),获取一个流
  • 中间操作
    一个中间操作链,对数据源的数据进行处理
  • 终止操作(终端操作)
    一个终止操作,执行中间操作链,并产生结果
    在这里插入图片描述

创建Stream

在这里插入图片描述

public class Demo01 {

    List<Person> people = Arrays.asList(
            new Person("A", 24),
            new Person("B", 44),
            new Person("E", 53),
            new Person("C", 53),
            new Person("D", 19));

    @Test
    public void test01() {
        // 1. 通过Collection集合提供的stream()
        ArrayList<Object> list = new ArrayList<>();
        Stream<Object> stream = list.stream();
        // 2.通过Arrays中静态方法获取数组流
        int arr[] = {1, 2, 3};
        IntStream stream1 = Arrays.stream(arr);
        // 3.通过Stream中的静态方法
        Stream<String> stream2 = Stream.of("aa", "bb", "cc");
        // 4.创建无限流
        // 迭代
        Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2);
        stream3.limit(10);
        stream3.forEach(System.out::println);

        // 生成
        Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);
    }
}

中间操作

1.筛选与切片

在这里插入图片描述

@Test
    public void test02() {
        // 内部迭代
        // 中间操作:不会执行任何操作
        Stream<Person> stream = people.stream().
                filter((e) -> e.age > 30);
        // 终止操作:一次性执行全部内容
        stream.forEach(System.out::println);
    }

    @Test
    public void test03() {
        people.stream()
                .filter((e) -> e.age > 20)
                // 取前两个
                .limit(2)
                .forEach(System.out::println);
    }

    @Test
    public void test04() {
        people.stream()
                .filter((e) -> e.age > 20)
                // 跳过前两个
                .skip(2)
                .forEach(System.out::println);
    }

    @Test
    public void test05() {
        people.stream()
                .filter((e) -> e.age > 20)
                .skip(2)
                // 去重
                .distinct()
                .forEach(System.out::println);
    }
2.映射

在这里插入图片描述

@Test
    public void test06() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc");
        list.stream()
                .map((str) -> str.toUpperCase())
                .forEach(System.out::println);

        System.out.println("提取Person名字");
        people.stream().map(Person::getName)
                .forEach(System.out::println);
    }

3.排序
@Test
    public void test07() {
        // 排序
        List<String> list = Arrays.asList("ddd", "aaa", "bbb", "ccc");
        list.stream()
                .sorted()
                .forEach(System.out::println);

        System.out.println("--------------------");
        // 年龄一样按照姓名排
        people.stream()
                .sorted((e1, e2) -> {
                    if (e1.age == e2.age) {
                        return e1.name.compareTo(e2.name);
                    } else {
                        return e1.age - e2.age;
                    }
                })
                .forEach(System.out::println);
    }

在这里插入图片描述

终止操作

终止操作会从流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void。

1.查找与匹配

在这里插入图片描述

@Test
    public void test08() {
        // 查找与匹配
        boolean b = people.stream()
                // 是否匹配所有元素
                .allMatch((e) -> e.name.equals("B"));
        System.out.println(b);

        System.out.println("----------------");
        // 至少有一个匹配
        boolean b1 = people.stream().anyMatch((e) -> e.name.equals("B"));
        System.out.println(b1);

        System.out.println("----------------");
        // 是否没有匹配所有元素
        boolean b2 = people.stream().noneMatch((e) -> e.name.equals("B"));
        System.out.println(b2);

        System.out.println("-------------------------");
        // 找出第一个,年龄最小的,最终结果有可能为空时
        Optional<Person> first = people.stream().sorted(Comparator.comparing(e -> e.age))
                .findFirst();
        System.out.println(first.get());

        System.out.println("-------------------------");
        Optional<Person> optional = people.stream()
                .filter((e) -> e.age > 30)
                .findAny();
        System.out.println(optional.get());
    }

    @Test
    public void test09() {
        long count = people.stream().count();
        System.out.println(count);

        // 获取年龄最大
        Optional<Person> max = people.stream().max(Comparator.comparingInt(e -> e.age));
        System.out.println(max.get());
        System.out.println("----------------------");

        // 获取最小名字
        Optional<String> min = people.stream()
                .map(Person::getName)
                .min(String::compareTo);
        System.out.println(min.get());
    }

2.归约

在这里插入图片描述

@Test
    public void test10() {
        // 归约
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Integer reduce = list.stream()
                .reduce(0, (x, y) -> x + y);
        System.out.println(reduce);

        System.out.println("---------------");
        // 年龄总和
        Optional<Integer> op = people.stream()
                .map(Person::getAge)
                .reduce(Integer::sum);
        System.out.println("年龄总和:" + op.get());
    }

在这里插入图片描述

3.收集

在这里插入图片描述
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

在这里插入图片描述
在这里插入图片描述

@Test
    public void test11() {
        // 收集
        // 提取所有姓名
        List<String> list = people.stream()
                .map(Person::getName)
                .collect(Collectors.toList());
        System.out.println(list);

        System.out.println("----------------");
        HashSet<String> set = people.stream()
                .map(Person::getName)
                .collect(Collectors.toCollection(HashSet::new));
        set.forEach(System.out::println);
    }

    @Test
    public void test12() {
        // 收集
        Long set = people.stream()
                .collect(Collectors.counting());
        System.out.println(set);

        // 年龄平均值
        Double age = people.stream()
                .collect(Collectors.averagingInt(Person::getAge));
        System.out.println(age);

        System.out.println("-------------------------");
        IntSummaryStatistics agesum = people.stream()
                .collect(Collectors.summarizingInt(Person::getAge));
        System.out.println(agesum);


        System.out.println("-------------------------");
        // 获取年龄字符最大
        Optional<Person> name = people.stream().max(Comparator.comparing(e -> e.name));
        System.out.println(name.get());
    }
4.分组、分区
 @Test
    public void test13() {
        // 分组
        // 按照相同年龄分组
        Map<Integer, List<Person>> map = people.stream()
                .collect(Collectors.groupingBy(Person::getAge));
        map.entrySet().forEach(System.out::println);
    }

    @Test
    public void test14() {
        // 多级分组
        Map<Integer, Map<String, List<Person>>> map = people.stream()
                .collect(Collectors.groupingBy(Person::getAge, Collectors.groupingBy((e) -> {
                    if (e.getAge() <= 35) {
                        return "青年";
                    } else {
                        return "中年";
                    }
                })));
        map.entrySet().forEach(System.out::println);
    }

    @Test
    public void test15() {
        // 分区
        // 满足条件一个区
        Map<Boolean, List<Person>> map = people.stream()
                .collect(Collectors.partitioningBy((e) -> e.age > 35));
        map.entrySet().forEach(System.out::println);
    }

    @Test
    public void test16() {
        // 分区
        // 满足条件一个区
        IntSummaryStatistics statistics = people.stream()
                .collect(Collectors.summarizingInt(Person::getAge));
        System.out.println(statistics.getAverage());
        System.out.println(statistics.getCount());
        System.out.println(statistics.getMax());
    }

    @Test
    public void test17() {
        // 分区
        // 满足条件一个区
        String s = people.stream()
                .map(Person::getName)
                // 中间 首部  尾部
                .collect(Collectors.joining(",", "<", ">"));
        System.out.println(s);
    }

并行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

Fork/Join 框架介绍

Fork/Join 框架:就是在必要的情况下,将一个大任务,进形拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运行的结果进行join汇总。
在这里插入图片描述

Fork/Join 框架与传统线程池的区别:

采用“工作窃取”模式(work-stealing):
当执行新的任务时,它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。

相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能。

public class ForkJoinDemo extends RecursiveTask<Long> {

    private static final long serialVersionUID = 13465648909L;
    private long start;
    private long end;
    private static final long THRESHOLD = 10000;

    public ForkJoinDemo(long start, long end) {
        this.start = start;
        this.end = end;
    }

    public static void main(String args[]) {
        Instant start = Instant.now();
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinDemo(0, 10000000L);
        Long sum = pool.invoke(task);
        System.out.println(sum);
        Instant end = Instant.now();
        System.out.println(Duration.between(start, end).toMillis());

    }

    protected Long compute() {
        long length = end - start;
        if (length <= THRESHOLD) {
            long sum = 0;
            for (long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        } else {
            long mid = (start + end) / 2;
            ForkJoinDemo left = new ForkJoinDemo(start, mid);
            left.fork();
            ForkJoinDemo right = new ForkJoinDemo(mid + 1, end);
            right.fork();
            return left.join() + right.join();
        }

    }
}

在这里插入图片描述

Java8并行流

Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。

@Test
    public void test20() {
        // 并行流
        long l = LongStream.rangeClosed(0, 10000000L)
                .parallel()
                .reduce(0, Long::sum);
        System.out.println(l);
    }

在这里插入图片描述

Stream练习

 @Test
 public void test18() {
        // 给定数字列表
        // 返回每个数字列表的平方列表
        Integer[] integers = new Integer[]{1, 2, 3, 4, 5};
        Arrays.stream(integers)
                .map((x) -> x * x)
                .forEach((i) -> System.out.print(i + " "));
    }

在这里插入图片描述

@Test
    public void test19() {
        // 获取people集合中数目
        Optional<Integer> optional = people.stream()
                .map((e) -> 1)
                .reduce(Integer::sum);
        System.out.println(optional.get());
    }

在这里插入图片描述

发布了83 篇原创文章 · 获赞 23 · 访问量 3532

猜你喜欢

转载自blog.csdn.net/qq_44779506/article/details/105303258