Stream 中的方法分为三类:
- 静态方法:用于创建流
- 中间操作:通常是将一种流转换成另一种流
- 终止操作:通常是对流中的元素进行计算,得出一个结果
流是惰性求值的,只有执行终止操作时才会真正执行计算。
创建流
empty
生成一个空的流
public static void empty() {
Stream.empty().forEach(System.out::println);
}
of
生成包含指定元素的串行流
public static void of() {
Stream.of("a").forEach(System.out::println);
Stream.of("a", "b", "c").forEach(System.out::println);
}
a
a
b
c
iterate
生成一个无限的串行流,流的第一个元素是 seed
,之后的元素都是对前一个元素应用函数 f
得到的。形如 seed、f(seed)、f(f(seed)) …
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f);
public static void iterate() {
// 由于是无限的流,所以需要 limit
Stream.iterate(1, (e) -> e * 2)
.limit(10)
.forEach(System.out::println);
}
1
2
4
8
16
32
64
128
256
512
generate
生成一个无限的串行流,流中的元素都是函数 s
提供的。通常用于生成常量流、随机元素流等。
public static<T> Stream<T> generate(Supplier<T> s);
public static void generate() {
// 由于是无限的流,所以需要 limit
Stream.generate(() -> 1)
.limit(5)
.forEach(System.out::println);
System.out.println();
Random random = new Random();
Stream.generate(random::nextInt)
.limit(5)
.forEach(System.out::println);
}
1
1
1
1
1
-1986698800
-1639744933
-172603197
-393447923
1674768852
concat
连接两个流
public static void concat() {
Stream<String> stream1 = Stream.of("a");
Stream<String> stream2 = Stream.of("b", "c");
Stream.concat(stream1, stream2).forEach(System.out::println);
}
a
b
c
builder
使用 Stream.Builder
构建流
public static void builder() {
Stream.Builder<String> builder = Stream.builder();
Stream<String> stream = builder
.add("a")
.add("b")
.add("c")
.build();
stream.forEach(System.out::println);
}
a
b
c
中间操作
filter
过滤元素,只有 predicate
为 true 的元素会进入下游的流
Stream<T> filter(Predicate<? super T> predicate);
public static void filter() {
Stream.of("java", "python", "javascript")
.filter((e) -> e.startsWith("j"))
.forEach(System.out::println);
}
java
javascript
map、mapToInt、mapToLong、mapToDouble
返回一个流,包含给定函数应用于流中每一个元素后的结果。可用于将一种流 T
转换为另一种流 R
,或者只操作元素,不改变流的类型。为了避免频繁自动拆箱、装箱的损耗,提供了针对基本类型的方法 mapToInt、mapToLong、mapToDouble
。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
public static void map() {
Stream<Integer> stream1 = Stream.of("java", "python", "javascript")
.map(String::length);
stream1.forEach(System.out::println);
IntStream intStream = Stream.of("java", "python", "javascript")
.mapToInt(String::length);
intStream.forEach(System.out::println);
}
4
6
10
4
6
10
flatMap、flatMapToInt、flatMapToLong、flatMapToDouble
mapper
函数的返回值是 Stream
。对流中的所有元素应用函数 mapper
,然后将其结果流中的元素放入新的流,然后返回这个新流。多用于处理一对多的关系:对流的元素应用一对多转换,然后将生成的元素平展成一个新的流。同样提供了针对基本类型的方法。
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
假设有订单列表 List<Order> orders
,订单中有商品列表 List<Item> items
,我们可以用以下的方式生成单个 Stream<Item>
并处理商品。
@Data
@AllArgsConstructor
static class Item {
private String name;
public static Item of(String name) {
return new Item(name);
}
}
@Data
@AllArgsConstructor
static class Order {
private List<Item> items;
public static Order of(Item... items) {
return new Order(Arrays.asList(items));
}
}
public static void flatMap() {
Item apple = Item.of("Apple");
Item banana = Item.of("Banana");
Item peach = Item.of("Peach");
Item lemon = Item.of("Lemon");
Order order1 = Order.of(apple, banana);
Order order2 = Order.of(peach, lemon);
List<Order> orders = Arrays.asList(order1, order2);
// 生成单个 Stream<Item>,而不是多个
Stream<Item> itemStream = orders.stream().flatMap(order -> order.getItems().stream());
itemStream.forEach(System.out::println);
}
T1.Item(name=Apple)
T1.Item(name=Banana)
T1.Item(name=Peach)
T1.Item(name=Lemon)
distinct
利用 equals
方法进行去重。
public static void distinct() {
Stream.of("a", "b", "c", "a", "b")
.distinct()
.forEach(System.out::println);
}
a
b
c
sorted
// 以自然序排序,元素必须都实现了接口 Comparable
Stream<T> sorted();
// 以指定的比较器排序
Stream<T> sorted(Comparator<? super T> comparator);
public static void sorted() {
// 自然序
Stream.of("sql", "python", "java")
.sorted()
.forEach(System.out::println);
System.out.println();
// 字符长度
Stream.of("sql", "python", "java")
.sorted(Comparator.comparingInt(String::length))
.forEach(System.out::println);
}
java
python
sql
sql
java
python
peek
对流中的元素应用函数 action
(可以修改元素,也可以只是简单的打印),然后返回当前流,与 map
不同,peek
不会生成新的流。
Stream<T> peek(Consumer<? super T> action);
public static void peek() {
Item apple = Item.of("Apple");
Item banana = Item.of("Banana");
Item peach = Item.of("Peach");
Item lemon = Item.of("Lemon");
Stream.of(apple, banana, peach, lemon)
.filter(e -> e.getName().length() < 6)
// 打印
.peek(System.out::println)
// 修改名称
.peek(e -> e.setName(e.getName() + "__"))
.forEach(System.out::println);
}
T1.Item(name=Apple)
T1.Item(name=Apple__)
T1.Item(name=Peach)
T1.Item(name=Peach__)
T1.Item(name=Lemon)
T1.Item(name=Lemon__)
limit
截取前 N 个元素,丢弃后面的元素。
public static void limit() {
Stream.of("a", "b", "c", "d", "e")
.limit(3)
.forEach(System.out::println);
}
a
b
c
skip
跳过前 N 个元素
public static void skip() {
Stream.of("a", "b", "c", "d", "e")
.skip(3)
.forEach(System.out::println);
}
d
e
终止操作
forEach、forEachOrdered
对于串行流来说,两个方法的行为是一样的。但对于并行流:
- forEach:行为是不确定的,元素可能以任意顺序被操作
- forEachOrdered:元素以添加的顺序被操作,这样牺牲了并行性的好处
public static void forEach() {
// 串行流
Stream.of("a", "b", "c", "d", "e")
.forEach(e -> System.out.print(e + " "));
System.out.println();
Stream.of("a", "b", "c", "d", "e")
.forEachOrdered(e -> System.out.print(e + " "));
System.out.println();
// 并行流
Stream.of("a", "b", "c", "d", "e")
.parallel()
.forEach(e -> System.out.print(e + " "));
System.out.println();
Stream.of("a", "b", "c", "d", "e")
.parallel()
.forEachOrdered(e -> System.out.print(e + " "));
}
下面是两次的运行结果。对于串行流,两个方法的结果是一样的。对于并行流,每次执行 forEach
的结果可能不一样,但执行 forEachOrdered
的结果肯定是一样的。
a b c d e
a b c d e
c d e b a
a b c d e
--------------
a b c d e
a b c d e
c e d b a
a b c d e
toArray
// Object 数组
Object[] toArray();
// 传入一个 new 数组的 generator,参数为数组的 length,且返回值是泛型数组
<A> A[] toArray(IntFunction<A[]> generator);
public static void toArray() {
Object[] objectArray = Stream.of("a", "b", "c").toArray();
String[] stringArray1 = Stream.of("a", "b", "c")
.toArray(length -> {
System.out.println(length);
return new String[length];
});
// 上面可以简化为
String[] stringArray2 = Stream.of("a", "b", "c").toArray(String[]::new);
System.out.println(Arrays.toString(objectArray));
System.out.println(Arrays.toString(stringArray1));
System.out.println(Arrays.toString(stringArray2));
}
3
[a, b, c]
[a, b, c]
[a, b, c]
reduce
// 注意:流中元素的类型为 T
T reduce(T identity, BinaryOperator<T> accumulator);
// 等价于以下代码,但不按顺序操作元素
T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
// 与上面的区别在于没有提供初始值
Optional<T> reduce(BinaryOperator<T> accumulator);
// 等价于以下代码,但不按顺序操作元素
boolean foundAny = false;
T result = null;
for (T element : this stream) {
if (!foundAny) {
foundAny = true;
result = element;
}
else
result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
// 注意:初始值为 U 类型,不是 T 类型
// identity 是初始值
// accumulator 是累加器,用于将元素累加到 result 中
// combiner 是多线程最后合并结果的,比如 toList 就是将两个 List 合并成一个 List 的
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
// 等价于以下代码,但不按顺序操作元素
U result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
实现 sum
public static void reduceSum() {
// 实现 sum
Integer sum1 = Stream.of(1, 2, 3).reduce(0, (a, b) -> a + b);
Integer sum2 = Stream.of(1, 2, 3).reduce(0, Integer::sum);
System.out.println(sum1);
System.out.println(sum2);
}
6
6
实现 max
public static void reduceMax() {
// 实现 max
Optional<Integer> max1 = Stream.of(1, 2, 3).reduce((a, b) -> Integer.max(a, b));
Optional<Integer> max2 = Stream.of(1, 2, 3).reduce(Integer::max);
System.out.println(max1);
System.out.println(max2);
}
Optional[3]
Optional[3]
实现 toList
public static void reduceToList() {
// 实现 toList
List<Integer> result = Stream.of(1, 2, 3)
.reduce(
new ArrayList<>(),
(list, e) -> {list.add(e); return list;},
(list1, list2) -> {list1.addAll(list2); return list1;}
);
System.out.println(result);
}
[1, 2, 3]
collect
Collectors 各个方法的使用,请移步 Collectors 中的各种方法。
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
// 等价于以下代码,
R result = supplier.get();
for (T element : this stream)
accumulator.accept(result, element);
return result;
// Collector 封装了上面的 3 个参数,并提供了其他的参数
<R, A> R collect(Collector<? super T, A, R> collector);
实现 toList
public static void collectToList() {
// 实现 toList
List<Integer> list1 = Stream.of(1, 2, 3)
. collect(
ArrayList::new,
ArrayList::add,
ArrayList::addAll
);
List<Integer> list2 = Stream.of(1, 2, 3)
.collect(Collectors.toList());
System.out.println(list1);
System.out.println(list2);
}
[1, 2, 3]
[1, 2, 3]
min、max
根据传入的比较器,求最大、最小值。流是空的,会返回 Optional.empty()
。
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
public static void min() {
// 自然序
Optional<String> min = Stream.of("sql", "python", "java")
.min(Comparator.comparingInt(String::length));
System.out.println(min);
}
count
public static void count() {
long count = Stream.of("java", "python", "javascript")
.filter((e) -> e.startsWith("j"))
.count();
System.out.println(count);
}
2
anyMatch、allMatch、noneMatch
// 是否有元素符合条件
boolean anyMatch(Predicate<? super T> predicate);
// 是否所有元素都符合条件
boolean allMatch(Predicate<? super T> predicate);
// 是否所有元素都不符合条件
boolean noneMatch(Predicate<? super T> predicate);
private static void match() {
boolean anyMatch = Stream.of(1, 2, 3)
.anyMatch(e -> e > 2);
boolean allMatch = Stream.of(1, 2, 3)
.allMatch(e -> e > 0);
boolean noneMatch = Stream.of(1, 2, 3)
.noneMatch(e -> e > 0);
System.out.println(anyMatch);
System.out.println(allMatch);
System.out.println(noneMatch);
}
true
true
false
findFirst、findAny
- findFirst:无论是串行流还是并行流,始终返回第一个
- findAny:返回任意一个元素。对于并行流,每次的结果可能不一样
private static void find() {
// 串行流
Optional<Integer> first1 = Stream.of(1, 2, 3)
.findFirst();
Optional<Integer> any1 = Stream.of(1, 2, 3)
.findAny();
// 并行流
Optional<Integer> first2 = Stream.of(1, 2, 3)
.parallel()
.findFirst();
Optional<Integer> any2 = Stream.of(1, 2, 3)
.parallel()
.findAny();
System.out.println(first1);
System.out.println(first2);
System.out.println(any1);
System.out.println(any2);
}
一下是两次的执行结果。可以看到并行流两次 findAny
的结果不同。
Optional[1]
Optional[1]
Optional[1]
Optional[1]
Optional[1]
Optional[1]
Optional[1]
Optional[2]