这是我参与更文挑战的第3天,活动详情查看: 更文挑战
微博上看到的一个关于javascript
的集合操作函数解释,很有意思。
[■,■,■,■].map(■→●) => [●,●,●,●]
[■,●,■,▲].filter(■→true) => [■,■]
[■,●,■,▲].find(●→true) => ●
[■,●,■,▲].findIndex(●→true) => 1
[■,●,■,▲].fill(●) => [●,●,●,●]
[■,●,■,▲].some(●→true) => true
[■,●,■,▲].every(●→true) => false
Stream的操作分为中间操作与终止操作。
每个中间操作都通过某种方式对Stream进行转换(映射,过滤等等),将一个Stream转换成另一个Stream,其元素类型可能相同,也可能不同。
终止操作会在最后一个中间操作产生的Stream上执行一个最终计算,如打印,保存到集合中,或返回某个元素。
Stream流管道操作通常是lazy的,直到调用终止操作时才会开始计算,对于完成终止操作不需要的数据元素,将永远都不会被计算。这使得无限Stream成为可能。
无限Stream的一个样例:
/**
* 无限Stream。
* 该方法返回无限素数Stream
* @return
*/
static Stream<BigInteger> primes() {
return Stream.iterate(BigInteger.ONE.add(BigInteger.ONE), BigInteger::nextProbablePrime);
}
/**
* 打印出前20个素数
*/
primes().limit(20).forEach(System.out::println);
【Effective Java】[第三版]第45条,谨慎使用Stream,滥用Stream会使程序代码难以读懂和维护。
简单来说,阅读你代码的人是否习惯使用Stream。 你在流中使用的方法名称是否很好的表达了其你的意图。 用Stream的地方都可以用迭代来实现。
Stream支持对象引用和int,long与double。不支持char。最好避免利用Stream来处理char。
/**
* Effective Java 3nd 例子(P174)
**/
"Hello World".chars().forEach(System.out::print);
//output: 721011081081113287111114108100
Stream适合以下工作:
- 统一转换元素的序列
- 过滤元素的序列
- 利用单个操作(如添加、连接或者计算其最小值)合并元素的顺序
- 将元素的序列存放到一个集合中,比如根据某些公共属性进行分组
- 搜索满足某些条件的元素的序列
类似文章开头的JavaScript,我们列举一下Stream中的一些操作:
// java stream
[■,●,■,▲].distinct() => [■,●,▲]
[■,●,■,▲].skip(2) => [■,▲]
[■,●,■,▲].limit(2) => [■,●]
[■,●,■,▲].count() => 4
[■,●,■,▲].findFirst().orElse(null).get() => ■
[■,■,■,■].map(■→●) => [●,●,●,●]
[[■, ■], [■, ■]].flatMap([■, ■] -> stream([■, ■])) => [■, ■, ■, ■]
[■,■,■,■].forEach(■→●) => [●,●,●,●]
[■,●,■,▲].filter(■→true) => [■,■]
[4,5,2,1].sorted() => [1,2,4,5]
[■,●,■,▲].filter(■→true) => [■,■]
[■,●,■,▲].collect(groupingBy(type)) => [[■,■], [●], [▲]]
[.......].collect(Collectors.toList())
// 各种聚合操作, 具体查看Collectors
// 是否有元素,而非随机找元素
[■,●,■,▲].findAny().orElse(null).get() => ■
// 欢迎补充
不管是lambda,还是Stream,都是为了让代码更加易读。代码最终还是写给人看的。
6月4日代码补充如下
// 辅助初始化
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
String[] array = new String[] {"a", "b", "c"};
/**
* Stream初始化
*/
// 空流
Stream<String> emptyStream = Stream.empty(); // []
// Collection(List等), Array(数组)转为Stream
Stream<String> listToStream = list.stream(); // [a, b]
Stream<String> arrayToStream = Stream.of(array); // [a, b, c]
Stream<String> arrayToStream2 = Stream.of("a", "b", "c"); // [a, b, c]
// 取数组的一部分,[1, 3)
Stream<String> arrayToStream3 = Arrays.stream(array, 1, 3); // [b, c]
// builder()创建
Stream<String> streamBuilder = Stream.<String>builder().add("a").add("b").add("c").build(); // [a, b, c]
// generate(func),无限顺序无序流,使用时需要指定长度,否则会一直生成知道占满内存
Stream<String> streamGenrated = Stream.<String>generate(() -> {
Random random = new Random();
return "" + random.nextInt(100);
}).limit(10); // [45, 44, 51, 60, 62, 3, 57, 48, 80, 27]
// iterate(Element(1), Element(n) -> Element(n+1))), 有序无限连续流,指定第一元素与生成后续元素的方法
Stream<String> streamIterate = Stream.<String>iterate("a", e -> {
return (char) (e.charAt(e.length()-1) + 1) + "";
}).limit(26); // [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
// int,long,double有各自的封装良好的流IntStream, LongStream, DoubleStream
IntStream intStream = IntStream.rangeClosed(1, 10);// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
LongStream longStream = LongStream.range(1, 5); // [1, 2, 3, 4]
Random random = new Random();
DoubleStream doubleStream = random.doubles(3); // [0.8078472890889652, 0.33210715318105766, 0.9277914692743904]
DoubleStream doubleStream2 = DoubleStream.iterate(1l, n -> n + 1l).limit(10); //[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
System.out.println(emptyStream.collect(Collectors.toList()));
System.out.println(listToStream.collect(Collectors.toList()));
// Stream无法复用,下面一行代码会报错:java.lang.IllegalStateException: stream has already been operated upon or closed
// System.out.println(listToStream.collect(Collectors.toList()));
System.out.println(arrayToStream.collect(Collectors.toList()));
System.out.println(arrayToStream2.collect(Collectors.toList()));
System.out.println(arrayToStream3.collect(Collectors.toList()));
System.out.println(streamBuilder.collect(Collectors.toList()));
System.out.println(streamGenrated.collect(Collectors.toList()));
System.out.println(streamIterate.collect(Collectors.toList()));
System.out.println(intStream.boxed().collect(Collectors.toList()));
System.out.println(longStream.boxed().collect(Collectors.toList()));
System.out.println(doubleStream.boxed().collect(Collectors.toList()));
System.out.println(doubleStream2.boxed().collect(Collectors.toList()));