筛选和切片
用谓词筛选-filter
1
2
3
|
menu.stream()
.filter(Dish::isVegetarian)
.collect(Collectors.toList());
|
取重-distinct
1
2
3
4
5
|
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(integer -> integer % 2 == 0)
.distinct()
.forEach(System.out:: println);
|
截短流-limit
1
2
3
|
menu.stream().filter(dish -> dish.getCalories() > 300)
.limit(3)
.forEach(System.out:: println);
|
跳过元素-skip
1
2
3
|
menu.stream().filter(dish -> dish.getCalories() > 300)
.skip(2)
.forEach(System.out:: println);
|
映射
map
获取菜单中菜名的length。
1
2
3
4
|
menu.stream()
.map(Dish::getName)
.map(String::length)
.forEach(System.out:: println);
|
flatMap
拆分单词字母并取重。
1
2
3
4
5
6
7
8
9
10
|
List<String> words = Arrays.asList("Hello", "World");
// ❌错误,返回2个字符串数组
words.stream().map(word -> word.split("")).distinct()
.forEach(System.out::println);
// ❌错误,返回2个java.util.stream.ReferencePipeline$Head类型数组
words.stream().map(word -> word.split("")).map(Arrays::stream)
.distinct().forEach(System.out::println);
// ✅ 正确做法
words.stream().map(word -> word.split("")).flatMap(Arrays::stream)
.distinct().forEach(System.out::println);
|
查找匹配
匹配
至少匹配一个-anyMatch
1
2
3
|
if (menu.stream().anyMatch(Dish::isVegetarian)){
System.out.println("This menu is (somewhat) vegetarian friendly");
}
|
全部匹配-allMatch
1
2
3
|
if (menu.stream().allMatch(dish -> dish.getCalories() < 1000)) {
System.out.println("This menu is healthy");
}
|
全不匹配-noneMatch
1
2
3
|
if (menu.stream().noneMatch(dish -> dish.getCalories() >= 1000)) {
System.out.println("This menu is healthy");
}
|
anyMatch
,allMatch
,noneMatch
都用到了短路求值。
查找
查找返回当前流中任意元素-findAny
1
2
3
|
menu.stream().filter(Dish::isVegetarian)
.findAny()
.ifPresent(d -> System.out.println(d.getName()));
|
Optional类( java.util.Optional)是一个容器类,代表一个值存在或不存在。findAny
返回Optional类型。Optional几个常用方法:
- isPresent() 将在Optional包含值的时候返回true, 否则返回false。
- ifPresent( Consumer< T> block)会在值存在的时候执行给定的代码块。
- T get() 会在值存在时返回值,否则抛出一个NoSuchElement异常。
- T orElse( T other)会在值存在时返回值,否则返回一个默认值。
查找第一个元素-findFirst
1
2
3
|
// n的平方后能被3整除的第一个元素
numbers.stream().map(n -> n * n).filter(n -> n % 3 ==0).findFirst()
.ifPresent(System.out:: println);
|
归约-reduce
元素求和
1
2
3
4
|
//Lambda
numbers.stream().reduce(0, (a, b) -> a + b);
//方法引用
numbers.stream().reduce(Integer::sum).get()
|
最大值、最小值
1
2
|
numbers.stream().reduce(Integer::max).get()
numbers.stream().reduce(Integer::min).get()
|
流的状态,无状态和有状态
无状态
如map
或filter
等操作会从输入流中获取每一个元素,并在输出流中得到 0 或 1 个结果。 这些操作一般都是没有内部状态的。
有状态
如reduce
、sum
、max
等操作需要内部状态来累积结果。
流常用操作
操作 |
类型 |
返回类型 |
使用的类型/函数接口 |
函数描述符号 |
filter |
中间 |
Stream |
Predicate |
T -> boolean |
distinct |
中间(有状态-无界) |
Stream |
|
|
skip |
中间(有状态-有界) |
Stream |
long |
|
limit |
中间(有状态-有界) |
Stream |
long |
|
map |
中间 |
Stream |
Function |
T -> R |
flatMap |
中间 |
Stream |
Function> |
T -> Stream |
sorted |
中间(有状态-无界) |
Stream |
Comparator |
(T, T) -> int |
anyMatch |
终端 |
boolean |
Predicate |
T -> boolean |
noneMatch |
终端 |
boolean |
Predicate |
T -> boolean |
allMatch |
终端 |
boolean |
Predicate |
T -> boolean |
findAny |
终端 |
Optional |
|
|
findFirst |
终端 |
Optional |
|
|
forEach |
终端 |
void |
Consumer |
T -> void |
collect |
终端 |
R |
Collector |
|
reduce |
中间(有状态-有界) |
Optional |
BinaryOperator |
(T, T) -> T |
count |
终端 |
long |
|
|
数值流
原始类型特化流IntStream
,LongStream
,DoubleStream
映射对象到值流mapToInt
,mapToLong
,mapToDouble
1
2
3
4
|
menu.stream().mapToInt(Dish::getCalories).sum();
menu.stream().mapToInt(Dish::getCalories).max();
menu.stream().mapToInt(Dish::getCalories).min();
menu.stream().mapToInt(Dish::getCalories).average();
|
转换回对象流boxed()
1
2
|
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();
|
Optional类型OptionalInt
,OptionalLong
,OptionalDouble
1
2
|
OptionalInt maxCalories = menu.stream().mapToInt(Dish::getCalories).max();
int max = maxCalories.orElse(1);
|
数值范围
IntStream
和LongStream
分别提供了静态方法range
和rangeClosed
1
2
|
// 1到100之内的偶数
IntStream evenNumbers = IntStream.rangeClosed(1, 100).filter(i -> i % 2 == 0);
|
示例,计算1~100到勾股数,如(3, 4, 5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100)
.filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)
.mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a * a + b * b)}))
.limit(5)
.forEach(arr -> System.out.println(
"(" + arr[0] + ","
+ arr[1] + ","
+ arr[2] + ")"
)
);
// better
IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100)
.mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)})
.filter(arr -> arr[2] % 1 == 0))
.limit(5)
.forEach(arr -> System.out.println(
"(" + arr[0] + ","
+ arr[1] + ","
+ arr[2] + ")"
)
);
|
构建流
由值创建流
1
2
3
4
|
//Stream.of
Stream<String> stringStream = Stream.of("Java 8", "Lambda", "In", "Action");
//创建空流
Stream<String> emptyStream = Stream.empty();
|
由数组创建流
1
2
3
|
//Arrays.stream
int[] intArrs = {1, 2, 3, 4};
System.out.println(Arrays.stream(intArrs).sum());
|
由文件生成流
1
2
3
4
5
6
7
8
9
10
11
|
long wordCount = 0;
try(Stream<String> lines = Files.lines(Paths.get("data.txt"),
Charset.defaultCharset())) {
wordCount = lines.flatMap(line -> Arrays.stream(line.split(" ")))
//.map(w -> new String[]{w, })
.distinct().count();
System.out.println(wordCount);
} catch (IOException e) {
e.printStackTrace();
} |
由函数生成流-无限流Stream.iterate
,Stream.generate
迭代Stream.iterate
1
2
3
4
5
6
7
|
// 输出:0, 2, 4
Stream.iterate(0, n -> n + 2).limit(3).forEach(System.out:: println);
// 斐波纳契序列
Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]})
.limit(10)
.map(t -> t[0])
.forEach(System.out:: println);
|
生成Stream.generate
1
2
|
// 0~1直接的随机数
Stream.generate(Math::random).limit(5).forEach(System.out:: println);
|
自定义Supplier
实现斐波纳契序列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
IntSupplier fib = new IntSupplier() {
private int previous = 0;
private int current = 1;
@Override
public int getAsInt() {
int oldPrevious = previous;
int nextValue = previous + current;
previous = current;
current = nextValue;
return oldPrevious;
}
};
IntStream.generate(fib).limit(5).forEach(System.out:: println);
|
本文为学习记录,因能力有限,如有错误请赐教……如需转载,请注明出处!