Stream流 | 总字数: 3.9k | 阅读时长: 18分钟 | 浏览量: |
生成流
通过集合生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 List<String> strList = new ArrayList <>(); strList.add("a" ); strList.add("b" ); Stream stream3 = list.stream();Set<String> strSet = new HashSet <>(); strSet.add("a" ); strSet.add("b" ); Stream stream4 = strSet.stream();Map<String,Integer> map = new HashMap <>(); map.put("a" , 100 ); map.put("b" , 200 ); Stream stream5 = map.entrySet().stream();
通过数组生成
1 2 int [] intArr = new int []{1 , 2 , 3 , 4 , 5 };IntStream stream = Arrays.stream(intArr);
该方法生成的流是数值流(IntStream)而不是Stream,使用数值流可以避免计算过程中拆箱装箱,提高性能
通过值生成
1 Stream<Integer> stream = Stream.of(1 , 2 , 3 , 4 , 5 );
通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流
通过文件生成
1 Stream<String> lines = Files.lines(Paths.get("data.txt" ), Charset.defaultCharset());
通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行
通过函数生成
iterate
1 Stream<Integer> stream = Stream.iterate(0 , n -> n + 2 ).limit(5 );
iterate方法接受两个参数,第一个为初始值,第二个为进行的函数操作,因为iterate生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数
generate
1 Stream<Double> stream = Stream.generate(Math::random).limit(5 );
generate方法接受一个参数,方法参数类型为Supplier,由他为流提供值,generate生成的流也是无限流,因此通过limit对流进行了截断
中间操作
filter条件筛选
返回结果生成新的流中只包含满足筛选条件的数据
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 ); Stream<Integer> stream = integerList.stream().filter(i -> i > 3 );
distinct去除重复元素
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 ); Stream<Integer> stream = integerList.stream().distinct();
limit返回指定流个数
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 ); Stream<Integer> stream = integerList.stream().limit(3 );
通过limit方法指定返回流的个数,limit的参数值必须>=0,否则将会抛出异常
skip跳过流中的元素
1 2 List<Integer> integerList = Arrays.asList(1 , 1 , 2 , 3 , 4 , 5 ); Stream<Integer> stream = integerList.stream().skip(2 );
通过skip方法跳过流中的元素,skip的参数值必须>=0,否则将会抛出异常
map流映射
流映射就是将接受的元素映射成另外一个元素,通过map方法可以完成映射
1 2 List<String> stringList = Arrays.asList("Java 8" , "Lambdas" , "In" , "Action" ); Stream<Integer> stream = stringList.stream().map(String::length);
当出现相同的key时,解决方法:取前面value的值,或者取后面放入的value值,则覆盖先前的value值
1 2 3 4 Map<Long, String> map = userList.stream() .collect(Collectors.toMap(User::getId, User::getUsername, (v1, v2) -> v1)); Map<Long, String> map = userList.stream() .collect(Collectors.toMap(User::getId, User::getUsername, (v1, v2) -> v2));
对相同key值的数据进行合并
1 2 Map<Long, Integer> map = itemList.stream().collect(Collectors.toMap(StocksComponentsItem::getStocksId, StocksComponentsItem::getCount, (e1, e2) -> e1 + e2));
获取treeMap,根据key值进行排序
1 2 3 4 Map<Long, String> treeMap = new HashMap <>(); TreeMap<Long, String> map = treeMap.entrySet().stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue(), (v1, v2) -> v1, TreeMap::new ));
常用方法
mapToDouble
mapToInt
mapToLong
flatMap流转换
扁平化映射,将多个stream连接成一个stream,这个操作是针对类似多维数组的,比如集合里面包含集合,相当于降维作用
例如:如果想要从List中取出学生列表,需要取出每个班级的学生List,再for循环调用List.addAll()方法把所有班级的学生List到一个新的总和List中
1 2 3 4 5 @Data public class StdCls { private String clsNo; private List<Student> studentList; }
使用map映射后会变成List<List>,若使用flatMap会进行扁平化处理,从而将List嵌套List用stream合并成一个List
1 2 3 4 List<String> nameList = stdClsList.stream() .map(StdCls::getStudentList) .flatMap(Collection::stream) .map(Student::getName).collect(Collectors.toList());
sorted排序
将流中的元素按照自然排序方式进行排序。
sorted():自然排序,流中元素需实现Comparable接口
1 2 3 List<String> list = Arrays.asList("aa" , "ff" , "dd" ); list.stream().sorted().forEach(System.out::println);
sorted(Comparator com):定制排序,自定义Comparator排序器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Student s1 = new Student ("aa" , 10 );Student s2 = new Student ("bb" , 20 );Student s3 = new Student ("aa" , 30 );Student s4 = new Student ("dd" , 40 );List<Student> studentList = Arrays.asList(s1, s2, s3, s4); studentList.stream().sorted( (o1, o2) -> { if (o1.getName().equals(o2.getName())) { return o1.getAge() - o2.getAge(); } else { return o1.getName().compareTo(o2.getName()); } } ).forEach(System.out::println);
peek消费
对流中每个元素执行操作,并返回一个新的流,返回的流还是包含原来流中的元素。
如同于map,能得到流中的每一个元素,但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值
1 2 3 4 5 6 7 8 9 Student s1 = new Student ("aa" , 10 );Student s2 = new Student ("bb" , 20 );List<Student> studentList = Arrays.asList(s1, s2); studentList.stream().peek(o -> o.setAge(100 )).forEach(System.out::println); Student{name='aa' , age=100 } Student{name='bb' , age=100 }
concat流合并
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static void main (String[] args) { ArrayList<String> list = new ArrayList <String>(); list.add("心如音" ); list.add("流老蛋" ); list.add("王值" ); list.add("李尔" ); list.add("张新敏" ); list.add("张天坤" ); Stream<String> s1 = list.stream().limit(4 ); Stream<String> s2 = list.stream().skip(2 ); Stream.concat(s1,s2).forEach(System.out::println); Stream.concat(s1,s2).distinct().forEach(System.out::println); }
终端操作
match元素匹配
allMatch匹配所有
1 2 3 4 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); if (integerList.stream().allMatch(i -> i > 3 )) { System.out.println("值都大于3" ); }
anyMatch匹配其中一个
1 2 3 4 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); if (integerList.stream().anyMatch(i -> i > 3 )) { System.out.println("存在大于3的值" ); }
noneMatch全部不匹配
1 2 3 4 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); if (integerList.stream().noneMatch(i -> i > 3 )) { System.out.println("值都小于3" ); }
count统计流中元素个数
1 2 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Long result = integerList.stream().count();
find查找
findFirst:查找第一个
findAny:随机查找一个
1 2 3 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Optional<Integer> result = integerList.stream().filter(i -> i > 3 ).findFirst(); Optional<Integer> result = integerList.stream().filter(i -> i > 3 ).findAny();
min、max获取流中最小最大值
1 2 3 4 5 Optional<Integer> min = menu.stream().map(Dish::getCalories).min(Integer::compareTo); Optional<Integer> max = menu.stream().map(Dish::getCalories).max(Integer::compareTo); OptionalInt min = menu.stream().mapToInt(Dish::getCalories).min();OptionalInt max = menu.stream().mapToInt(Dish::getCalories).max();
reduce元素组合
把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 String reduceStr1 = Stream.of("ma" , "zhi" , "chu" ).reduce("" , String::concat);String reduceStr2 = Stream.of("ma" , "zhi" , "chu" ).reduce("" , (x,y)->x+y);System.out.println(reduceStr1); System.out.println(reduceStr2); Integer total1 = Stream.of(1 ,2 ,3 ,4 ).reduce(0 , Integer::sum);Integer total2 = Stream.of(1 ,2 ,3 ,4 ).reduce(0 , (x, y) -> x +y);System.out.println(total1); System.out.println(total2); Integer total3 = Stream.of(1 , 2 , 3 , 4 ).reduce(Integer::sum).get();System.out.println(total3); double minValue = Stream.of(-1.1 , 8.8 , -2.2 , -6.6 ).reduce(Double.MAX_VALUE, Double::min);System.out.println(minValue); Optional<Integer> min = menu.stream().map(Dish::getCalories).reduce(Integer::min); Optional<Integer> max = menu.stream().map(Dish::getCalories).reduce(Integer::max);
求值
summingInt:求和
sum:求和
averagingInt:求平均值
summarizingInt:同时求总和、平均值、最大值、最小值
1 2 3 4 5 6 7 8 9 10 11 int sum = menu.stream().collect(Collectors.summingInt(Dish::getCalories));int sum = menu.stream().map(Dish::getCalories).reduce(0 , Integer::sum);int sum = menu.stream().mapToInt(Dish::getCalories).sum();double average = menu.stream().collect(Collectors.averagingInt(Dish::getCalories));IntSummaryStatistics intSummaryStatistics = menu.stream().collect(Collectors.summarizingInt(Dish::getCalories));double average = intSummaryStatistics.getAverage(); int min = intSummaryStatistics.getMin(); int max = intSummaryStatistics.getMax(); long sum = intSummaryStatistics.getSum();
foreach元素遍历
遍历流中的每一个元素,按照指定的方法执行,执行顺序不一定按照流的顺序
1 2 3 4 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); integerList.stream().forEach(System.out::println); Stream.of(1 ,2 ,3 ,4 ,5 ,6 ).parallel().forEach(System.out::println);
toArray返回数组
1 2 3 String[] strings = Stream.of("ma" , "zhi" , "chu" ).toArray(String[]::new ); System.out.println(Arrays.toString(strings));
collect返回集合
minBy/maxBy获取最小、最大值
1 2 Optional<Integer> min = menu.stream().map(Dish::getCalories).collect(Collectors.minBy(Integer::compareTo)); Optional<Integer> max = menu.stream().map(Dish::getCalories).collect(Collectors.maxBy(Integer::compareTo));
toMap获取属性映射
1 2 3 4 5 6 7 8 9 List<String> strings = menu.stream().map(Dish::getName).collect(Collectors.toList()); Set<String> sets = menu.stream().map(Dish::getName).collect(Collectors.toSet()); Map<Integer, House> houseMap = houses.stream().collect(Collectors.toMap(House::getOwnerid, o -> o)); Map<Integer, House> houseMap1 = houses.stream().collect(Collectors.toMap(House::getOwnerid, Function.identity())); houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename,(v1,v2)->v2)); houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename,(v1,v2)->v1));
counting统计元素个数
1 2 3 List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Long result = integerList.stream().count();Long result = integerList.stream().collect(Collectors.counting());
joining拼接流中的元素
1 String result = menu.stream().map(Dish::getName).collect(Collectors.joining(", " ));
默认如果不通过map方法进行映射处理拼接的toString方法返回的字符串,joining的方法参数为元素的分界符,如果不指定生成的字符串将是一串的
groupingBy元素分组
1 2 3 4 5 Map<Type, List<Dish>> result = dishList.stream().collect(Collectors.groupingBy(Dish::getType)); Map<String, Map<Integer, List<Dish>>> result = menu.stream().collect(Collectors.groupingBy(Dish::getName, Collectors.groupingBy(Dish::getCalories)));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ArrayList<GateScanCodeRecord> objects = new ArrayList <>(); objects.add(new GateScanCodeRecord ().setMonth("2020-07" ).setDay("2020-07-12" )); objects.add(new GateScanCodeRecord ().setMonth("2020-06" ).setDay("2020-06-14" )); objects.add(new GateScanCodeRecord ().setMonth("2020-06" ).setDay("2020-06-12" )); objects.add(new GateScanCodeRecord ().setMonth("2020-05" ).setDay("2020-05-17" )); objects.add(new GateScanCodeRecord ().setMonth("2020-05" ).setDay("2020-05-12" )); TreeMap<String, List<GateScanCodeRecord>> collect2 = objects.parallelStream().collect(Collectors.groupingBy(GateScanCodeRecord::getMonth, TreeMap::new , Collectors.toList())); TreeMap<String, List<GateScanCodeRecord>> collect3 = objects.parallelStream().collect(Collectors.groupingBy(GateScanCodeRecord::getMonth, () -> new TreeMap <>((o1, o2) -> Math.toIntExact(Long.parseLong(o2.replaceAll("-" ,"" )) - Long.parseLong(o1.replaceAll("-" ,"" )))), Collectors.toList())); TreeMap<String, TreeMap<String, List<GateScanCodeRecord>>> collect = objects.stream() .collect(Collectors.groupingBy(GateScanCodeRecord::getMonth, () -> new TreeMap <>((o1, o2) -> Math.toIntExact(Long.parseLong(o2.replaceAll("-" ,"" )) - Long.parseLong(o1.replaceAll("-" ,"" )))), Collectors.groupingBy(GateScanCodeRecord::getDay, () -> new TreeMap <>((o1, o2) -> Math.toIntExact(Long.parseLong(o2.replaceAll("-" ,"" )) - Long.parseLong(o1.replaceAll("-" ,"" )))), Collectors.toList())) );
partitioningBy元素分区
1 2 3 4 5 6 Map<Boolean, List<Dish>> result = menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian)); Map<Boolean, List<Dish>> result = menu.stream().collect(Collectors.groupingBy(Dish::isVegetarian)); List<Integer> integerList = Arrays.asList(1 , 2 , 3 , 4 , 5 ); Map<Boolean, List<Integer>> result = integerList.stream().collect(Collectors.partitioningBy(i -> i < 3 ));
mapping获取属性映射集合
对分组之后的对象集合转换为对象的某个属性的集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void main (String[] args) { List<Person> personList = new ArrayList <>(); Person tom = new Person ("tom" , "男" , 11 ); Person amy = new Person ("amy" , "女" , 13 ); Person ali = new Person ("ali" , "男" , 12 ); Person daming = new Person ("daming" , "男" , 13 ); personList.add(tom); personList.add(amy); personList.add(ali); personList.add(daming); Map<String, Set<String>> resultMap = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.mapping(Person::getName, Collectors.toSet()))); System.out.println(resultMap.toString()); }
Optional
Optional.of(T value):通过一个非null的value来构造一个Optional,返回的Optional包含了value这个值,对于该方法,传入的参数一定不能为null,否则会抛出NullPointerException
Optional.ofNullable(T value):与of的区别在于,传入的参数可以为null,进行三目运算,判断传入的参数是否为null,如果为null的话,返回的就是Optional.empty()
Optional.empty():用来构造一个空的Optional,即该Optional中不包含值
ifPresent
如果Optional中有值,则对该值调用consumer.accept,否则什么也不做
1 2 Optional<User> user = Optional.ofNullable(getUserById(id)); user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));
orElse
如果Optional中有值则将其返回,否则返回orElse方法传入的参数
1 2 3 public T orElse (T other) { return value != null ? value : other; }
1 2 3 4 User user = Optional .ofNullable(getUserById(id)) .orElse(new User (0 , "Unknown" )); System.out.println("Username is: " + user.getUsername());
orElseGet
与orElse方法的区别在于:orElseGet方法传入的参数为一个Supplier接口的实现,当Optional中有值的时候,返回值;当Optional中没有值的时候,返回从该Supplier获得的值
1 2 3 public T orElseGet (Supplier<? extends T> ither) { return value != null ? value : other.get(); }
1 2 3 User user = Optional.ofNullable(getUserById(id)) .orElseGet(() -> new User (0 , "Unknown" )); System.out.println("Username is: " + user.getUsername());
orElseThrow
与orElse方法的区别在于:orElseThrow方法当Optional中有值的时候,返回值;没有值的时候会抛出异常,抛出的异常由传入的exceptionSupplier提供
1 2 3 4 5 6 7 public <X extends Throwable > T orElseThrow (Supplier<? extends X> exceptionSupplier) throws X { if (value != null ) { return value; } else { throw exceptionSupplier.get(); } }
1 2 User user = Optional.ofNullable(getUserById(id)) .orElseThrow(() -> new EntityNotFoundException ("id 为 " + id + " 的用户没有找到" ));
map
如果当前Optional为Optional.empty,则依旧返回Optional.empty;否则返回一个新的Optional,该Optional包含的是:函数mapper在以value作为输入时的输出值
1 2 3 4 5 6 7 8 public <U> Optional<U> map (Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()){ return empty(); } else { return Optional.ofNullable(mapper.apply(value)); } }
1 2 3 4 5 6 7 Optional<String> username = Optional .ofNullable(getUserById(id)) .map(user -> user.getUsername()) .map(name -> name.toLowerCase()) .map(name -> name.replace('_' , ' ' )); System.out.println("Username is: " + username.orElse("Unknown" ));
flatMap
与map方法的区别在于,map方法参数中的函数mapper输出的是值,然后map方法会使用Optional.ofNullable将其包装为Optional,而flatMap要求参数中的函数mapper输出的就是Optional
1 2 3 4 5 6 7 8 public <U> Optional<U> flatMap (Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()){ return empty(); } else { return Objects.requireNonNull(mapper.apply(value)); } }
1 2 3 4 5 6 Optional<String> username = Optional .ofNullable(getUserById(id)) .flatMap(user -> Optional.of(user.getUsername())) .flatMap(name -> Optional.of(name.toLowerCase())); System.out.println("Username is: " + username.orElse("Unknown" ));
filter
filter方法接受一个Predicate来对Optional中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个Optional,否则返回Optional.empty
1 2 3 4 5 6 7 8 public Optional<T> filter (Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) { return this ; } else { return predicate.test(value) ? this : empty(); } }
1 2 3 4 5 6 Optional<String> username = Optional .ofNullable(getUserById(id)) .filter(user -> user.getId() < 10 ) .map(user -> user.getUsername()); System.out.println("Username is: " + username.orElse("Unknown" ));