首页 > 编程语言 >Java8新特性之Stream流(六)

Java8新特性之Stream流(六)

时间:2023-10-12 18:46:59浏览次数:43  
标签:Stream System 特性 public item jack println Java8

1. Stream流介绍

一种支持顺序和并行聚合操作的元素序列,能够对集合、数组进行过滤、排序、去重等操作;

Stream流与日常IO流是不同的技术体系;

官方定义:

A sequence of elements supporting sequential and parallel aggregate operations.

Stream的两种操作:

public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon");
        // 中间操作
        Stream<String> namesOfStartsWithJ = names.filter(item -> item.startsWith("j"));
        // 终止操作
        namesOfStartsWithJ.forEach(System.out::println);
    }
}

// 运行结果
jerry
jack
jon

2. Stream的创建方式

  • 数组
public class StreamTest {

    public static void main(String[] args) {
        String[] names = {"tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon"};
        // Arrays工具类的静态方法stream()
        Stream<String> namesOfStream = Arrays.stream(names);
    }
}

  • 集合
public class StreamTest {

    public static void main(String[] args) {
        String[] names = {"tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon"};
        List<String> nameList = Arrays.asList(names);
        // Collection接口的默认方法stream()和parallelStream()
        Stream<String> namesOfStream1 = nameList.stream(); // 顺序流
        Stream<String> namesOfStream2 = nameList.parallelStream(); // 并行流
    }
}

  • Stream接口的静态方法
public class StreamTest {

    public static void main(String[] args) {
        // Stream接口的静态方法of()
        Stream<String> namesOfStream1 = Stream.of("tom");
        Stream<String> namesOfStream2 = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon");
        // Stream接口的静态方法iterate()和generate()生成的无限流
        Stream<Integer> namesOfStream3 = Stream.iterate(1, item -> item + 1); // 迭代方式产生
        Stream<Integer> namesOfStream4 = Stream.generate(() -> new Random().nextInt(100)); // 生成方式产生
        // Stream接口的静态方法empty()生成的空流
        Stream<Integer> namesOfStream5 = Stream.empty();
    }
}

3. Stream的中间操作

  • 过滤
    • filter:对元素进行过滤;
    • distinct:对元素进行去重,必须重写元素的hashCode()和equals()方法;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 过滤不是'j'开头的名称
        names.filter(item -> item.startsWith("j"))
            // 去掉重复的名称
            .distinct()
            .forEach(System.out::println);
    }
}

// 运行结果
jerry
jack
jon
  • 切片
    • limit:截取前面n个元素;
    • skip:跳过前面n个元素,当流中元素个数不足n个时,将返回一个空流;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 截取前面3个元素
        names.limit(3)
            // 跳过前面2个元素
            .skip(2)
            .forEach(System.out::println);
    }
}

// 运行结果
jack

  • 映射
    • map:对元素进行操作,转换为另一种类型;
    • flatMap:对元素进行操作,转换为一种Stream流;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack");
        // 将string名称转换为User对象
        names.map(User::new).forEach(System.out::println);
    }
}

class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User: {name=" + name + "}";
    }
}

// 运行结果
User: {name=tom}
User: {name=jerry}
User: {name=jack}

public class StreamTest {

    public static void main(String[] args) {
        Integer[] arr1 = {1, 2, 3};
        Integer[] arr2 = {4, 5, 6};
        Integer[] arr3 = {7, 8, 9};
        Stream<Integer[]> stream = Stream.of(arr1, arr2, arr3);
        // 将二维数组流转换为一维数组流
        stream.flatMap(Arrays::stream).forEach(System.out::println);
    }
}

// 运行结果
1
2
3
4
5
6
7
8
9
  • 排序
    • sorted:若元素实现了Comparable接口,重写了compareTo方法,则采用元素内部的方法比较,否则需要传入自定义的比较函数;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 将名称进行排序
        names.sorted().forEach(System.out::println);
    }
}

// 运行结果
bob
jack
jack
jerry
jon
kevin
lisa
mark
tom

4. Stream的终止操作

  • 查找
    • findFirst:返回第一个元素,注意不是直接返回的元素对象,而是被Optional容器包装的元素对象;
    • findAny:返回任意一个元素,注意也是返回的被Optional容器包装的元素对象;
    • max:返回元素中的最大值,需要传入比较函数,注意也是返回的被Optional容器包装的元素对象;
    • min:返回元素中的最小值,需要传入比较函数,注意也是返回的被Optional容器包装的元素对象;
public class StreamTest {

    public static void main(String[] args) {
        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);
        Optional<Integer> first = stream1.findFirst();
        System.out.println("first: " + first.get());

        Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6);
        Optional<Integer> any = stream2.findAny();
        System.out.println("any: " + any.get());

        Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5, 6);
        Optional<Integer> max = stream3.max(Integer::compareTo);
        System.out.println("max: " + max.get());

        Stream<Integer> stream4 = Stream.of(1, 2, 3, 4, 5, 6);
        Optional<Integer> min = stream4.min(Integer::compareTo);
        System.out.println("min: " + min.get());
    }
}

// 运行结果
first: 1
any: 1
max: 6
min: 1

  • 匹配

    • allMatch:是否所有元素都匹配;

    • anyMatch:是否有任意一个元素匹配;

    • noneMatch:是否所有元素都不匹配;

public class StreamTest {

    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 是否所有名称长度都小于6
        boolean result1 = stream1.allMatch(item -> item.length() < 6);
        System.out.println("result1: " + result1);

        Stream<String> stream2 = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 是否有名称包含字符'z'
        boolean result2 = stream2.anyMatch(item -> item.contains("z"));
        System.out.println("result2: " + result2);

        Stream<String> stream3 = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 是否所有名称都不是'b'开头
        boolean result3 = stream3.noneMatch(item -> item.startsWith("b"));
        System.out.println("result3: " + result3);
    }
}

// 运行结果
result1: true
result2: false
result3: false

  • 统计
    • count:统计流中元素个数;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 统计以'j'开头的名称数量
        long size = names.filter(item -> item.startsWith("j")).count();
        System.out.println("size: " + size);
    }
}

// 运行结果
size: 4

  • 遍历

    • forEach:遍历元素
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob", "kevin", "jon", "jack");
        // 遍历以'j'开头的名称
        names.filter(item -> item.startsWith("j")).forEach(System.out::println);
    }
}

// 运行结果
jerry
jack
jon
jack

  • 聚合
    • reduce:按照自定义规则对元素进行聚合操作,并返回期待的结果;
public class StreamTest {

    public static void main(String[] args) {
        Stream<Integer> stream1 = Stream.iterate(1, item -> item + 1);
        // 1~100的和
        Optional<Integer> sum1 = stream1.limit(100).reduce(Integer::sum);
        System.out.println("sum1: " + sum1.get());

        Stream<Integer> stream2 = Stream.iterate(1, item -> item + 1);
        // 初始值为100, 再加上1~100的和
        Integer sum2 = stream2.limit(100).reduce(100, Integer::sum);
        System.out.println("sum2: " + sum2);
    }
}

// 运行结果
sum1: 5050
sum2: 5150

  • 收集
    • collect:将已操作过的元素收集起来,可返回List、Set、Map等等;
public class StreamTest {

  public static void main(String[] args) {
        Stream<Integer> stream1 = Stream.iterate(1, item -> item + 1);
        // 将1~10的偶数收集到List中
        List<Integer> evenNumbers = stream1.limit(10)
            .filter(item -> item % 2 == 0)
          .collect(Collectors.toList());
        System.out.println("偶数: " + evenNumbers);

        Stream<Integer> stream2 = Stream.iterate(1, item -> item + 1);
        // 将1~10的奇偶数分类放入map中
        Map<String, List<Integer>> numberMap = stream2.limit(10)
            .collect(
                Collectors.toMap(
                    item -> item % 2 == 0 ? "偶数" : "奇数",
                    item -> {
                        List<Integer> list = new ArrayList<>();
                        list.add(item);
                        return list;
                    },
                    (oldList, newList) -> {
                        newList.addAll(oldList);
                        return newList;
                    }
                )
            );
        System.out.println("奇偶数分类: " + numberMap);
    }
}

// 运行结果
偶数: [2, 4, 6, 8, 10]
奇偶数分类: {偶数=[10, 8, 6, 4, 2], 奇数=[9, 7, 5, 3, 1]}

5. Stream的并行流

  1. Stream流可以通过实例的parallel和sequential两个方法在并行流和顺序流之间切换;
  2. Stream并行流是以Java7引入的fork/join框架为基础,以递归方式将可以并行的任务拆分成更小的任务,然后将每个子任务的结果合并起来生成整体结果;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> names = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob");
        names.parallel().filter(item -> {
            System.out.println("filter: " + "thread=" + Thread.currentThread().getName() + ", item=" + item);
            return item.startsWith("j");
        }).forEach(item -> System.out.println("result: " + item));
    }
}

// 运行结果
filter: thread=main, item=lisa
filter: thread=ForkJoinPool.commonPool-worker-2, item=bob
filter: thread=main, item=tom
filter: thread=ForkJoinPool.commonPool-worker-3, item=jack
filter: thread=ForkJoinPool.commonPool-worker-1, item=jerry
filter: thread=ForkJoinPool.commonPool-worker-2, item=mark
result: jerry
result: jack

6. Stream的注意事项

  1. Stream自己不会存储元素;
  2. Stream的中间操作不会改变源对象,相反它会返回一个持有结果的新Stream实例;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob");
        Stream<String> stream2 = stream1.filter(item -> item.startsWith("j"));
        // stream1与stream2是两个不同的对象
        System.out.println(stream1);
        System.out.println(stream2);
    }
}

// 运行结果
java.util.stream.ReferencePipeline$Head@404b9385
java.util.stream.ReferencePipeline$2@6d311334

  1. Stream的中间操作是延迟加载的,只有当终止操作存在的时候,中间操作才会执行;
public class StreamTest {

    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("tom", "jerry", "jack", "lisa", "mark", "bob");
        Stream<String> stream2 = stream1.filter(item -> {
            // 这里的打印不会执行
            System.out.println("filter: " + item);
            return item.startsWith("j");
        });
    }
}

  1. Stream的执行实际上是每一个元素沿着执行链垂直移动的,也就是说当一个元素将执行链执行完成后才会开始第二个元素,但注意排序操作例外;
public class StreamTest {

    public static void main(String[] args) {
        Stream<Integer> stream1 = Stream.of(3, 1, 2, 5, 6, 4);
        stream1.sorted((a, b) -> {
            // 全部元素完成排序
            System.out.println("sort: " + a + ", " + b);
            return Integer.compare(a, b);
        }).filter(item -> {
            // 1. 对元素过滤
            System.out.println("filter: " + item);
            return item <= 3;
        }).map(item -> {
            // 2. 对元素操作
            System.out.println("map: " + item * 2);
            return item * 2;
        }).forEach(item -> {
            // 3. 对元素打印
            System.out.println("print: " + item);
        });
    }
}

// 运行结果
sort: 1, 3
sort: 2, 1
sort: 2, 3
sort: 2, 1
sort: 5, 2
sort: 5, 3
sort: 6, 3
sort: 6, 5
sort: 4, 3
sort: 4, 6
sort: 4, 5
filter: 1
map: 2
print: 2
filter: 2
map: 4
print: 4
filter: 3
map: 6
print: 6
filter: 4
filter: 5
filter: 6

  1. Stream的实例在执行终止操作后不能再执行其他操作,否则会抛出stream has already been operated upon or closed异常;

————————————————

原文链接:https://blog.csdn.net/gu19930914/article/details/115769134

标签:Stream,System,特性,public,item,jack,println,Java8
From: https://www.cnblogs.com/hefeng2014/p/17760277.html

相关文章

  • Java8新特性之重复注解和类型注解(五)
    1.重复注解介绍Java8中引入的一个新注解@Repeatable,该注解只能标记在其他注解上,表示被标记的注解可以重复声明在类、属性、方法等上面;但@Repeatable注解还是得需要定义容器注解配合才能使用,所以也只是增强了代码的可读性;publicclassAnnotationTest{/***Java8之......
  • Java8新特性之方法引用(三)
    1.方法引用介绍方法引用其实是lambda表达式的升级写法,采用::固定语法,可以使代码更简洁、紧凑;2.方法引用的5种类型2.1对象引用::实例方法名函数式接口抽象方法的形参列表与实例方法的一致,且方法的返回值类型一致;publicclassMethodReferencesTest{publicstaticvo......
  • Java8新特性之接口的默认方法和静态方法(四)
    1.背景介绍在Java8之前,接口中定义的方法都是抽象方法,即默认都是被publicabstract修饰的;但从Java8开始,允许在接口中定义带有方法体的默认方法和静态方法;publicclassInterfaceTest{publicstaticvoidmain(String[]args){}}interfaceInterfaceA{/*......
  • Java8新特性之函数式接口(二)
    1,函数式接口介绍前言:由于Java8中引入了lambda表达式语法,但该语法需要配合一种特定的接口才能使用,由此产生出了函数式接口;函数式接口指有且仅有一个抽象方法(由Object对象继承的方法不算)(但可以有多个默认方法和静态方法)的接口,当这样的接口在作为方法参数时可以隐式的转换为lambda......
  • Java8新特性之Lambda表达式(一)
    Java8新特性之Lambda表达式(一)文章目录1.lambda表达式介绍2.lambda表达式的重要特征3.lambda表达式对域外变量的限制4.lambda表达式的优缺点5.lambda表达式的使用场景6.lambda表达式的实现原理7.相关链接1.lambda表达式介绍lambda表达式是Java8提供的新特......
  • ASEMI整流桥KBU810参数,KBU810特性
    编辑-ZKBU810参数描述:型号:KBU810最大直流反向电压VR:1000V最大工作峰值反向电压VRWM:700V最大平均正向电流IF:8A非重复正向浪涌电流IFSM:300A操作和储存温度范围TJ,TSTG:-55to150℃正向电压VF:1.1V最大反向泄漏电流IRM:10uA每个元件的典型热阻RthJA:2.7℃/W KBU810封装规格:封装:KBU-4总......
  • Java 1.8 list特性用法
    list转换成具体的字符串拼接@TestpublicvoidListToString(){//构造listList<String>list=Arrays.asList("张三","李四","王五","赵六");//以逗号分隔,带前缀后缀Stringstr1=list.stream().collect(Collectors.joining(&q......
  • 开发者笔记 C++11新特性并发编程future
    上一篇介绍了<thread>文件里线程相关类,这篇将介绍C++<future>头文件里线程类,future里包含的类主要是处理异步任务,线程函数封装,线程间通信,同步,捕捉异常处理https://zhuanlan.zhihu.com/p/509118687future的引入c++11引入的future是为了解决异步通信问题的。future可以看做是数......
  • Spring Boot 2.6.0 发布,一大波新特性,禁止了循环依赖,还有哪些更新
    1、默认禁止了循环依赖循环依赖大家都知道,也被折磨过,这下2.6.0的版本默认禁止了循环依赖,如果程序中出现循环依赖就会报错。当然并没有一锤子打死,也提供了开启允许循环依赖的配置,只需要在配置文件中开启即可:spring:main:allow-circular-references:true2、支持自定义脱敏规......
  • C++11新特性之基本范围的For循环(range-based-for)
    C++11新特性之基本范围的For循环(range-based-for)最新推荐文章于 2023-07-2219:30:58 发布Rayen0715于2017-01-0713:49:35发布49588收藏174版权Range-Based-For熟悉C++98/......