标签:integer 终端 需要 项目 去重 实体 算法 类型 复合
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
流看作在时间中分布的一组值。相反,集合则是空间(这里就是计算机内存)中分布的一组值,在一个时间点上全体存在——你可以使用迭代器来访问for-each循环中的内部成员。
List<Dish> lowCaloricDishes = new ArrayList<>(); for(Dish d: menu){ if(d.getCalories() < 400){ lowCaloricDishes.add(d); } } Collections.sort(lowCaloricDishes, new Comparator<Dish>() { public int compare(Dish d1, Dish d2){ return Integer.compare(d1.getCalories(), d2.getCalories()); } }); List<String> lowCaloricDishesName = new ArrayList<>(); for(Dish d: lowCaloricDishes){ lowCaloricDishesName.add(d.getName()); }
import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; List<String> lowCaloricDishesName = menu.stream() .filter(d -> d.getCalories() < 400) .sorted(comparing(Dish::getCalories)) .map(Dish::getName) .collect(toList());
简单说,对 Stream 的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果,或者导致一个副作用(side effect)。例如:
List<String> name = menu.stream() .filter(dish -> dish.getCalories() > 300) .map(Dish::getName) .limit(3) .collect(Collectors.toList());
接下来,我们将开始学习Stream中的Api 使用技巧,接下来将会使用到实体类 -Dish,以及链表:
实体类:Dish
public class Dish { private String name; private boolean vegetarian; private int calories; private Type type; public enum Type {MEAT, FISH, OTHER} 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 void setName(String name) { this.name = name; } public boolean isVegetarian() { return vegetarian; } public void setVegetarian(boolean vegetarian) { this.vegetarian = vegetarian; } public int getCalories() { return calories; } public void setCalories(int calories) { this.calories = calories; } public Type getType() { return type; } public void setType(Type type) { this.type = type; } }
使用链表:
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));
该操作会接受一个谓词(一个返回boolean的函数)作为参数,并返回一个包括所有符合谓词的元素的流。
示例代码:
List<Dish> vegatarianMenu = menu.stream() .filter(Dish::isVegetarian) .collect(Collectors.toList());
流还支持一个叫作distinct的方法,它会返回一个元素各异(根据流所生成元素的 hashCode和equals方法实现)的流
示例代码:
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream() .filter(integer -> integer % 2 == 0) .distinct() .forEach(System.out::println);
输出结果为:2,4(去重一个 2)
流支持limit(n)方法,该方法会返回一个不超过给定长度的流。所需的长度作为参数传递 给limit
List<Dish> vegatarianMenu = menu.stream() .filter(Dish::isVegetarian) .limit(3) .collect(Collectors.toList());
流还支持skip(n)方法,返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流
List<Dish> vegatarianMenu = menu.stream() .filter(Dish::isVegetarian) .skip(2) .collect(Collectors.toList());
流支持map方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”
List<String> dishNames = menu.stream()
.map(Dish::getName)
.collect(Collectors.toList());
对于一张单词表, 如何返回一张列表, 列出里面各不相同的字符呢? 例如, 给定单词列表["Hello","World"],你想要返回列表["H","e","l", "o","W","r","d"]
List<String> uniqueCharacters = words.stream() .map(w -> w.split("")) .flatMap(Arrays::stream) .distinct() .collect(Collectors.toList());
anyMatch方法可以回答“流中是否有一个元素能匹配给定的谓词”。返回结果为boolean数据类型,如果流中出现匹配项,返回True。
if (list.stream().anyMatch(Dish::isVegetarian)){ System.out.printf("The menu is (somewhat) vegetarian friendly!!"); }
AllMatch 用法和AnyMatch 相似,方法返回结果为“流中所有结果都符合判断规则”。
boolean flag = list.stream().allMatch(dish -> dish.getCalories() <1000);
NoneMatch 与 AllMatch 恰恰相反,返回结果为“流中所有结果都不符合”。
boolean flag = list.stream().allMatch(dish -> dish.getCalories() <1000);
findAny方法将返回当前流中的任意元素。它可以与其他流操作结合使用。方法返回结果为 Optional<T>。
list.stream()
.filter(Dish::isVegetarian)
.findAny()
.ifPresent(d -> System.out.println(d.getName()));
有些流有一个出现顺序(encounterorder)来指定流中项目出现的逻辑顺序(比如由List或排序好的数据列生成的流)。对于这种流,你可能想要找到第一个元素。为此有一个finFirst 方法,它的工作方式类似于findany。
someNumbers.stream() .map(x -> x * x) .filter(x -> x % 3 == 0) .findFirst() .ifPresent(System.out::println);
你可能会想,为什么会同时有findFirst和findAny呢?答案是并行。找到第一个元素 在并行上限制更多。如果你不关心返回的元素是哪个,请使用findAny,因为它在使用并行流 时限制较少。
需要将流中所有元素反复结合起来,得到一个值,比如一个Integer。这样的查询可以被归类为约操作 (将流归约成一个值)。
//Type 1 int result = list.stream() .reduce(0, Integer::sum); System.out.println(result); //Type 2 list.stream() .reduce(Integer::sum) .ifPresent(System.out::println);
//Max list.stream() .reduce(Integer::max) .ifPresent(System.out::println); //Min list.stream() .reduce(Integer::min) .ifPresent(System.out::println);
github 地址:https://github.com/jaycekon/StreamDemo
标签:integer 终端 需要 项目 去重 实体 算法 类型 复合
原文地址:http://www.cnblogs.com/jaycekon/p/7467026.html