• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

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

java8 来源:追风少年Walker 1次浏览



过滤出素食
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);




版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)