Java stream 流

224 阅读3分钟

流式计算

  • 能用流解决的用迭代必然能解决.
  • 流可以进行并行计算,大大提高效率.
  • 流处理==集合==
  • 一个 流只能使用 ==一次==
  • ==并行流需要的条件比较多==

流与集合的区别

  • 流不存储数据
  • 流的操作不会影响其数据源
  • 流的操作是==惰性的==,即 有需求 才会进行计算,可以操作==无限流==

流的创建

利用 collection 集合类的 stream 方法

public static void main(String[] args) {
    ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    System.out.println(arrayList.parallelStream().filter(o -> o % 2 > 0).count());
}

利用静态的 stream.of 方法

public static void main(String[] args) {
    ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

    Stream<ArrayList<Integer>> stream = Stream.of(arrayList);

    System.out.println(stream.count());
}
  • stream.of 方法是可变参数
public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);
}

使用 empty 创建空流

public static void main(String[] args) {
    Stream<Object> empty = Stream.empty();
    System.out.println(empty.count());
}

使用 generate 创建无限流

public static void main(String[] args) {
    Stream<Integer> generate = Stream.generate(() -> Integer.MAX_VALUE);
    System.out.println(generate.count()); // 永远不会执行
}

使用迭代器创建

public static void main(String[] args) {
    Stream<BigInteger> iterate = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));
    System.out.println(iterate.count());
}

流的操作

  • 流的操作会生成一个新的流,不会对原有的流有任何侵入.

filter 方法

  • 匹配
  • 筛选
  • 过滤
public static void main(String[] args) {
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
    System.out.println(stream.filter(n -> n % 2 == 0).count());
}

map 方法

  • 转换
  • 映射
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
stream.map(n -> n+1).forEach(System.out::println);

distinct 方法

  • 元素去重
public static void main(String[] args) {
    Stream<Integer> concat = Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6, 6));
    concat.distinct().forEach(System.out::println);
}

sorted

  • 排序

peek

  • 产生另一个流,元素与原来的流中的元素相同,在访问某个元素时,就回调用action
  • 类似一个监视器
    public static void main(String[] args) {
        Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6, 6))
                .peek(o-> System.out.print("hello"))
                .forEach(System.out::print);
    }

输出 : hello1hello2hello3hello4hello5hello6hello6

遍历

  • 并行流的遍历顺序是不确定的
Stream<Integer> concat = Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6));
concat.parallel().forEach(System.out::println);
  • 使用 ==forEachOrdered== 避免随机顺序的问题,但是牺牲了部分性能
Stream<Integer> concat = Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6));
concat.parallel().forEachOrdered(System.out::println);

将流转回 array

  • 使用 toArray
public static void main(String[] args) {
    Stream<Integer> concat = Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6));

    Integer[] integers = concat.toArray(Integer[]::new);
    
    System.out.println(Arrays.toString(integers));
}
  • 使用 collect 方法
public static void main(String[] args) {
    Stream<Integer> concat = Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6));

    List<Integer> integers = concat.collect(Collectors.toList());
    
    System.out.println(integers);
}

抽取子流和链接流

抽取子流

  • 从前截取
public static void main(String[] args) {
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
    stream.limit(3).forEach(System.out::println);
}
  • 从后截断
public static void main(String[] args) {
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
    stream.skip(3).forEach(System.out::println);
}

链接流

public static void main(String[] args) {
    Stream<Integer> concat = Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6));
    concat.forEach(System.out::println);
}

流转换为 map

  • 使用 toMap 可解决,在键可能会冲突时,使用 (existVal, newVal) -> existVal) 来选择需要保留的键值对,否则会抛出异常.
class Student {
    int id;
    String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
public static void main(String[] args) {
    Student a = new Student(1, "a");
    Student d = new Student(1, "d");

    Student b = new Student(2, "b");
    Student c = new Student(3, "c");
    List<Student> students = Arrays.asList(a, b, c, d);

    Map<Integer, String> collect = students.parallelStream().collect(Collectors.toMap(
        student -> student.id, student -> student.name, (existVal, newVal) -> existVal));

    String s = collect.get(1);
    System.out.println(s);


}
  • 转化为 ==键--集合== 对
Map<Integer, List<Student>> collect = students.parallelStream().collect(Collectors.groupingBy(Student::getId));

基本类型流

IntStream

  • 可以存储 short char byteboolean int

doubleStream

  • 可以存储 double float

LongStream

  • 存储 long