使用for 循环计算来自伦敦的艺术家人数
int count = 0;
for (Artist artist : allArtists) {
if (artist.isFrom("London")) {
count++;
}
}
使用Iterator迭代
int count = 0;
Iterator iterator = allArtists.iterator();
while(iterator.hasNext()) {
Artist artist = iterator.next();
if (artist.isFrom("London")) {
count++;
}
}
2.使用stream内部迭代
long count = allArtists.stream()
.filter(artist -> artist.isFrom("London"))
.count();
每种操作都对应Stream 接口的一个方法。为了找出来自伦敦的艺术家,需要对Stream 对象进行过滤:filter。过滤在这里是指“只保留通过某项测试的对象”。测试由一个函数完成,根据艺术家是否来自伦敦,该函数返回true 或者false。由于Stream API 的函数式编程风格,我们并没有改变集合的内容,而是描述出Stream 里的内容。count() 方法计算给定Stream 里包含多少个对象。
只过滤,不计数
allArtists.stream()
.filter(artist -> artist.isFrom("London"));
这行代码并未做什么实际性的工作,filter 只刻画出了Stream,但没有产生新的集合。像filter 这样只描述Stream,最终不产生新集合的方法叫作惰性求值方法;而像count 这样最终会从Stream 产生值的方法叫作及早求值方法。
由于使用了惰性求值,没有输出艺术家的名字:
allArtists.stream()
.filter(artist -> {
System.out.println(artist.getName());
return artist.isFrom("London");
});
如果将同样的输出语句加入一个拥有终止操作的流,如例3-3 中的计数操作,艺术家的名字就会被输出
long count = allArtists.stream()
.filter(artist -> {
System.out.println(artist.getName());
return artist.isFrom("London");
})
.count();
判断一个操作是惰性求值还是及早求值很简单:只需看它的返回值。
如果返回值是Stream,那么是惰性求值;
如果返回值是另一个值或为空,那么就是及早求值。
collect(toList()) 方法由Stream 里的值生成一个列表,是一个及早求值操作。
@Test
public void testCollect() throws Exception {
//Stream 的of 方法使用一组初始值生成新的Stream
List collected = Stream.of("a", "b", "c").collect(Collectors.toList());
Assert.assertEquals(Arrays.asList("a", "b", "c"), collected);
}
如果有一个函数可以将一种类型的值转换成另外一种类型,map 操作就可以使用该函数,将一个流中的值转换成一个新的流。
@Test
public void testMap() throws Exception {
//小写转大写
List<String> upperWords = new ArrayList<>();
//for循环实现
for (String s : Arrays.asList("a", "b", "c")) {
upperWords.add(s.toUpperCase());
}
Assert.assertEquals(Arrays.asList("A", "B", "C"), upperWords);
//lambda实现
upperWords = Stream.of("a", "b", "c")
.map(string -> string.toUpperCase())
.collect(Collectors.toList());
Assert.assertEquals(Arrays.asList("A", "B", "C"), upperWords);
}
遍历数据并检查其中的元素时,可尝试使用Stream 中提供的新方法filter
@Test
public void testFilter() throws Exception {
//判断是否以数字开头
List<String> beginWithNumber = new ArrayList<>();
//for循环实现
for (String s : Arrays.asList("1aa", "2bb", "cccc")) {
if (isDigit(s.charAt(0))) {
beginWithNumber.add(s);
}
}
Assert.assertEquals(Arrays.asList("1aa", "2bb"), beginWithNumber);
//lambda实现
beginWithNumber = Stream.of("1aa", "2bb", "cccc")
.filter(string -> isDigit(string.charAt(0)))
.collect(Collectors.toList());
Assert.assertEquals(Arrays.asList("1aa", "2bb"), beginWithNumber);
}
flatMap 方法可用Stream 替换值, 然后将多个Stream 连接成一个Stream
@Test
public void testFlatMap() throws Exception {
List collect = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6))
.flatMap(numbers -> numbers.stream())
.collect(Collectors.toList());
Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6), collect);
}
求最大值和最小值
@Test
public void testMaxAndMin() throws Exception {
List
可以实现从一组值中生成一个值
@Test
public void testReduce() throws Exception {
int sum = Stream.of(1, 2, 3, 4)
.reduce(0, (a, b) -> a + b);//0是初始值
Assert.assertEquals(10, sum);
int multi = Stream.of(10, 20, 30)
.reduce(1, (a, b) -> a * b);
Assert.assertEquals(6000, multi);
//将reduce 操作展开
BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;
int count = accumulator.apply(
accumulator.apply(
accumulator.apply(0, 1),
2),
3);
}
高阶函数是指接受另外一个函数作为参数,或返回一个函数的函数。
高阶函数不难辨认:看函数签名就够了。
如果函数的参数列表里包含函数接口,或该函数返回一个函数接口,那么该函数就是高阶函数。
内部迭代将更多控制权交给了集合类。
和 Iterator 类似,Stream 是一种内部迭代方式。
将 Lambda表达式和 Stream 上的方法结合起来,可以完成很多常见的集合操作。