8.JAVA流

合集下载

Java8用法总结

Java8用法总结

Java8⽤法总结⼀、新特性Java8带来了很多的新特性,本篇就以下⼏个⽅⾯,从实际⽤法的⾓度进⾏介绍。

Lambda 表达式函数式接⼝Stream默认⽅法Optional 类⼆、Lambda表达式2.1 引例@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class Product {private String id;private Long num;private Double price;}为了以后排序,我们定义⼀种⽐较器,按价格排序:Comparator<Product> byPrice = new Comparator<Product>() {@Overridepublic int compare(Product o1, Product o2) {return o1.getPrice().compareTo(o2.getPrice());}};byPrice的作⽤是按价格⽐较2种产品,它是⼀种⾏为,可以⽤Lambda表达:Comparator<Product> byPrice = (Product o1, Product o2) -> o1.getPrice().compareTo(o2.getPrice();这⾥只有⼀种类型Product,可根据Comparator<Product>判断,因此进⼀步简化:Comparator<Product> byPrice = (o1, o2) -> o1.getPrice().compareTo(o2.getPrice();2.2 概念Lambda表⽰⼀种⾏为,通过Lambda表达式将⾏为参数化,这样,⾏为可以和对象⼀样传递;从第三章可以了解,Lambda表达式可以⽤函数式接⼝表⽰,Comparator就是⼀种函数式接⼝;2.3 表达式Lambda表达式有三部分,参数列表、"->"、Lambda主体,实际中有以下2种形式:(parameters) -> expression(parameters) ->{ statements; }(List<Product> list) -> list.isEmpty; // 判断队列为空() -> new Product(); // 新建⼀个对象(String s) -> s.length; // 求字符串长度(Product p) -> System.out.println(p); // 输出对象三、函数式接⼝3.1 相关概念函数式接⼝:只定义⼀个抽象⽅法的接⼝;它可能还会有很多默认⽅法,但有且仅有⼀个抽象⽅法;常见的函数式接⼝如Comparator, Runnable;函数式接⼝可以⽤来表达Lamdba表达式;如将⼀个Lamdba表达式传递给⼀个函数式接⼝,即Lamdba表达式以内联的⽅式实现了函数式接⼝;函数描述符:函数式接⼝的抽象⽅法;如果我们想写⼀个⽤于2个数计算的计算器,可能需要实现如下⼏个函数,根据运算符调⽤对应函数计算;public <T> T add(T a, T b);public <T> T add(T a, T b);public <T> T multiply(T a, T b);public <T> T divide(T a, T b);换⼀种思路,如果有这样⼀个函数 public double func(double a, double b, Function f); f是⼀个函数式接⼝,它表⽰具体运算,具体代码实现如下:@Log4j2public class T19 {public static void main(String[] args) {(myFunction(1, 2, (a, b) -> a + b));(myFunction(1.0, 2.0, (a, b) -> a - b));(myFunction(BigDecimal.ZERO, BigDecimal.valueOf(2), (a, b) -> a.multiply(b)));}public static <T> T myFunction(T a, T b, MyBiFunctionInterface<T> f) {return f.apply(a, b);}}@FunctionalInterfacepublic interface MyBiFunctionInterface<T> {T apply(T a, T b);}输出如下:2018-09-01 19:39:11 - test.other.T19 INFO test.other.T19.main(T19.java:20) : 32018-09-01 19:39:11 - test.other.T19 INFO test.other.T19.main(T19.java:21) : -1.02018-09-01 19:39:11 - test.other.T19 INFO test.other.T19.main(T19.java:22) : 0Java8提供了很多函数式接⼝,⼀般情况下不⽤去定义函数式接⼝,⽐如例⼦中MyBiFunctionInterface,可⽤BinaryOperator代替,BinaryOperator这个函数式接⼝,接收2个类型为T的参数,返回⼀个类型为T的结果,即(T, T) -> T,修改后如下:public static <T> T myFunction(T a, T b, BinaryOperator<T> f) {return f.apply(a, b);}3.3 常见函数式接⼝Function<T, R>T-> RPredict<T>T -> booleanConsumer<T>T -> voidSupplier<T>() -> TUnaryOperator<T>T -> TBinaryOperator<T>(T, T) -> TBiFunction<T, U>(T, U) -> RBiPredicate<L, R>(L, R) -> booleanBiConsumer<T, U>(T, U) -> void3.4 ⽅法引⽤Lamdba表达式的快捷写法,它更直观,可读性更好,⽐如:(Product p) -> p.getPrice == Product::getPrice⽅法引⽤主要有⼆类:(1)指向静态⽅法;如 Integer::parseInt;(2)指向实例⽅法:如 String::length;(3)构造函数的⽅法引⽤:如Supplier<Product> p = Product::new;例:第⼆章引例中还可以如下表达:Comparator<Product> c = paring(Product::getPrice);复合,就是将多个Lamdba表达式连接起来,表⽰更加复杂的功能;主要有以下三种(1)函数复合:将Function代表的Lamdba复合起来,有andThen, compose;其中f.andThen(g) = g(f(x)),先计算f表达式,将结果再计算g表达式;pose(g) = f(g(x)),先计算g表达式,将结果再计算f表达式;Function<Integer, Integer> f = x -> x + 1;Function<Integer, Integer> g = x -> x * 2;Function<Integer, Integer> h1 = f.andThen(g); // (1 + 1) * 2 = 4Function<Integer, Integer> h2 = pose(g); // (1 * 2) + 1 = 3(2)Predicate的复合,有negate, and, or,分别表⽰⾮、且、或,按从左到右的顺序Predicate<Product> p1 = a -> a.getPrice() > 100; // ⼤于100Predicate<Product> p2 = p1.negate(); // ⼩于等于100Predicate<Product> p3 = p1.negate().and(a -> a.getNum() > 10); // 价格⼩于等于100,且数量⼤于10(3)⽐较器复合,如Comparator<Product> c = paring(Product::getPrice).reversed().thenComparing(Product::getNum);四、流4.1 概念流⽤来处理数据集合,它具有如下特点:(1)流强调的是计算,它是源+数据处理,流将外部迭代(如for/while)转化为对我们透明的内部迭代;(2)只能遍历⼀次,遍历完就关闭;流具有如下优点:(1)内置了很多常⽤⽅法(如排序、分类、统计);(2)能透明的并⾏处理;(3)声明式的,只需关注我要怎么样,不⽤关注我该如何实现,通过内置的⽅法与复合很容易实现;4.2 流的操作流的操作分为:(1)中间操作:filter(Predicate<T>), map(Function(T, R), limit, sorted(Comparator<T>), distinct,flatMap;(2)终端操作:只有终端操作才能产⽣输出,包括:allMatch, anyMatch, noneMatch, findAny, findFirst, forEach, collect, reduce, count4.3 流的⽤法@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class Product {private String id;private Long num;private Double price;private Boolean isUse;}List<Product> list = Lists.newArrayList(Product.builder().id("11").num(20l).price(100d).isUse(true).build(),Product.builder().id("12").num(25L).price(120d).isUse(true).build(),Product.builder().id("13").num(25L).price(100d).isUse(true).build(),Product.builder().id("14").num(20L).price(110d).isUse(false).build());(1)filter, 找出价格⼤于100的产品:List<Product> list1 = list.stream().filter(p -> p.getPrice() > 100).collect(Collectors.toList());(2)distinct,去重Arrays.asList(1, 2, 3, 1).stream().distinct().forEach(System.out::print); // 输出123(3)limit,输出前n个Arrays.asList(1, 2, 3, 1).stream().limit(2).forEach(System.out::print); //输出12(4)skip,跳过前n个Arrays.asList(1, 2, 3, 1).stream().skip(2).forEach(System.out::print); // 输出31(5)map, 映射,T -> R<R> Stream<R> map(Function<? super T, ? extends R> mapper);list.stream().map(Product::getPrice).distinct().forEach(System.out::println);输出:100.0120.0110.0(6)flatMap,扁平化,将每个元素产⽣的中间集合合并成⼀个⼤集合;接收的Function将T->Stream<R> <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);Arrays.asList(new String[]{"hello", "world"}).stream().map(p -> p.split("")).flatMap(Arrays::stream) //.flatMap(p -> Arrays.stream(p)).distinct().forEach(System.out::print);// 输出:helowrd(7)匹配boolean anyMatch(Predicate<? super T> predicate);allMatch: 都满⾜条件才返回true;anyMatch: 有⼀个满⾜就返回true;noneMatch: 都不满⾜才返回true;boolean b = Arrays.asList(1, 2, 3, 1).stream().anyMatch(p -> p > 2); //返回true(8)查找,与其它操作结合使⽤findAny: Optional<T> findAny()findFirst: Optional<T> findFirst()Arrays.asList(1, 2, 3, 4, 1).stream().filter(p -> p > 2).findAny() //输出Optional[3]Arrays.asList(1, 2, 3, 4, 1).stream().filter(p -> p > 2).findFirst() //输出Optional[3]4.4 reduce归约归约操作是很常⽤的操作,它将流中的值反复的结合起来,最终得到⼀个值,它是⼀种终端操作;(1)Optional<T> reduce(BinaryOperator<T> accumulator);(2)T reduce(T identity, BinaryOperator<T> accumulator);(3)<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner);(1)给定归约算法,最终归约成⼀个值,考虑到流可能为空,所以返回类型为Option,例:Optional<Integer> op1 = Arrays.asList(1, 2, 3, 4, 1).stream().reduce(Integer::sum); //输出Optional[11](2)给定了初值,归约算法,返回结果;Arrays.asList(1, 2, 3, 4, 1).stream().reduce(0, Integer::sum); //输出11// Steam<T>中T为包装类型,没有sum,但Java8为流的原始类型提供了⼀些⽅法,如下Arrays.asList(1, 2, 3, 4, 1).stream().mapToInt(a -> a).sum();list.stream().mapToLong(Product::getNum).sum();(3)第三个参数表⽰合并⽅式,当是并⾏流时,各线程独⽴计算结果,最后将各线程的结果合并;BiFunction<Double, Product, Double> f1 = (Double a, Product b) -> a + b.getNum();BinaryOperator<Double> f2 = (a, b) -> a + b;double b2 = list.parallelStream().reduce(0d, f1, f2);(b2); //输出904.5 数值流数值流除了具有流的⽅法外,还有⼀些特殊的统计⽅法,例DoubleStream doubleStream = list.stream().mapToDouble(Product::getPrice);double average = doubleStream.average().getAsDouble();//数值流->对象流Stream<Double> sd = doubleStream.boxed();// ⽣成n以内的勾股数Stream<double[]> stream = IntStream.rangeClosed(1, 30).boxed().flatMap(a -> IntStream.rangeClosed(a, 30).mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)}).filter(t -> t[2] % 1 == 0));stream.limit(3).forEach(t -> System.out.println(t[0] + ", " + t[1] + ", " + t[2]));输出:3.0,4.0,5.05.0, 12.0, 13.06.0, 8.0, 10.04.6 构建流Stream.iterate(0, n -> n + 2).limit(10);Stream.generate(Math::random).limit(10);五、收集器(collect归约)5.1 常见⽤法Map<Double, List<Product>> map = list.stream().collect(groupingBy(Product::getPrice));Long allNum = list.stream().collect(summingLong(Product::getNum));double average = list.stream().collect(averagingDouble(Product::getPrice));LongSummaryStatistics statistics = list.stream().collect(summarizingLong(Product::getNum));String ids = list.stream().map(Product::getId).collect(joining(", "));5.2 reducing归约Optional<Product> opp = list.stream().collect(reducing((a, b) -> a.getPrice() > b.getPrice() ? a : b));long allNum2 = list.stream().collect(reducing(0L, Product::getNum, Long::sum));long allNum3 = list.stream().collect(reducing(0L, Product::getNum, (i, j) -> i + j));collect中reducing归约三要素,初值,提取值,归约⽅法,若⽆初值返回Optional,若提取值即是对象本⾝,可省略;5.3 多重分组Map<Double, Map<Long, List<Product>>> map = list.stream().collect(groupingBy(Product::getPrice, groupingBy(Product::getNum))); Map<Double, Map<String, List<Product>>> map2 = list.stream().collect(groupingBy(Product::getPrice, groupingBy(p -> {if (p.getNum() <= 80L)return "little";else if (p.getNum() >= 120L)return "many";elsereturn "normal";})));System.out.println(JacksonUtil.toJson(map));System.out.println(JacksonUtil.toJson(map2));输出如下:{"100.0" : {"20" : [ {"id" : "11","num" : 20,"price" : 100.0,"isUse" : true} ],"25" : [ {"id" : "13","num" : 25,"price" : 100.0,"isUse" : true} ]},"110.0" : {"20" : [ {"id" : "14","num" : 20,"price" : 110.0,"isUse" : false} ]},"120.0" : {"25" : [ {"id" : "12","num" : 25,"price" : 120.0,"isUse" : true} ]}}{"100.0" : {"little" : [ {"id" : "11","num" : 20,"price" : 100.0,"isUse" : true}, {"id" : "13","num" : 25,"price" : 100.0,"isUse" : true} ]},"110.0" : {"little" : [ {"id" : "14","num" : 20,"price" : 110.0,"isUse" : false} ]},"120.0" : {"little" : [ {"id" : "12","num" : 25,"price" : 120.0,"isUse" : true} ]}}在⼀次分组的⼦集合中处理数据Map<Double, Long> map = list.stream().collect(groupingBy(Product::getPrice, counting()));Map<Double, Optional<Product>> map2 = list.stream().collect(groupingBy(Product::getPrice, maxBy(comparingLong(Product::getNum)))); Comparator<Product> c = ((p1, p2) -> p1.getNum().compareTo(p2.getNum()));Map<Double, Optional<Product>> map3 = list.stream().collect(groupingBy(Product::getPrice, maxBy(c)));Map<Double, Product> map4 = list.stream().collect(groupingBy(Product::getPrice,collectingAndThen(maxBy(comparing(Product::getNum)), Optional::get)));5.4 分区由⼀个谓词作为分类,分为2类,true与false,⽤法与groupingBy完全⼀样Map<Boolean, List<Product>> map = list.stream().collect(partitioningBy(Product::getIsUse));Map<Boolean, Map<Double, List<Product>>> map2 = list.stream().collect(partitioningBy(Product::getIsUse,groupingBy(Product::getPrice)));Map<Boolean, LongSummaryStatistics> map3 = list.stream().collect(partitioningBy(Product::getIsUse,summarizingLong(Product::getNum)));Map<Boolean, Double> map4 = list.stream().collect(partitioningBy(Product::getIsUse, averagingLong(Product::getNum)));六、optional6.1 使⽤(1)单级包装⽤法:我们会见到如下代码,String name = null;if (product != null) {name = product.getId();}利⽤optional可转化为Optional<Product> optProduct = Optional.ofNullable(product);Optional<String> optName = optProduct.map(Product::getId);(2)多级包装⽤法public String getName(Person person) {return person.getCar().getInsurance().getName();}经过包装如下,注意为防⽌Optional<Optional<T>>这种中间结果造成编译不通过,需要使⽤flatMap public String getName(Person person) {Optional<Person> optPerson = Optional.ofNullable(person);return optPerson.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unknown"); }。

java8stream、lambda表达式对list操作分组、过滤、求和、最值、排序、去重

java8stream、lambda表达式对list操作分组、过滤、求和、最值、排序、去重

java8stream、lambda表达式对list操作分组、过滤、求和、最值、排序、去重1.分组通过groupingBy分组指定字段list.stream().collect(Collectors.groupingBy(User::getSex));2.过滤通过filter⽅法过滤某些条件list.stream().filter(a -> !a.getJobNumber().equals("201901")).collect(Collectors.toList());3.求和基本类型:先mapToInt,然后调⽤sum⽅法List.stream().mapToInt(User::getAge).sum();⼤数类型:reduce调⽤BigDecimal::add⽅法List.stream().map(User::getFamilyMemberQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);4.最值最⼤值List.stream().map(User::getEntryDate).max(Date::compareTo).get();最⼩值List.stream().map(User::getEntryDate).min(Date::compareTo).get();5.排序list.stream().sorted((o1, o2)->o1.getItem().getValue().compareTo(o2.getItem().getValue())).collect(Collectors.toList());sort()单字段排序,根据id排序 list.sort(paring(Obj::getItem));多字段排序,根据id,年龄排序 list.sort(paring(Obj::getItem).thenComparing(Obj::getItem));6.去重通过distinct⽅法List.stream().distinct().collect(Collectors.toList());对属性重写⽅法7.获取list某个字段组装新listList.stream().map(a -> a.getId()).collect(Collectors.toList());。

Java8Stream.distinct()列表去重的操作

Java8Stream.distinct()列表去重的操作

Java8Stream.distinct()列表去重的操作在这篇⽂章⾥,我们将提供Java8 Stream distinct()⽰例。

distinct()返回由该流的不同元素组成的流。

distinct()是Stream接⼝的⽅法。

distinct()使⽤hashCode()和equals()⽅法来获取不同的元素。

因此,我们的类必须实现hashCode()和equals()⽅法。

如果distinct()正在处理有序流,那么对于重复元素,将保留以遭遇顺序⾸先出现的元素,并且以这种⽅式选择不同元素是稳定的。

在⽆序流的情况下,不同元素的选择不⼀定是稳定的,是可以改变的。

distinct()执⾏有状态的中间操作。

在有序流的并⾏流的情况下,保持distinct()的稳定性是需要很⾼的代价的,因为它需要⼤量的缓冲开销。

如果我们不需要保持遭遇顺序的⼀致性,那么我们应该可以使⽤通过BaseStream.unordered()⽅法实现的⽆序流。

1. Stream.distinct()distinct()⽅法的声明如下:Stream<T> distinct()它是Stream接⼝的⽅法。

在此⽰例中,我们有⼀个包含重复元素的字符串数据类型列表DistinctSimpleDemo.javapackage com.concretepage;import java.util.Arrays;import java.util.List;import java.util.stream.Collectors;public class DistinctSimpleDemo {public static void main(String[] args) {List<String> list = Arrays.asList("AA", "BB", "CC", "BB", "CC", "AA", "AA");long l = list.stream().distinct().count();System.out.println("No. of distinct elements:"+l);String output = list.stream().distinct().collect(Collectors.joining(","));System.out.println(output);}}OutputNo. of distinct elements:3AA,BB,CC2. Stream.distinct() with List of Objects在此⽰例中,我们有⼀个Book对象列表。

Java8中Stream详细用法大全

Java8中Stream详细用法大全

Java8中Stream详细⽤法⼤全⼀、概述Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进⾏的操作,可以执⾏⾮常复杂的查找、过滤和映射数据等操作。

使⽤Stream API 对集合数据进⾏操作,就类似于使⽤ SQL 执⾏的数据库查询。

也可以使⽤ Stream API 来并⾏执⾏操作。

简⽽⾔之,Stream API 提供了⼀种⾼效且易于使⽤的处理数据的⽅式。

特点:1. 不是数据结构,不会保存数据。

2. 不会修改原来的数据源,它会将操作后的数据保存到另外⼀个对象中。

(保留意见:毕竟peek⽅法可以修改流中元素)3. 惰性求值,流在中间处理过程中,只是对操作进⾏了记录,并不会⽴即执⾏,需要等到执⾏终⽌操作的时候才会进⾏实际的计算。

⼆、分类 ⽆状态:指元素的处理不受之前元素的影响; 有状态:指该操作只有拿到所有元素之后才能继续下去。

⾮短路操作:指必须处理所有元素才能得到最终结果; 短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则⽆需判断B的结果。

三、具体⽤法1. 流的常⽤创建⽅法1.1 使⽤Collection下的 stream() 和 parallelStream() ⽅法List<String> list = new ArrayList<>();Stream<String> stream = list.stream(); //获取⼀个顺序流Stream<String> parallelStream = list.parallelStream(); //获取⼀个并⾏流1.2 使⽤Arrays 中的 stream() ⽅法,将数组转成流Integer[] nums = new Integer[10];Stream<Integer> stream = Arrays.stream(nums);1.3 使⽤Stream中的静态⽅法:of()、iterate()、generate()Stream<Integer> stream = Stream.of(1,2,3,4,5,6);Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);stream2.forEach(System.out::println); // 0 2 4 6 8 10Stream<Double> stream3 = Stream.generate(Math::random).limit(2);stream3.forEach(System.out::println);1.4 使⽤ BufferedReader.lines() ⽅法,将每⾏内容转成流BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));Stream<String> lineStream = reader.lines();lineStream.forEach(System.out::println);1.5 使⽤ Pattern.splitAsStream() ⽅法,将字符串分隔成流Pattern pattern = pile(",");Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");stringStream.forEach(System.out::println);2. 流的中间操作2.1 筛选与切⽚ filter:过滤流中的某些元素 limit(n):获取n个元素 skip(n):跳过n元素,配合limit(n)可实现分页 distinct:通过流中元素的 hashCode() 和 equals() 去除重复元素Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14.distinct() //6 7 9 8 10 12 14.skip(2) //9 8 10 12 14.limit(2); //9 8newStream.forEach(System.out::println);2.2 映射 map:接收⼀个函数作为参数,该函数会被应⽤到每个元素上,并将其映射成⼀个新的元素。

Java8新特性之Steam流式编程

Java8新特性之Steam流式编程

Java8新特性之Steam流式编程特地感谢鲁班⼤叔的分享,原学习地址:以下是学习过程整理的笔记1、简介Stream 流处理,⾸先要澄清的是 java8 中的 Stream 与 I/O 流 InputStream 和 OutputStream 是完全不同的概念。

Stream 机制是针对集合迭代器的增强。

流允许你⽤声明式的⽅式处理数据集合(通过查询语句来表达,⽽不是临时编写⼀个实现)2、创建对象流的三种⽅式1. 由集合对象创建流。

对⽀持流处理的对象调⽤ stream()。

⽀持流处理的对象包括 Collection 集合及其⼦类List<Integer> list = Arrays.asList(1,2,3);Stream<Integer> stream = list.stream();2. 由数组创建流。

通过静态⽅法 Arrays.*stream()* 将数组转化为流(Stream)IntStream stream = Arrays.stream(new int[]{3, 2, 1});3. 通过静态⽅法 Stream.of() ,但是底层其实还是调⽤ Arrays.stream()Stream<Integer> stream = Stream.of(1, 2, 3);注意:还有两种⽐较特殊的流空流:Stream.empty()⽆限流:**Stream.generate() ** 和 **Stream.iterate() **。

可以配合 limit() 使⽤可以限制⼀下数量// 接受⼀个 Supplier 作为参数Stream.generate(Math::random).limit(10).forEach(System.out::println);// 初始值是 0,新值是前⼀个元素值 + 2Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println);3、流处理的特性1. 不存储数据2. 不会改变数据源3. 不可以重复使⽤测试⽤例:package com.godfrey.stream.features;import org.junit.Assert;import org.junit.Test;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;import java.util.stream.Stream;/*** 流特性** @author godfrey* @since 2021-08-15*/class StreamFeaturesTest {/*** 流的简单例⼦*/@Testpublic void test1() {List<Integer> list = Stream.of(1, 2, 5, 9, 7, 3).filter(val -> val > 2).sorted().collect(Collectors.toList());for (Integer item : list) {System.out.println(item);}}/*** 流不会改变数据源*/@Testpublic void test2() {List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);list.add(1);Assert.assertEquals(3, list.stream().distinct().count());Assert.assertEquals(4, list.size());}/*** 流不可以重复使⽤*/@Test(expected = IllegalStateException.class)public void test3() {Stream<Integer> integerStream = Stream.of(1, 2, 3);Stream<Integer> newStream = integerStream.filter(val -> val > 2);integerStream.skip(1);}}⾸先,test1() 向我们展⽰了流的⼀般⽤法,由下图可见,源数据流经管道,最后输出结果数据。

java8 map foreach 跳出循环实现方法

java8 map foreach 跳出循环实现方法

java8 map foreach 跳出循环实现方法在Java 8中,我们可以使用map和forEach方法来对集合进行遍历和操作。

然而,跳出循环是一项常见的需求,但在forEach方法中并不容易实现。

下面是一种可以在Java 8中实现跳出循环的方法。

要实现跳出循环,我们可以结合使用Stream的anyMatch方法和自定义的Predicate函数接口。

anyMatch方法会对集合中的每个元素应用传入的Predicate函数,直到找到一个满足条件的元素,然后立即返回true。

我们可以利用这一点来跳出循环。

首先,我们需要定义一个Predicate函数接口,用来判断是否满足跳出循环的条件。

例如,我们想要在集合中找到第一个大于100的元素,可以定义如下的Predicate函数接口:```javapublic interface BreakCondition<T> {boolean test(T t);}```接下来,我们可以使用该接口来实现跳出循环的方法:```javapublic static <T> void breakableForEach(List<T> list, BreakCondition<T> condition, Consumer<T> action) {AtomicBoolean found = new AtomicBoolean(); // 用于记录是否找到满足条件的元素list.stream().anyMatch(element -> {if (condition.test(element)) {found.set(true);return true; // 跳出循环} else {action.accept(element);return false; // 继续循环}});if (found.get() == false) {System.out.println("未找到满足条件的元素");}}```以上方法中,我们首先使用AtomicBoolean来记录是否找到满足条件的元素,初始值为false。

java8 stream 空指针处理

java8 stream 空指针处理Java 8 引入了流(Stream) API,它是处理集合的非常强大的一种方式。

在使用 Stream API 的时候我们有可能会遇到空指针异常,这是因为在集合中可能存在 null 引用元素,这时候需要对空指针进行处理。

本篇文档主要介绍如何在使用 Stream API 的过程中处理空指针异常,包括以下内容:- 什么是空指针异常 - 如何在 Stream API 中进行空指针处理 - null 安全的 Stream API 库一、什么是空指针异常在 Java 中,当一个引用变量没有引用任何对象时,我们称之为空引用,即 null。

如果我们试图对这个引用执行任何操作(比如调用它的方法或者访问它的属性),就会抛出一个空指针异常。

这是因为假设这个引用指向某个对象,我们才能访问它的方法和属性,但是当它引用 null 的时候没有任何东西可供访问,就会抛出异常。

在集合中也可能存在 null 引用元素,如果我们使用Stream API 处理集合时没有进行空指针处理,在对 null 引用元素进行操作时就会抛出空指针异常。

二、如何在 Stream API 中进行空指针处理1. 使用过滤函数过滤 null 元素我们可以通过在 Stream API 的链式调用中使用过滤函数 filter() 来过滤 null 引用元素,例如:List<String> list = Arrays.asList("a", "b",null, "c", null);List<String> filteredList =list.stream() .filter(e -> e !=null) .collect(Col lectors.toList());在这个例子中,我们使用 filter() 方法过滤 null引用元素,这样可以避免在后续的操作中出现空指针异常。

java8多个enum匹配的流式写法

标题:探讨Java 8中多个Enum匹配的流式写法在Java 8中,引入了流式操作(Stream API),为我们提供了一种优雅而高效的处理集合数据的方式。

在实际开发中,我们经常需要对一个集合中的元素进行匹配,尤其是当这个集合中包含多个Enum类型的元素时,如何使用流式写法进行匹配成为了一个常见问题。

本文将深入探讨在Java 8中多个Enum匹配的流式写法,以及个人观点和理解。

---1. 背景介绍让我们了解一下Java 8中Enum的基本概念。

Enum(枚举类型)是一种特殊的数据类型,它通常表示固定数量的常量。

Java 8引入了流式操作(Stream),它允许我们对集合中的元素进行高级抽象的操作,包括筛选、映射、聚合等。

2. 多个Enum匹配的问题在实际开发中,我们可能会遇到需要对包含多个Enum类型的集合进行匹配的情况。

我们有一个包含多个不同状态的订单列表,我们需要筛选出所有已完成和已取消的订单。

在传统的做法中,我们通常需要使用多次循环来实现匹配,但是在Java 8中,我们可以利用流式写法来简化这个过程。

3. 流式写法实现多个Enum匹配在Java 8中,我们可以使用流式操作的filter方法来实现对多个Enum的匹配。

以订单列表为例,假设我们有一个Order类,其中包含一个Status枚举表示订单的状态。

我们可以通过以下方式来筛选出所有已完成和已取消的订单:```javaList<Order>pletedOrCancelledOrders = orders.stream().filter(order -> order.getStatus() == PLETED || order.getStatus() == Status.CANCELLED).collect(Collectors.toList());```在这个例子中,我们使用了stream方法将订单列表转换为流,然后使用filter方法筛选出状态为已完成或已取消的订单,最后使用collect 方法将结果收集到一个新的列表中。

Java8-使用stream.sorted()对List和Map排序

Java8-使⽤stream.sorted()对List和Map排序前提 java8中,Comparator()是⼀个函数式接⼝,可以使⽤Lambda表达式实现; Stream sorted(Comparator<? super T> comparator);vo@Data@AllArgsConstructorpublic class DailyDataChartVo {/*** ⽇期*/private LocalDate date;/*** 今⽇营收*/private BigDecimal revenue;}List排序1. 按⽇期排序List<DailyDataChartVo> list = list.stream().sorted(paring(DailyDataChartVo::getDate)).collect(Collectors.toList());2. 按⽇期排序后,逆序List<DailyDataChartVo> list = list.stream().sorted(paring(DailyDataChartVo::getDate).reversed()).collect(Collectors.toList());3. 按⽇期排序后,再按⾦额排序List<DailyDataChartVo> list = list.stream().sorted(paring(DailyDataChartVo::getDate).thenComparing(DailyDataChartVo::getRevenue)).collect(Collectors.toList());4. 按⾦额排序,排序时过滤Null值(如果排序的字段为null,NPE)List<DailyDataChartVo> list = list.stream().filter(c -> Objects.nonNull(c.getRevenue())).sorted(paring(DailyDataChartVo::getRevenue)).collect(Collectors.toList());5. 按⾦额排序,Null值排在最前⾯List<DailyDataChartVo> list = list.stream().sorted(paring(DailyDataChartVo::getRevenue,Comparator.nullsFirst(BigDecimal::compareTo))).collect(Collectors.toList());//注意Comparator.nullsFirst的⽅法引⽤中,⽐较的字段是BigDecimal类型的,如果前后类型不⼀致,会报错:Non-static method cannot be referenced from a static context6. 按⾦额排序,Null值排在最后⾯List<DailyDataChartVo> list = list.stream().sorted(paring(DailyDataChartVo::getRevenue,Comparator.nullsLast(BigDecimal::compareTo))).collect(Collectors.toList());Map排序1. 按key排序Map<LocalDate, BigDecimal> map = map.entrySet().stream().sorted(paringByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> c1, LinkedHashMap::new)); 将map转换成流,在流中对元素进⾏排序,排序后,再⽤LinkedHashMap收集来保留顺序public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey());} paringByKey():对任意的c1, c2进⾏⽐较,然后将结果强制转换成⼀个可序列化的Comparator<Map.Entry<K, V>>2. 按key排序后,逆序Map<LocalDate, BigDecimal> map = map.entrySet().stream().sorted(paringByKey(Comparator.reverseOrder())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> c1, LinkedHashMap::new));3. 按value排序Map<LocalDate, BigDecimal> map = map.entrySet().stream().sorted(paringByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> c1, LinkedHashMap::new));。

总结一下关于在Java8中使用stream流踩过的一些坑

总结⼀下关于在Java8中使⽤stream流踩过的⼀些坑Java8的stream流第⼀个坑:Collectors.toAsList()其实是new了⼀个list,在向⾥⾯赋值。

注意这⾥Collectors.toList()的写法,这⾥其实是底层new ArraryList().筛选的数据放到⼀个新的list。

虽然标1处和标2处是同⼀个变量,但是内存地址是不⼀样啊。

下⾯的逻辑时把hldrPolVOList中的某些元素删除。

但是这个⽅法执⾏完后其实是没有删除⾥⾯元素的。

原因就是这⾥的new ArraryList()更改了内存地址造成的。

测试:解决办法:第⼆个坑:list.stream().foreach(p->{return;});这⾥的return是结束的foreach⽽不是外部⽅法解决办法:把stream改成for循环。

第三个坑:并⾏流(parallelStream() )的foreach操作⾥,如果把⼀个ArrayList⾥的值copy到另外⼀ArrayList时,就有可能多或者少元素。

原因并⾏流是多线程,⽽ArrayList是⾮线程安全的。

写在最后关于java8的stream是⾮常好⽤的,主要写的代码更加简洁,不在写⼤量代码。

但是也不是所有场景都适合⽤的,如果本来业务耗时⽐较长,然后有希望减少业务执⾏时间。

在数据量不是很⼤的情况下,stream流是没有优势的,也就是说数据量⼩,且同意业务内多处使⽤stream处理数据,这时执⾏耗时⽐for循环更多,只有业务量达到百万级别才体现出优势。

到此这篇关于总结⼀下关于在Java8中使⽤stream流踩过的⼀些坑的⽂章就介绍到这了,更多相关Java8的stream流内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档