第五章(5)数值流 (去装箱化)

      我们之前学了规约reduce,那么统计所有菜的总热量应该这么做:

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, 300, Dish.Type.FISH), 
				   new Dish("salmon", false, 450, Dish.Type.FISH) );
		
		int count = menu.parallelStream().map(Dish::getCalories).reduce(0, Integer::sum);
		System.out.println(count);

这段代码虽然可以得到正确的结果,但是他还是存在着问题,那就是Integer的拆箱工作,会多少影响一点效率。

     那么java8为了解决这一问题,专门提供了原始类型流特化:IntStream,DoubleStream,LongStream。分别将流中的元素特化为int、long和double,从而避免了暗含的装箱成本。每个接口都带来了进行常用数值归约的新方法,比如对数值流求和的sum,找到最大元素的max。此外还有在必要时再把它们转换回对象流的方法。要记住的是,这些特化的原因并不在于流的复杂性,而是装箱造成的复杂性——即类似int和Integer之间的效率差异。

1.映射到数值流

    将流转换为特化版本的常用方法是mapToInt、mapToDouble和mapToLong。与map的工作方式是一样的,比如下面我们使用数值流来统计所有菜的热量。

int count = menu.parallelStream().mapToInt(Dish::getCalories).sum();
System.out.println(count);

如果流是空的,那么sum方法默认返回0 

2.转换为对象流(装箱)

有时候,你需要把IntStream或DoubleStream等转换为Stream<Integer>,那该怎么玩呢?

IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();

3.默认值OptionalInt

上面我们举得第一个例子使用sum对数值流求和如果流是空的那么默认返回0,这是没有任何问题的,那么再试想一个情况,我们使用max求最大值得时候,当流是空的的时候,再返回0,那么就不对了,所以如果求诸如最大值最小值的操作的时候,那么返回结果都必须为OptionalInt(或OptionalDouble,OptionalLong):

IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
OptionalInt maxval = intStream.max();
System.out.println(maxval.getAsInt());

现在,如果没有最大值的话,你就可以显式处理OptionalInt去定义一个默认值了:

int max = maxval.orElse(1); //如果没有最大值的话,显式提供一个默认最大值

 

猜你喜欢

转载自blog.csdn.net/qq564425/article/details/81637925