Stream
可以看做是遍历数据集的高级迭代器。
先定义一个DISH类,任务是要求返回低热量的菜的名称。(卡路里<400)
package lambdasinaction.chap4;
import java.util.*;
public class Dish {
private final String name;
private final boolean vegetarian;
private final int calories;
private final Type type;
public Dish(String name, boolean vegetarian, int calories, Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Type getType() {
return type;
}
public enum Type { MEAT, FISH, OTHER }
@Override
public String toString() {
return name;
}
public static final List<Dish> menu =
Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 400, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH));
}
这是不用流的写法
public static void main(String [] args) throws Exception{
List<Dish> dishList = new ArrayList<Dish>();
for(Dish dish:menu){
if(dish.getCalories()<400){
dishList.add(dish);
}
}
Collections.sort(dishList, new Comparator<Dish>() {
@Override
public int compare(Dish dish1, Dish dish2) {
return Integer.compare(dish1.getCalories(),dish2.getCalories());
}
});
List<String> result = new ArrayList<String>();
for(Dish dish:dishList){
result.add(dish.getName());
}
System.out.println(result);
}
如果使用流的话,上述代码实际上在完成四个步骤:
1.过滤(选出cal<500)
2.排序
3.得到菜名
4.转换成list
List<String> lowCalResult = menu.parallelStream()
.filter(t->t.getCalories()<500)
.sorted(Comparator.comparing(Dish::getCalories))//sort by cal
.map(Dish::getName)
.collect(Collectors.toList());
System.out.println(lowCalResult);
//按照种类分别把菜名分到不同的list
Map<Dish.Type,List<Dish>> dishedByType =
menu.stream().collect(groupingBy(Dish::getType));
stream一些特点
只能遍历一次:
当遍历到第二次的时候:
Exception in thread “main” java.lang.IllegalStateException: stream has already been operated upon or closed
会抛出异常。
外部迭代与内部迭代
集合遍历是属于外部迭代,相当于把迭代的过程暴露给用户,而内部迭代已经封装好了。(collect方法)
流操作
关闭流的操作(eg:collect)叫做终端操作。
中间的操作看似是独立的,但实际上可以合并起来。
List<String> lowCalResult = menu.parallelStream()
.filter(t->{
System.out.println("filtering: "+t.getName());
return t.getCalories()>300; })
.map(d->{
System.out.println("mapping: "+d.getName());
return d.getName();
})
.limit(3)
.collect(Collectors.toList());
System.out.println(lowCalResult);
result:
filtering: chicken
filtering: rice
filtering: french fries
mapping: chicken
mapping: rice
mapping: french fries
filtering: pork
mapping: pork
filtering: pizza
filtering: prawns
filtering: salmon
mapping: prawns
filtering: season fruit
mapping: pizza
filtering: beef
mapping: salmon
mapping: beef
[pork, beef, chicken]
StreamAPI 的操作
流的用法
用谓词筛选
List<String> vege = menu.parallelStream()
.filter(Dish::isVegetarian)
.map(Dish::getName)
.collect(Collectors.toList());
System.out.println(vege);
distinct
List<Integer> nums = Arrays.asList(1,2,2,4,5,4,2,2);
nums.stream().filter(i->i%2==0).distinct().forEach(System.out::println);
截短流
limit(n) 选出前n个
skip(n) 省略前n个
map
例如想返回每个菜名的长度
menu.stream().map(Dish::getName).map(String::length).forEach(System.out::println);
flatMap
扁平流,把一个流中的每一个数值转换成另外一个流,然后把所有的流链接成为一个流。
List<String> wordList = Arrays.asList("hello","world","byr");
List<String> unique = wordList.stream()
.map(w->w.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
System.out.println(unique);
flatMap能够把map生成的所有的流汇聚成一条流
查找和匹配
检查谓词是否至少匹配一个元素
anymatch()
检查谓词是否匹配所有元素
allmatch()
确保没有元素与给定谓词匹配
noneMatch()
随便返回一个
findany()
会返回一个Optional,这是一个容器类,可以避免抛出null,因为findany可能会什么也找不到,返回一个Null
reduce 操作
遍历整个流然后返回一个值
List<Integer> nums = Arrays.asList(1,5,3,5,2,4);
int product = nums.stream().reduce(0,(a,b)->(a+b));
int product2 = nums.stream().reduce(0,Integer::sum);
Optional<Integer> product3 = nums.stream().reduce(Integer::sum);
System.out.println(product);
System.out.println(product2);
System.out.println(product3);
归约可以拿来求最大最小
Optional<Integer> max = nums.stream().reduce(Integer::max);
Optional<Integer> min = nums.stream().reduce(Integer::min);
map&reduce
用mapReduce来求和
//统计流当中有多少菜
int count = menu.stream()
.map(d->1)
.reduce(0,(a,b)->a+b);
数值流
Stream没有提供sum接口,但Java8引入了原始类型流特化,即IntStream,DoubleStream,LongStream,这些接口都有sum方法
1.映射到数值流
int calories = menu.stream()
.mapToInt(Dish::getCalories)
.sum();
System.out.println(calories);
2.转换为对象流
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer>stream = intStream.boxed();
3.OptionalInt
mapToInt(可能处理的是空的流),默认返回0
数值范围
IntStream evenNums = IntStream.rangeClosed(1,100)
.filter(t->t%2==0);
evenNums.forEach(System.out::println);
exam:构建一个三元数流
boxed方法可以显式地把特化的流转换回对象流
mapToObj(map方法同时转换回对象流)
Stream<double[]> pythgoreanTriples =
IntStream.rangeClosed(1,100).boxed()//change back to object stream
.flatMap(a->
IntStream.rangeClosed(a,100)
.mapToObj(b->new double[]{a,b,Math.sqrt(a*a+b*b)})
.filter(t->t[2]%1==0));//change back to object stream
pythgoreanTriples.limit(10)
.forEach(t->System.out.println(t[0]+" "+t[1]+" "+t[2]));
由文件生成流
long uniqueWords = 0;
try{
Stream<String> lines = Files.lines(Paths.get("/home/graviti/下载/Java8InAction-master/src/main/resources/lambdasinaction/chap3/data.txt"), Charset.defaultCharset());
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
.distinct()
.count();
System.out.println(uniqueWords);
}catch (Exception e){
e.printStackTrace();
}
创建无限流
Stream.iterate
生成fibonachii 流
Stream.iterate(new int []{0,1},t->(new int[]{t[1],t[0]+t[1]}))
.limit(20)
.map(t->t[0])
.forEach(System.out::println);