6

stream是什么

Stream就像一条数据流,你可以把它看作是一系列元素的通道,这些元素可以是集合中的数据。使用Stream,你可以通过一系列的操作来处理这些数据,而不必显式地使用传统的循环和条件语句。Stream提供了一种更简洁、更易读的方法来对数据进行操作,尤其是对于集合(比如List、Set、Map等)中的元素。

Java Stream的特点

  1. 惰性求值: stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
  2. 函数式编程: Stream 提供了丰富的函数式编程操作,如 map、filter、reduce 等,使得对集合的处理更加灵活和表达力更强。
  3. 不改变原始数据: Stream 操作不会改变原始数据,而是返回一个新的 Stream。这种非破坏性的操作使得可以轻松地组合和复用操作。

流的操作种类

流的种类分为两种,元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。

中间操作

中间操作是对流进行处理和转换的操作,它们不会触发实际的计算,而是返回一个新的 Stream。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。而是在终端操作开始的时候才真正开始执行。
通俗的解释是中间操作就像是对一条河流进行不同的处理,但并没有真正触发水流的运动,是工作前的准备,你可以在河流中设置一个过滤器,只允许通过的鱼有特定颜色。这只是一种设定,但并没有让鱼开始移动。这就是中间操作的作用。

终端操作

终端操作是对流进行最终处理的操作,它们会触发对流的遍历和计算,并生成一个结果。终端操作是流的最后一步,一旦触发,就无法再对同一个流进行其他操作。
通俗的解释是你可以把终端操作看作是在河流中放一个桶,捞起鱼,然后数一数。这个过程是真正触发了对水流的操作,得到了一个最终的结果,即桶中的鱼的数量。

image.png

stream的使用

中间操作的使用

filter(): 根据给定的条件过滤流中的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> newNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
System.out.println(newNumbers);
//输出 [2、4、6]

map(): 将流中的每个元素映射为另一个元素。

List<String> words = Arrays.asList("apple","banana");

List<String> upperCaseWords = words.stream()
                            .map(String::toUpperCase)
                            .collect(Collectors.toList());  

System.out.println(upperCaseWords);  // 输出: [APPLE, BANANA]

distinct() 去除流中的重复元素。

 List<String> myList = Arrays.asList("apple", "banana", "apple");
 List<String> uniqueList = myList.stream()
                          .distinct() 
                          .collect(Collectors.toList());

System.out.println(uniqueList); 
// ["apple", "banana"]

limit(long maxSize) 截取元素

 List<String> myList = Arrays.asList("apple", "banana", "apple");
 List<String> limitedList = myList.stream()
                          .limit(1) 
                          .collect(Collectors.toList());

System.out.println(limitedList); 
//  ["apple"]

sorted() 将流中的元素按照自然排序方式进行排序。

 List<Integer> numbers = List.of(5, 2, 8, 1, 6, 3, 7, 4);

 List<Integer> sortedNumbers = numbers.stream()
                        .sorted()  
                        .collect(Collectors.toList());  

 System.out.println(sortedNumbers); 
 // [1, 2, 3, 4, 5, 6, 7, 8]

skip():和limit()相反,将前几个元素跳过(取出)再返回一个流,

 List<String> myList = Arrays.asList("apple", "banana", "apple");
 List<String> skipList = myList.stream()
                          .skip(1) 
                          .collect(Collectors.toList());

System.out.println(skipList); 
// ["banana", "apple"]

flatMap() 流中的每个元素都放到一个流中,最后将所有的流合并成一个新流

 List<String> words = Arrays.asList("hello", "world");

 List<String> uniqueCharacters = words.stream()
  .flatMap(s -> Arrays.stream(s.split("")))  
  .distinct()
  .collect(Collectors.toList()); 

System.out.println(uniqueCharacters);  
//  [h, e, l, o, w, r, d]

终端操作的使用

forEach() 对流中的每个元素执行指定的操作

List<String> myList = Arrays.asList("apple", "banana", "orange");
myList.stream().forEach(System.out::println);
// apple banana orange

collect() 将流元素收集到一个容器中,比如List,Set,Map。

 List<String> myList = Arrays.asList("apple", "banana", "orange");

 List<String> collectedList = myList.stream().collect(Collectors.toList());
 Set<String> set = myList.stream().collect(Collectors.toSet());
 Map<String, String> map = myList.stream().collect(Collectors.toMap(k -> k, v -> v));

 System.out.println(collectedList);
 // [apple, banana, orange]
 System.out.println(set);
 // [banana, orange, apple]
 System.out.println(map);
 // {banana=banana, orange=orange, apple=apple}

count()返回流中元素的数量

List<String> myList = Arrays.asList("apple", "banana", "orange");
long count = myList.stream().count();
System.out.println(count); // 3

reduce()对流中的元素进行归约操作

 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
 Integer i = numbers.stream().reduce((a, b) -> a + b).get();
 System.out.println(i); // 15

anyMatch()判断流中是否有任一元素匹配给定条件

List<String> myList = Arrays.asList("apple", "banana", "orange");
boolean anyMatch = myList.stream().anyMatch(s -> s.startsWith("a"));

System.out.println(anyMatch); // true

allMatch()判断流中是否所有元素都匹配给定条件

List<String> myList = Arrays.asList("apple", "banana", "orange");
boolean allMatch = myList.stream().allMatch(s -> s.length() > 3);
System.out.println(allMatch); // true

noneMatch()判断流中是否没有任何元素匹配给定条件

List<String> myList = Arrays.asList("apple", "banana", "orange");
boolean noneMatch = myList.stream().noneMatch(s -> s.contains("x"));
System.out.println(noneMatch); // true

findAny()返回流中的任意元素和findFirst()返回流中的第一个元素

 List<String> myList = Arrays.asList("apple", "banana", "orange");
 Optional<String> findAny = myList.stream().findAny();
 Optional<String> first = myList.stream().findFirst();

 System.out.println(findAny); // 可能是其中任何值
 System.out.println(first); // Optional[apple]

min() 和 max() 返回流中的最小或最大元素。

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
Integer min = numbers.stream().min(Comparator.naturalOrder()).get(); Integer max = numbers.stream().max(Comparator.naturalOrder()).get();
System.out.println(min); // 1
System.out.println(max); // 9

groupingBy() 给定条件进行分组

 List<String> myList = Arrays.asList("apple", "banana", "orange");
 Map<Integer, List<String>> groupedByLength = myList.stream()
                .collect(Collectors.groupingBy(String::length));
        
groupedByLength.forEach((length, strings) -> {
 System.out.println("Length " + length + ": " + strings);
});

// Length 5: [apple]
// Length 6: [banana, orange]

上面列举了一些关于stream的常见用法


kexb
474 声望15 粉丝

引用和评论

0 条评论