java8新特性(四):Stream流的使用


过滤出素食
List<Dish> vegetarian = menu.stream().filter(Dish::isVegetarian).collect(Collectors.toList());




过滤出偶数,并且不重复的元素。
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println);



截断流
List<Dish> dishes = menu.stream()
.filter(d -> d.getCalories() > 300)
.limit(3)
.collect(toList());


跳过元素
List<Dish> dishes = menu.stream()
.filter(d -> d.getCalories() > 300)
.skip(2)
.collect(toList());


映射

List<String> dishNames = menu.stream()
.map(Dish::getName)
.collect(toList());



List<String> words = Arrays.asList("Java8", "Lambdas", "In", "Action");
List<Integer> wordLengths = words.stream()
                                                                 .map(String::length)
                                                                 .collect(toList());


展开流

List<String> uniqueCharacters = words.stream().map(w -> w.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());




查找和匹配

任意匹配
if(menu.stream().anyMatch(Dish::isVegetarian)){
          System.out.println("The menu is (somewhat) vegetarian friendly!!");
}

全部匹配
boolean isHealthy = menu.stream().allMatch(d -> d.getCalories() < 1000);


全部不匹配
boolean isHealthy = menu.stream().noneMatch(d -> d.getCalories() >= 1000);


获取任意一个元素
Optional<Dish> dish =menu.stream() .filter(Dish::isVegetarian) .findAny();


归约
将一个流中的元素反复结合运算得到一个值。

使用循环求和
List<Integer> numbers = new ArrayList<>();
int sum1 = 0;
for(int x: numbers){
    sum1 += x;
}

使用流的API求和
int sum2 = numbers.stream().reduce(0, (a,b) -> a + b);


求最大值
Optional<Integer> max = numbers.stream().reduce(Integer::max);

求最小值
Optional<Integer> min = numbers.stream().reduce(Integer::min);

使用reduce相对于使用逐步迭代的好处在于,外部迭代改成了内部迭代,在需要实现并行执行的操时作变得简单。

有状态操作和无状态操作
比如map或者filter会从输入流中获取每一个元素,并且在输出流中得到一个结果,这些操作没有内部状态,称为无状态操作
但是像reduce、sum、max这些操作都需要内部状态来累计计算结果,所以称为有状态操作
还有一些操作sort、distinct,看上去和filter、map差不多,他们接收一个流,再生成一个流,但是区别在于排序和去重复项需要知道先前的历史。比如排序就需要将所有元素放入缓存区后才能给输出流加入一个项目,这个操作对缓存的要求是无上限的,流有多大就需要多大的缓存才能进行运算。这些操作也是有状态操作

中间操作和终端操作
 操作类型返回值使用的函数接口或者类型
filter
中间操作
Stream<T>
Predicate<T>
distinct
中间操作,有状态,无边界Stream<T>
skip
中间操作,有状态,有边界Stream<T>
long
limit
中间操作,有状态,有边界Stream<T>
long
map
中间操作
Stream<R>
Function<T, R>

flatMap
中间操作
Stream<R>
Function<T, Stream<R>>
sorted
中间操作,有状态,无边界
Stream<T>
Comparator<T>
anyMatch
终端操作
boolean
Predicate<T>
noneMatch
终端操作
boolean
Predicate<T>
allMatch
终端操作
boolean
Predicate<T>
findAny
终端操作
Optional<T>


findFirst
终端操作Optional<T>
forEach
终端操作
void
Consumer<T>
collect
终端操作R
Collector<T, A, R>
reduce
终端操作,有状态,有边界
Optional<T>
BinaryOperator<T>
count
终端操作
long

中间操作就像是水管的一部分,终端操作就像水龙头,增加水管长度不会消耗水,只有打开水龙头才会开始消耗水。

Java5的时候就引入了自动装箱拆箱的功能, 在对包装类型进行数学计算的时候,包装类型就会被自动拆箱成基本类型, 而将一个基本类型的值赋值给一个包装类型的变量或者放入集合中时基本类型又会被自动装箱成包装类型,这个过程是需要消耗计算性能的。Java8的包装类型的流的计算过程中同样包含了对基本类型的自动装箱和拆箱的过程,所以Java8又引入了三个原始类型的流用来解决这个问题。(IntStream, DoubleStream和LongStream), 分别对应基本类型int, double, long,从而避免了自动装箱和拆箱的性能消耗。
基本类型的使用:
Stream的求和: int sum3 = menu.stream().map(Dish::getColories).reduce(0, Integer::sum);
使用IntStream的求和: int sum4 = menu.stream().mapToInt(Dish::getColories).sum();

创建一个流

1, 使用range方法给定一个范围来创建一个基本类型的流。
IntStream intStream = IntStream.range(1,100);

2,直接给值来创建流
Stream<String> stream = Stream.of("walker","sun","is","the","best");

3,由数组创建流
IntStream stream2 = Arrays.stream(numbers2);


4, 由文件生成流
try {
    Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
catch (IOException e) {
    e.printStackTrace();
}

5,由函数生成流
迭代: Stream.iterate(0, n -> n + 2).limit(10) .forEach(System.out::println);

生成:Stream.generate(Math::random).limit(5) .forEach(System.out::println);


  • 17
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值