通过 Stream.of() ,我们可以很容易地将一组元素转化成流。
Stream.of("今天", "是", "个", "好日子").forEach(System.out::println);
System.out.println();
Stream.of(23, 29.2, 291.8).forEach(System.out::println);
运行结果:
今天
是
个
好日子
23
29.2
291.8
每种集合都可以通过调用 stream() 方法来产生一个流。 Bruce Eckel 举了这样一个示例:
List bubbles = Arrays.asList(new Bubble(1), new Bubble(2), new Bubble(3));
System.out.println(bubbles.stream().mapToInt(b -> b.i).sum());
System.out.println();
Set set = new HashSet<>(Arrays.asList("It's a wonderful day".split(" ")));
set.stream().map(x -> x + " ").forEach(System.out::println);
System.out.println();
Map map = new HashMap<>();
map.put("pi", 3.14);
map.put("e", 2.71);
map.put("phi", 1.618);
map.entrySet().stream().map(e -> e.getKey() + ": " + e.getValue()).forEach(System.out::println);
运行结果:
6
a
It's
wonderful
day
phi: 1.618
e: 2.71
pi: 3.14
其中 Bubble 的定义是:
public class Bubble {
public final int i;
public Bubble(int i) {
this.i = i;
}
@Override
public String toString() {
return "Bubble(" +
"" + i +
')';
}
private static int count = 0;
public static Bubble bubbler() {
return new Bubble(count++);
}
}
PHI源于斐波那契数列(1-1-2-3-5-8-13-21-……)这个数列之所以非常有名,不仅是因为数列中相邻两项之和等于后一项,而且相邻的两项相除所得的商也约等于1.618。
PHI 还有一点奇妙之处是其比例与其倒数是一样的。1.618的倒数是0.618,而1.618:1与1:0.618计算结果相同。
在自然界,人们发现鹦鹉螺身上每圈罗纹的直径与相邻罗纹直径之比是 PHI。
建筑设计上,雅典城卫城供奉庇护神雅典娜的巴特农神殿,其正立面的长与宽之比为黄金比。
据说,最早发现这个优美比例的是古希腊的毕达哥拉斯学派 . 他们曾不厌其烦地把线段 一段一段地分成不同的两截,反复改变着比例并加以比较,最后才找到了这个 “ 最优雅的比例 ”。
但是把这个比例冠以 “ 黄金 ” 二字的美名则开始于意大利著名科学家 与艺术家达芬奇。 从此,0.618作为黄金比统治着当时欧洲的建筑和艺术,并影响到人们生活的许多方面,一直延续至今。
达芬奇的《蒙娜丽莎》就是严格按照黄金比例进行设计绘制的典范。
在视觉上,黄金分割本质上带来的是和谐(相似、重复、联系),以及变化(运动、活力),通过这两点,带给人以美的享受。
可以利用 Arrays 类中的 stream() 静态方法,把数组转换为流。
Arrays.stream(new double[]{3.14, 2.71, 1.618}).forEach(n -> System.out.format("%f ", n));
System.out.println();
Arrays.stream(new int[]{3, 2, 1}).forEach(n -> System.out.format("%d ", n));
System.out.println();
Arrays.stream(new long[]{13, 12, 11}).forEach(n -> System.out.format("%d ", n));
System.out.println();
Arrays.stream(new int[]{3, 2, 1, 0, -1, -2}, 3, 6).forEach(n -> System.out.format("%d ",
n));
运行结果:
3.140000 2.710000 1.618000
3 2 1
13 12 11
0 -1 -2
最后一个示例展示了如果设定数组范围。Arrays.stream() 方法还定义了两个额外参数。第一个参数是数组起始位置(包含),第一个参数是数组终止位置(不包含)。
IntStream 类提供了 range() 方法用于生成整型序列的流。很适合编写循环:
//传统
int result = 0;
for (int i = 10; i < 20; i++) {
result += i;
}
System.out.println(result);
//for-in 循环
result = 0;
for (int i : range(10, 20).toArray())
result += i;
System.out.println(result);
//使用流
System.out.println(range(10, 20).sum());
运行结果:
145
145
145
第一种方式是传统编写 for 循环的方式;
第二种方式是使用 range() 创建流,接着将其转化为数组,最后在 for-in 代码块中使用;
相对来说,第三种方式最好。使用 range() 创建流之后,对流中的数字进行求和(sum)。
Bruce Eckel 利用 range 与 forEach 方法,实现了一个 for 循环工具类:
public class Repeat {
public static void repeat(int n, Runnable action) {
range(0, n).forEach(i -> action.run());
}
}
public class Looping {
static void hi() {
System.out.println("Hi!");
}
public static void main(String[] args) {
repeat(3, () -> System.out.println("Looping!"));
repeat(2, Looping::hi);
}
}
运行结果:
Looping!
Looping!
Looping!
Hi!
Hi!
Stream.iterate() 以种子(第一个入参)作为起始值,该值会传递给 UnaryOperator(第二个入参)。UnaryOperator 的返回结果会添加到流中,并且会把结果值作为下一次迭代方法的初始入参。
我们可以利用 iterate() 生成一个斐波那契数列。
public class Fibonacci {
int x = 1;
Stream numbers() {
return Stream.iterate(0, i -> {
// System.out.format("i -> %s\n",i);
// System.out.format("x -> %s\n",x);
int result = x + i;
x = i;
// System.out.format("result -> %s\n\n",result);
return result;
});
}
public static void main(String[] args) {
new Fibonacci().numbers()
.skip(20)//丢弃前 20 个
.limit(10)//然后再取 10 个
.forEach(System.out::println);
}
}
运行结果:
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229