JAVA21-Stream(流)

什么是流?流(Stream)是 Java 8 引入的一个强大的 API,用于处理集合数据的函数式编程操作。流提供了一种高效、声明式的方式来处理数据,特别适合对集合进行过滤、映射、排序、聚合等操作。

你可以把它想象成一条水流,它会把集合中的元素一个一个放入这条水流中,无论集合是有序的还是无序的,它们在流中都会一个一个的按照顺序被取出,你可以对取出的每一个元素做无限次数的中间处理一次终结操作,终结操作后,这个流就被销毁了

Java 8 Stream

  • 一个
  • 简化代码
  • 不易出错
  • 可读性/可维护性++

如何获得流

普通流

  1. 任何的集合调用.stream()方法就可以得到一个
  2. Stream.of
  3. String.chars
  4. IntStream.range

并发流

拿到一个流后还可以把它转换成并发流.parallel()
Collection.parallelStream() 集合中这个方法也可以返回一个并发流
并发流可以用在一些中间操作相互独立没有依赖关系的情况下,可以提升效率,可以并行的玩完成
并发流的使用要相当小心,你要确认是否有线程安全问题,也要确认是否给你带来了性能提升
否则就忘掉它吧

可以对流中的元素做哪些中间处理

常见的中间操作

  • filter 过滤
  • sorted 排序
  • map 映射

可以对流做哪些终结操作

任何返回非stream的操作都是终结操作

常见的终结操作

  • collect 收集
  • Collectors.toList
  • Collectors.toSet
  • Collectors.toCollection
  • Collectors.groupingBy
  • Collectors.partitioningBy
  • Collectors.joining
  • Collectors.summingInt
  • forEach 循环每个元素
  • count/max/min
  • anyMatch/noneMatch
  • findFirst/findAny 用在filter操作之后,取第一个或任意取一个,返回值是一个Optional,因为filter可能没有匹配的

Optional的正确用法

不要把它当成空指针用,它的正确用法是和函数式绑定

 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class Main {
    private static class User {
        private String name;
        private int age;

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

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public boolean isWang() {
            return name.startsWith("王");
        }
    }

    public static void main(String[] args) {
        List<User> users = Arrays.asList(
                new User("张三", 20),
                new User("李四", 25),
                new User("王五", 23));

        // 反例
        Optional<User> optionalUser = users.stream().filter(User::isWang).findAny();
        if (optionalUser.isPresent()) {
            System.out.println(optionalUser.get().getName());
        } else {
            throw new IllegalStateException();
        }
        
        // 正例
        User user = users.stream().filter(User::isWang).findAny().orElseThrow(IllegalStateException::new);
        System.out.println(user.getName());
    }
}

Stream Test

  • Test 1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Problem2 {
    // 判断一段文本中是否包含关键词列表中的文本,如果包含任意一个关键词,返回true,否则返回false
    // 例如,text="catcatcat,boyboyboy", keywords=["boy", "girl"],返回true
    // 例如,text="I am a boy", keywords=["cat", "dog"],返回false
    public static boolean containsKeyword(String text, List<String> keywords) {
        return keywords.stream().anyMatch(text::contains);
    }

    public static void main(String[] args) {
        System.out.println(containsKeyword("catcatcat,boyboyboy", Arrays.asList("boy", "girl")));
        System.out.println(containsKeyword("I am a boy", Arrays.asList("cat", "dog")));
    }
}
  • Test 2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class Problem3 {
    // 使用流的方法,再把之前的题目做一遍吧
    // 统计一个给定的字符串中,大写英文字母(A,B,C,...,Z)出现的次数。
    // 例如,给定字符串"AaBbCc1234ABC",返回6,因为该字符串中出现了6次大写英文字母ABCABC
    public static int countUpperCaseLetters(String str) {
        return (int) str.chars().filter(Character::isUpperCase).count();
    }

    public static void main(String[] args) {
        System.out.println(countUpperCaseLetters("AaBbCc1234ABC"));
    }
}
  • Test 3
 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
30
public class Problem5 {
    static class Order {
        private Integer id;
        private String name;

        Order(Integer id, String name) {
            this.id = id;
            this.name = name;
        }

        public Integer getId() {
            return id;
        }

        public String getName() {
            return name;
        }
    }
    
    // 使用流的方法,把订单处理成ID->订单的映射
    // 例如,传入参数[{id=1,name='肥皂'},{id=2,name='牙刷'}]
    // 返回一个映射{1->Order(1,'肥皂'),2->Order(2,'牙刷')}
    public static Map<Integer, Order> toMap(List<Order> orders) {
        return orders.stream().collect(Collectors.toMap((order -> order.id), (order -> order)));
    }

    public static void main(String[] args) {
        System.out.println(toMap(Arrays.asList(new Order(1, "肥皂"), new Order(2, "牙刷"))));
    }
}
  • Test 4
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Problem6 {
    // 使用流的方法,把所有长度等于1的单词挑出来,然后用逗号连接起来
    // 例如,传入参数words=['a','bb','ccc','d','e']
    // 返回字符串a,d,e
    public static String filterThenConcat(Set<String> words) {
        return words.stream().filter(ch -> ch.length() == 1).collect(Collectors.joining(","));
    }

    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<>(Arrays.asList("a", "bb", "ccc", "d", "e"));
        System.out.println(filterThenConcat(set));
    }
}
updatedupdated2025-03-012025-03-01