比较 Stream 和 List

StreamList不一样,List存储的每个元素都是已经存储在内存中的某个Java对象,而Stream输出的元素可能并没有预先存储在内存中,而是实时计算出来的。

Stream API的基本用法就是:创建一个Stream,然后做若干次转换,最后调用一个求值方法获取真正计算的结果:

int result = createNaturalStream()// 创建Stream
             .filter(n -> n % 2 == 0)// 任意个转换
             .map(n -> n * n)// 任意个转换
             .limit(100)// 任意个转换
             .sum();// 最终计算结果

Stream API的特点是:

创建 Stream

  1. Stream.of() 静态方法

            Stream<String> stream = Stream.of("A", "B", "C", "D");
            // forEach()方法相当于内部循环调用,
            // 可传入符合Consumer接口的void accept(T t)的方法引用:
            stream.forEach(System.out::println);
    
  2. 基于数组或者 Collection

            Stream<String> stream1 = Arrays.stream(new String[] { "A", "B", "C" });
            Stream<String> stream2 = List.of("X", "Y", "Z").stream();
            stream1.forEach(System.out::println);
            stream2.forEach(System.out::println);
    
  3. 基于 Supplier

    public class Main {
        public static void main(String[] args) {
            Stream<Integer> natual = Stream.generate(new NatualSupplier());
            // 注意:无限序列必须先变成有限序列再打印:
            natual.limit(20).forEach(System.out::println);
        }
    }
    
    class NatualSupplier implements Supplier<Integer> {
        int n = 0;
        public Integer get() {
            n++;
            return n;
        }
    }
    
    
  4. 其他方法

    1. 使用 Files 提供的方法按行便利文本:Stream<String> lines = Files.lines(Paths.get("/path/to/file.txt"))

    2. 使用正则表达式将长字符串分割成 Stream 序列

      Pattern p = Pattern.compile("\\\\s+");
      Stream<String> s = p.splitAsStream("The quick brown fox jumps over the lazy dog");
      s.forEach(System.out::println);
      

<aside> 💡 因为Java的范型不支持基本类型,所以我们无法用Stream<int>这样的类型,会发生编译错误。为了保存int,只能使用Stream<Integer>,但这样会产生频繁的装箱、拆箱操作。为了提高效率,Java标准库提供了IntStreamLongStreamDoubleStream这三种使用基本类型的Stream,它们的使用方法和范型Stream没有大的区别,设计这三个Stream的目的是提高运行效率:

// 将int[]数组变为IntStream:
IntStream is = Arrays.stream(newint[] { 1, 2, 3 });
// 将Stream<String>转换为LongStream:
LongStream ls = List.of("1", "2", "3").stream().mapToLong(Long::parseLong);

</aside>

map() 方法

Stream<Integer> s = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> s2 = s.map(n -> n * n);

使用 map() 方法可以处理流中的每一个元素

public class Main {
    public static void main(String[] args) {
        List.of("  Apple ", " pear ", " ORANGE", " BaNaNa ")
                .stream()
                .map(String::trim) // 去空格
                .map(String::toLowerCase) // 变小写
                .forEach(System.out::println); // 打印
    }
}

filter() 方法

使用 filter() 方法可以过滤掉集合中的部分元素