三. Stream API

1. 过滤

record Fruit(String cname, String name, String category, String color) { }Stream.of(new Fruit("草莓", "Strawberry", "浆果", "红色"),new Fruit("桑葚", "Mulberry", "浆果", "紫色"),new Fruit("杨梅", "Waxberry", "浆果", "红色"),new Fruit("核桃", "Walnut", "坚果", "棕色"),new Fruit("草莓", "Peanut", "坚果", "棕色"),new Fruit("蓝莓", "Blueberry", "浆果", "蓝色")
)

在这里插入图片描述
找到所有浆果

.filter(f -> f.category.equals("浆果"))

找到蓝色的浆果

方法1:

.filter(f -> f.category().equals("浆果") && f.color().equals("蓝色"))

方法2:让每个 lambda 只做一件事,两次 filter 相对于并且关系

.filter(f -> f.category.equals("浆果"))
.filter(f -> f.color().equals("蓝色"))

方法3:让每个 lambda 只做一件事,不过比方法2强的地方可以 or,and,nagate 运算

.filter(((Predicate<Fruit>) f -> f.category.equals("浆果")).and(f -> f.color().equals("蓝色")))

2. 映射

在这里插入图片描述

.map(f -> f.cname() + "酱")

3. 降维(扁平化)

例1
在这里插入图片描述

Stream.of(List.of(new Fruit("草莓", "Strawberry", "浆果", "红色"),new Fruit("桑葚", "Mulberry", "浆果", "紫色"),new Fruit("杨梅", "Waxberry", "浆果", "红色"),new Fruit("蓝莓", "Blueberry", "浆果", "蓝色")),List.of(new Fruit("核桃", "Walnut", "坚果", "棕色"),new Fruit("草莓", "Peanut", "坚果", "棕色"))
).flatMap(Collection::stream)    
  • 这样把坚果和浆果两个集合变成了含六个元素的水果流

例2:

Stream.of(new Order(1, List.of(new Item(6499, 1, "HUAWEI MateBook 14s"),new Item(6999, 1, "HUAWEI Mate 60 Pro"),new Item(1488, 1, "HUAWEI WATCH GT 4"))),new Order(1, List.of(new Item(8999, 1, "Apple MacBook Air 13"),new Item(7999, 1, "Apple iPhone 15 Pro"),new Item(2999, 1, "Apple Watch Series 9")))
)

想逐一处理每个订单中的商品

.flatMap(order -> order.items().stream())

这样把一个有两个元素的订单流,变成了一个有六个元素的商品流

4. 构建

在这里插入图片描述

根据已有的数组构建流

Arrays.stream(array)

根据已有的 Collection 构建流(包括 List,Set 等)

List.of("a","b","c").stream()

把一个对象变成流

Stream.of("d")

把多个对象变成流

Stream.of("x", "y")

5. 拼接

两个流拼接

Stream.concat(Stream.of("a","b","c"), Stream.of("d"))

6. 截取

Stream.concat(Stream.of("a", "b", "c"), Stream.of("d")).skip(1).limit(2)
  • skip 是跳过几个元素

  • limit 是限制处理的元素个数

  • dropWhile 是 drop 流中元素,直到条件不成立,留下剩余元素

  • takeWhile 是 take 流中元素,直到条件不成立,舍弃剩余元素

        Stream<Integer> concat = Stream.concat(s1, s2);concat.takeWhile(x->x<3).forEach(System.out::print);concat.dropWhile(x->x<3).forEach(System.out::print);

7. 生成

在这里插入图片描述

生成从 0 ~ 9 的数字

IntStream.range(0, 10)

或者

IntStream.rangeClosed(0, 9)

如果想订制,可以用 iterate 方法,例如下面生成奇数序列

IntStream.iterate(1, x -> x + 2)
  • 参数1 是初始值
  • 参数2 是一个特殊 Function,即参数类型与返回值相同,它会根据上一个元素 x 的值计算出当前元素
  • 需要用 limit 限制元素个数

也可以用 iterate 的重载方法

IntStream.iterate(1, x -> x < 10, x -> x + 2)
  • 参数1 是初始值
  • 参数2 用来限制元素个数,一旦不满足此条件,流就结束
  • 参数3 相当于上个方法的参数2

iterate 的特点是根据上一个元素计算当前元素,如果不需要依赖上一个元素,可以改用 generate 方法

例如下面是生成 5 个随机 int

Stream.generate(()-> ThreadLocalRandom.current().nextInt()).limit(5)

不过如果只是生成随机数的话,有更简单的办法

ThreadLocalRandom.current().ints(5)

如果要指定上下限,例如下面是生成从 0~9 的100个随机数

ThreadLocalRandom.current().ints(100, 0, 10)

8. 查找与判断

在这里插入图片描述

下面的代码找到流中任意(Any)一个偶数

int[] array = {1, 3, 5, 4, 7, 6, 9};Arrays.stream(array).filter(x -> (x & 1) == 0).findAny().ifPresent(System.out::println);
  • 注意 findAny 返回的是 OptionalInt 对象,因为可能流中不存在偶数
  • 对于 OptionalInt 对象,一般需要用 ifPresent(findAny筛选后存在数据即处理,否则不处理) 或 orElse(提供默认值)来处理

与 findAny 比较类似的是 firstFirst,它俩的区别

  • findAny 是找在流中任意位置的元素,不需要考虑顺序,对于上例返回 6 也是可以的
  • findFirst 是找第一个出现在元素,需要考虑顺序,对于上例只能返回 4
  • findAny 在顺序流中与 findFirst 表现相同,区别在于并行流下会更快

判断流中是否存在任意一个偶数

Arrays.stream(array).anyMatch(x -> (x & 1) == 0)
  • 它返回的是 boolean 值,可以直接用来判断

判断流是否全部是偶数

Arrays.stream(array).allMatch(x -> (x & 1) == 0)
  • 同样,它返回的是 boolean 值,可以直接用来判断

判断流是否全部不是偶数

Arrays.stream(array).noneMatch(x -> (x & 1) == 0)
  • noneMatch 与 allMatch 含义恰好相反

9. 排序与去重

已知有数据

record Hero(String name, int strength) { }Stream.of(new Hero("独孤求败", 100),new Hero("令狐冲", 90),new Hero("风清扬", 98),new Hero("东方不败", 98),new Hero("方证", 92),new Hero("任我行", 92),new Hero("冲虚", 90),new Hero("向问天", 88),new Hero("不戒", 88)
)

要求,首先按 strength 武力排序(逆序),武力相同的,按姓名长度排序(正序)

仅用 lambda 来解

.sorted((a,b)-> {int res = Integer.compare(b.strength(), a.strength());return (res == 0) ? Integer.compare(a.nameLength(), b.nameLength()) : res; 
})

方法引用改写

.sorted(Comparator.comparingInt(Hero::strength).reversed().thenComparingInt(Hero::nameLength)
)

其中:

  • comparingInt 接收一个 key 提取器(说明按对象中哪部分来比较),返回一个比较器
  • reversed 返回一个顺序相反的比较器
  • thenComparingInt 接收一个 key 提取器,返回一个新比较器,新比较器在原有比较器结果相等时执行新的比较逻辑

增加一个辅助方法

record Hero(String name, int strength) {int nameLength() {return this.name.length();}
}

原理:

.sorted((e, f) -> {int res =((Comparator<Hero>) (c, d) ->((Comparator<Hero>) (a, b) -> Integer.compare(a.strength(), b.strength())).compare(d, c)).compare(e, f);return (res == 0) ? Integer.compare(e.nameLength(), f.nameLength()) : res;
})

如果不好看,改成下面的代码

.sorted(step3(step2(step1())))static Comparator<Hero> step1() {return (a, b) -> Integer.compare(a.strength(), b.strength());
}static Comparator<Hero> step2(Comparator<Hero> step1) {return (c, d) -> step1.compare(d, c);
}static Comparator<Hero> step3(Comparator<Hero> step2) {return (e, f) -> {int res = step2.compare(e, f);return (res == 0) ? Integer.compare(e.nameLength(), f.nameLength()) : res;};
}

10. 化简

reduce(init, (p,x) -> r)

  • init 代表初始值
  • (p,x) -> r 是一个 BinaryOperator,作用是根据上次化简结果 p 和当前元素 x,得到本次化简结果 r

这样两两化简,可以将流中的所有元素合并成一个结果

/*化简:两两合并,只剩一个适合:最大值、最小值、求和、求个数....reduce((p, x) -> r)        p 上次的合并结果, x 当前元素, r 本次合并结果.reduce(init, (p, x) -> r).reduce(init, (p, x) -> r, (r1, r2) -> r)*/
public class C10ReduceTest {record Hero(String name, int strength) {}public static void main(String[] args) {Stream<Hero> stream = Stream.of(new Hero("令狐冲", 90),new Hero("风清扬", 98),new Hero("独孤求败", 100),new Hero("方证", 92),new Hero("东方不败", 98),new Hero("冲虚", 90),new Hero("向问天", 88),new Hero("任我行", 92),new Hero("不戒", 88));// 1) 求武力最高的 hero
//        Optional<Hero> result = stream.reduce((h1, h2) -> h1.strength() > h2.strength() ? h1 : h2);
//        Hero result = stream.reduce(new Hero("-", -1), (h1, h2) -> h1.strength() > h2.strength() ? h1 : h2);
//        System.out.println(result);// 2) 求高手总数
//        System.out.println(stream.map(h -> 1).reduce(0, (a, b) -> a + b));//        System.out.println(stream.count());
//        System.out.println(stream.max(Comparator.comparingInt(Hero::strength)));
//        System.out.println(stream.min(Comparator.comparingInt(Hero::strength)));
//        System.out.println(stream.mapToInt(Hero::strength).sum());System.out.println(stream.mapToInt(Hero::strength).average());}
}

11. 收集

collect( supplier, accumulator, combiner)

  • supplier 是描述如何创建收集容器 c :()-> c
  • accumulator 是描述如何向容器 c 添加元素 x:(c, x) -> void
  • combiner 是描述如何合并两个容器:(c1, c2) -> void
    • 串行流下不需要合并容器
    • 并行流如果用的是并发容器,也不需要合并
public class C11CollectTest {record Hero(String name, int strength) {}/*收集:将元素收集入容器.collect(() -> c, (c, x) -> void, ?)() -> c             创建容器 c(c, x) -> void      将元素 x 加入 容器 c*/public static void main(String[] args) {Stream<String> stream = Stream.of("令狐冲", "风清扬", "独孤求败", "方证","东方不败", "冲虚", "向问天", "任我行", "不戒", "不戒", "不戒", "不戒");/*1) 收集到 ListList<String> result = stream.collect(() -> new ArrayList<>(), (list, x) -> list.add(x), (a, b) -> { });ArrayList::new   ()->new ArrayList()ArrayList::add   (list,x)->list.add(x)List<String> result = stream.collect(ArrayList::new, ArrayList::add, (a, b) -> { });*//*2) 收集到 SetSet<String> result = stream.collect(LinkedHashSet::new, Set::add, (a, b) -> { });*//*3)收集到 MapMap<String, Integer> result = stream.collect(HashMap::new, (map,x)->map.put(x, 1), (a, b) -> { });*///        StringBuilder sb = stream.collect(StringBuilder::new, StringBuilder::append, (a,b)->{});
//        System.out.println(sb);StringJoiner sb = stream.collect(()->new StringJoiner(","), StringJoiner::add, (a,b)->{});System.out.println(sb);}
}

12. 收集器

Collectors 类 中提供了很多现成的收集器,详情见网页

// Collector 收集器
public class C12CollectorTest {record Hero(String name, int strength) {}public static void main(String[] args) {Stream<String> stream = Stream.of("令狐冲", "风清扬", "独孤求败", "方证","东方不败", "冲虚", "向问天", "任我行", "不戒");/*1) 收集到 ListList<String> result = stream.collect(() -> new ArrayList<>(), (list, x) -> list.add(x), (a, b) -> { });ArrayList::new   ()->new ArrayList()ArrayList::add   (list,x)->list.add(x)List<String> result = stream.collect(ArrayList::new, ArrayList::add, (a, b) -> { });*/
//        List<String> result = stream.collect(Collectors.toList());/*2) 收集到 SetSet<String> result = stream.collect(LinkedHashSet::new, Set::add, (a, b) -> { });*/
//        Set<String> result = stream.collect(Collectors.toSet());/*3)收集到 StringBuilderStringBuilder sb = stream.collect(StringBuilder::new, StringBuilder::append, (a,b)->{});*/
//        String result = stream.collect(Collectors.joining());/*4)收集到 StringJoinerStringJoiner sb = stream.collect(()->new StringJoiner(","), StringJoiner::add, (a,b)->{});*/
//        String result = stream.collect(Collectors.joining(","));/*3)收集到 MapMap<String, Integer> result = stream.collect(HashMap::new, (map,x)->map.put(x, 1), (a, b) -> { });*/
//        Map<String, Integer> map = stream.collect(Collectors.toMap(x -> x, x -> 1));/*Map3: new ArrayList(["令狐冲","风清扬","向问天","任我行"])4: new ArrayList(["独孤求败","东方不败"])2: new ArrayList(["方证","冲虚","不戒"])下游收集器*///        Map<Integer, List<String>> result = stream.collect(Collectors.groupingBy(x -> x.length(), Collectors.toList()));Map<Integer, String> result = stream.collect(Collectors.groupingBy(x -> x.length(), Collectors.joining(",")));for (Map.Entry<Integer, String> e : result.entrySet()) {System.out.println(e);}}
}

13. 下游收集器

做 groupingBy 分组收集时,组内可能需要进一步的数据收集,称为下游收集器,详情见网页

public class C13GroupingByTest {record Hero(String name, int strength) {}public static void main(String[] args) {Stream<Hero> stream = Stream.of(new Hero("令狐冲", 90),new Hero("风清扬", 98),new Hero("独孤求败", 100),new Hero("方证", 92),new Hero("东方不败", 98),new Hero("冲虚", 90),new Hero("向问天", 88),new Hero("任我行", 92),new Hero("不戒", 88));/*1. mapping(x->y, dc)  需求:根据名字长度分组,分组后组内只保留他们的武力值new Hero("令狐冲", 90)->90dc 下游收集器 down collectorstream.collect(groupingBy(h -> h.name().length(), mapping(h -> h.strength(), toList())));*//*2. filtering(x->boolean, dc)  需求:根据名字长度分组,分组后组内过滤掉武力小于 90 的在分组收集的过程中,执行过滤stream.collect(groupingBy(h -> h.name().length(), filtering(h -> h.strength() >= 90, toList())));先过滤,再来分组收集stream.filter(h -> h.strength() >= 90).collect(groupingBy(h -> h.name().length(), toList()));*//*3. flatMapping(x->substream, dc)     需求:根据名字长度分组,分组后组内保留人名,并且人名切分成单个字符"令狐冲".chars().mapToObj(Character::toString).forEach(System.out::println);stream.collect(groupingBy(h -> h.name().length(),flatMapping(h -> h.name().chars().mapToObj(Character::toString), toList())));*//*4. counting() 需求:根据名字长度分组,分组后求每组个数stream.collect(groupingBy(h -> h.name().length(), counting()));*//*5. minBy((a,b)->int) 需求:根据名字长度分组,分组后求每组武功最低的人6. maxBy((a,b)->int) 需求:根据名字长度分组,分组后求每组武功最高的人stream.collect(groupingBy(h -> h.name().length(), maxBy(Comparator.comparingInt(Hero::strength))));*//*7. summingInt(x->int)            需求:根据名字长度分组,分组后求每组武力和8. averagingDouble(x->double)    需求:根据名字长度分组,分组后求每组武力平均值stream.collect(groupingBy(h -> h.name().length(), averagingDouble(h -> h.strength())));*//*9. reducing(init,(p,x)->r)求和stream.collect(groupingBy(h -> h.name().length(), mapping(h -> h.strength(), reducing(0, (p, x) -> p + x))));求个数stream.collect(groupingBy(h -> h.name().length(), mapping(h -> 1, reducing(0, (p, x) -> p + x))));*/// 求平均,缺少 finisherMap<Integer, double[]> collect = stream.collect(groupingBy(h -> h.name().length(),mapping(h -> new double[]{h.strength(), 1},reducing(new double[]{0, 0}, (p, x) -> new double[]{p[0] + x[0], p[1] + x[1]}))));for (Map.Entry<Integer, double[]> e : collect.entrySet()) {System.out.println(e.getKey() + ":" + Arrays.toString(e.getValue()));}}
}

14. 基本流

在这里插入图片描述在这里插入图片描述

基本类型流指 IntStream、LongStream 和 DoubleStream,它们在做数值计算时有更好的性能。

转换成基本流

  • mapToInt
  • mapToLong
  • mapToDouble
  • flatMapToInt
  • flatMapToLong
  • flatMapToDouble
  • mapMultiToInt
  • mapMultiToLong
  • mapMultiToDouble

基本流转对象流

  • mapToObj
  • boxed
public class C14Effective {record Hero(String name, int strength) {}/*三种基本流*/public static void main(String[] args) {IntStream a = IntStream.of(97, 98, 99);LongStream b = LongStream.of(1L, 2L, 3L);DoubleStream c = DoubleStream.of(1.0, 2.0, 3.0);Stream<Integer> d = Stream.of(1, 2, 3);//        a.mapToObj(Character::toString).forEach(System.out::println);//        IntSummaryStatistics stat = a.summaryStatistics();
//        System.out.println(stat.getSum());
//        System.out.println(stat.getCount());
//        System.out.println(stat.getMax());
//        System.out.println(stat.getMin());
//        System.out.println(stat.getAverage());Stream<Hero> stream = Stream.of(new Hero("令狐冲", 90),new Hero("风清扬", 98));stream.mapToInt(Hero::strength).forEach(System.out::println );}
}

15. 特性

  1. 一次使用:流只能使用一次(终结方法只能调用一次)
  2. 两类操作:
    1. 中间操作,lazy 懒惰的
    2. 终结操作,eager 迫切的
public class C15Summary {public static void main(String[] args) {/*掌握 Stream 流的特性1. 一次使用2. 两类操作(中间操作 lazy 懒惰, 终结操作 eager 迫切)*/Stream<Integer> s1 = Stream.of(1, 3, 5); // 水滴// -----------------------------------    -------------------------  阀门s1.map(x -> x + 1)                        // 水管.filter(x -> x <= 5)                    // 水管.forEach(x -> System.out.println(x));   // 水管 总阀门}
}

《stream.html》

16. 并行

// 并行流
public class C16Parallel {public static void main(String[] args) {/*List<Integer> collect = Stream.of(1, 2, 3, 4).collect(Collector.of(() -> {System.out.printf("%-12s %s%n",simple(),"create");return new ArrayList<Integer>();},(list, x) -> {List<Integer> old = new ArrayList<>(list);list.add(x);System.out.printf("%-12s %s.add(%d)=>%s%n",simple(), old, x, list);},(list1, list2) -> {List<Integer> old = new ArrayList<>(list1);list1.addAll(list2);System.out.printf("%-12s %s.add(%s)=>%s%n", simple(),old, list2, list1);return list1;},list -> null,Collector.Characteristics.IDENTITY_FINISH));*//*1) 数据量问题: 数据量大时才建议用并行流2) 线程会无限增加吗: 跟 cpu 能处理的线程数相关3) 收尾的意义: 转不可变集合、StringBuilder 转 String ...4) 是否线程安全: 不会有线程安全问题5) 特性:是否需要收尾(默认收尾)是否需要保证顺序(默认保证)容器是否支持并发(默认不需要支持)到达选择哪一种?A. Characteristics.CONCURRENT + Characteristics.UNORDERED + 线程安全容器  并发量大性能可能会受影响B. 默认 + 线程不安全容器                                                   占用内存多,合并多也会影响性能*/List<Integer> collect = Stream.of(1, 2, 3, 4).parallel().collect(Collector.of(() -> {System.out.printf("%-12s %s%n", simple(), "create");return new Vector<Integer>();},                                                                          // 1.如何创建容器(list, x) -> {List<Integer> old = new ArrayList<>(list);list.add(x);System.out.printf("%-12s %s.add(%d)=>%s%n", simple(), old, x, list);},                                                                          // 2.如何向容器添加数据(list1, list2) -> {List<Integer> old = new ArrayList<>(list1);list1.addAll(list2);System.out.printf("%-12s %s.add(%s)=>%s%n", simple(), old, list2, list1);return list1;},                                                                          // 3.如何合并两个容器的数据list -> {System.out.printf("%-12s finish: %s=>%s%n", simple(), list, list);return Collections.unmodifiableList(list);}                                                                           // 4.收尾, Collector.Characteristics.IDENTITY_FINISH                                 // 不需要收尾, Collector.Characteristics.UNORDERED                                       // 不需要保证顺序, Collector.Characteristics.CONCURRENT                                      // 容器需要支持并发));System.out.println(collect);collect.add(100);System.out.println(collect);}private static String simple() {String name = Thread.currentThread().getName();int idx = name.indexOf("worker");if (idx > 0) {return name.substring(idx);}return name;}
}

17. 效率

17.1 数组求和

其中

  • primitive 用 loop 循环对 int 求和
  • intStream 用 IntStream 对 int 求和
  • boxed 用 loop 循环对 Integer 求和
  • stream 用 Stream 对 Integer 求和

元素个数 100

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
T01Sum.primitiveavgt525.424± 0.782ns/op
T01Sum.intStreamavgt547.482± 1.145ns/op
T01Sum.boxedavgt572.457± 4.136ns/op
T01Sum.streamavgt5465.141± 4.891ns/op

元素个数 1000

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
T01Sum.primitiveavgt5270.556± 1.277ns/op
T01Sum.intStreamavgt5292.467± 10.987ns/op
T01Sum.boxedavgt5583.929± 57.338ns/op
T01Sum.streamavgt55948.294± 2209.211ns/op

元素个数 10000

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
T01Sum.primitiveavgt52681.651± 12.614ns/op
T01Sum.intStreamavgt52718.408± 52.418ns/op
T01Sum.boxedavgt56391.285± 358.154ns/op
T01Sum.streamavgt544414.884± 3213.055ns/op

结论:

  • 做数值计算,优先挑选基本流(IntStream 等)在数据量较大时,它的性能已经非常接近普通 for 循环
  • 做数值计算,应当避免普通流(Stream)性能与其它几种相比,慢一个数量级
// 性能:求和
public class T01Sum {@State(Scope.Benchmark)public static class MyState {public static final int COUNT = 10000;public int[] numbers = new int[COUNT];public List<Integer> numberList = new ArrayList<>(COUNT);public MyState() {for (int i = 0; i < COUNT; i++) {int x = i + 1;numbers[i] = x;numberList.add(i, x);}}}@Benchmark@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)public int primitive(MyState state) {int sum = 0;for (int number : state.numbers) {sum += number;}return sum;}@Benchmark@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)public int boxed(MyState state) {int sum = 0;for (Integer i : state.numberList) {sum += i;}return sum;}@Benchmark@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)public int stream(MyState state) {return state.numberList.stream().reduce(0, (a, b) -> a + b);}@Benchmark@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)public int intStream(MyState state) {return IntStream.of(state.numbers).sum();}public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(T01Sum.class.getSimpleName()).forks(1).build();new Runner(opt).run();//        MyState state = new MyState();
//        T01Sum test = new T01Sum();
//        System.out.println(test.primitive(state));
//        System.out.println(test.boxed(state));
//        System.out.println(test.stream(state));
//        System.out.println(test.intStream(state));}
}

17.2 求最大值

其中(原始数据都是 int,没有包装类)

  • custom 自定义多线程并行求最大值
  • parallel 并行流求最大值
  • sequence 串行流求最大值
  • primitive loop 循环求最大值

元素个数 100

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
T02Parallel.customavgt539619.796± 1263.036ns/op
T02Parallel.parallelavgt56754.239± 79.894ns/op
T02Parallel.primitiveavgt529.538± 3.056ns/op
T02Parallel.sequenceavgt580.170± 1.940ns/op

元素个数 10000

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
T02Parallel.customavgt541656.093± 1537.237ns/op
T02Parallel.parallelavgt511218.573± 1994.863ns/op
T02Parallel.primitiveavgt52217.562± 80.981ns/op
T02Parallel.sequenceavgt55682.482± 264.645ns/op

元素个数 1000000

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
T02Parallel.customavgt5194984.564± 25794.484ns/op
T02Parallel.parallelavgt5298940.794± 31944.959ns/op
T02Parallel.primitiveavgt5325178.873± 81314.981ns/op
T02Parallel.sequenceavgt5618274.062± 5867.812ns/op

结论:

  • 并行流相对自己用多线程实现分而治之更简洁
  • 并行流只有在数据量非常大时,才能充分发力,数据量少,还不如用串行流

17.3 并行(发)收集

元素个数 100

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
loop1avgt51312.389± 90.683ns/op
loop2avgt51776.391± 255.271ns/op
sequenceavgt51727.739± 28.821ns/op
parallelNoConcurrentavgt527654.004± 496.970ns/op
parallelConcurrentavgt516320.113± 344.766ns/op

元素个数 10000

BenchmarkModeCntScore (ns/op)Error (ns/op)Units
loop1avgt5211526.546± 13549.703ns/op
loop2avgt5203794.146± 3525.972ns/op
sequenceavgt5237688.651± 7593.483ns/op
parallelNoConcurrentavgt5527203.976± 3496.107ns/op
parallelConcurrentavgt5369630.728± 20549.731ns/op

元素个数 1000000

BenchmarkModeCntScore (ms/op)Error (ms/op)Units
loop1avgt569.154± 3.456ms/op
loop2avgt583.815± 2.307ms/op
sequenceavgt5103.585± 0.834ns/op
parallelNoConcurrentavgt5167.032± 15.406ms/op
parallelConcurrentavgt552.326± 1.501ms/op

结论:

  • sequence 是一个容器单线程收集,数据量少时性能占优
  • parallelNoConcurrent 是多个容器多线程并行收集,时间应该花费在合并容器上,性能最差
  • parallelConcurrent 是一个容器多线程并发收集,在数据量大时性能较优

17.4 MethodHandle 性能

正常方法调用、反射、MethodHandle、Lambda 的性能对比

BenchmarkModeCntScoreErrorUnits
Sample2.lambdathrpt5389307532.881± 332213073.039ops/s
Sample2.methodthrpt5157556577.611± 4048306.620ops/s
Sample2.originthrpt5413287866.949± 65182730.966ops/s
Sample2.reflectionthrpt591640751.456± 37969233.369ops/s

18. 综合练习

  1. 将 filter 的课堂例题修改为方法引用方式实现

  2. takeWhile 与 filter 的区别

  3. 三级排序

  4. 包含 null 值的排序

  5. 二维流扁平映射

  6. 三维流扁平映射

  7. 用 stream 打印九九乘法表

  8. 用 stream 生成斐波那契数列的前 10 项

    Stream.iterate(new int[]{1, 1}, x -> new int[]{x[1], x[0] + x[1]}).map(x -> x[0]).limit(10)
    
  9. 自定义 Collector 求平均

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19347.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nacos 2.x 系列【13】服务权重管理

文章目录 1. 概述2. 负载均衡器3. 配置权重4. 案例演示4.1 环境搭建4.2 默认权重4.3 权重值为零4.4 权重不一样 1. 概述 Nacos服务管理模块&#xff0c;提供了服务权重管理功能&#xff0c;用于给服务实例设置权重&#xff0c;权重越高&#xff0c;被分配的流量越大&#xff0…

Altium Designer软件下载安装「专业PCB设计软件」Altium Designer安装包获取!

Altium Designer&#xff0c;这款软件凭借其全面的设计流程覆盖&#xff0c;从概念到实现&#xff0c;都能为电子工程师提供强大的支持。 在硬件设计方面&#xff0c;Altium Designer提供了丰富的元件库和灵活的布局选项&#xff0c;使得工程师能够轻松地进行电路设计&#xff…

uniapp登录成功后跳回原有页面+无感刷新token

uniapp登录成功后跳回原有页面 引言 在C端的页面场景中&#xff0c;我们经常会有几种情况到登录页&#xff1a; 区分需要登录和不用登录的页面&#xff0c;点击需要登录才能查看的页面 已经登录但是超时&#xff0c;用户凭证失效等原因 以上情况可以细分为两种&#xff0c;一…

单片机/嵌入式小白教程—硬件(三)51单片机最小系统

目录 简介 51单片机器件原理图 复位电路 供电电路 晶振电路 下载电路 最小系统原理图 更加方便的51单片机 简介 传统51单片机最小系统包含&#xff1a;复位电路、供电电路、晶振电路、下载电路 51单片机器件原理图 其中&#xff0c; 第9脚&#xff08;RST&#xff09;…

DOM型XSS

前言 什么是DOM型XSS DOM型XSS漏洞是一种特殊类型的XSS,是基于文档对象模型 Document Object Model (DOM)的一种漏洞。 什么是DOM DOM全称Document Object Model,是一个与平台、编程语言无关的接口&#xff0c;它允许程序或脚本动态地访问和更新文档内容、结构和样式&#xff0…

橙派探险记:开箱香橙派 AIpro 与疲劳驾驶检测的奇幻之旅

目录 引子&#xff1a;神秘包裹的到来 第一章&#xff1a;香橙派AIpro初体验 资源与性能介绍 系统烧录 Linux 镜像&#xff08;TF 卡&#xff09; 调试模式 登录模式 第二章&#xff1a;大胆的项目构想 系统架构设计 香橙派 AIpro 在项目中的重要作用 第三章&#xf…

[Redis]String类型

基本命令 set命令 将 string 类型的 value 设置到 key 中。如果 key 之前存在&#xff0c;则覆盖&#xff0c;无论原来的数据类型是什么。之前关于此 key 的 TTL 也全部失效。 set key value [expiration EX seconds|PX milliseconds] [NX|XX] 选项[EX|PX] EX seconds⸺使用…

苏州金龙新V系客车科技助力“粤”动广州

粤动活力新V系&#xff01; 5月23日&#xff0c;苏州金龙新V系智慧客车推介会在羊城广州举行。活动现场展出了4款新V系代表车型&#xff0c;来自广东省旅游客运、道路运输行业的200余位从业者齐聚一堂&#xff0c;共同品鉴、体验了苏州金龙新V系产品的“新、心、芯”魅力。苏州…

如何降本增效获得目标客户?AI企业使用联盟营销这个方法就对了!

AI工具市场正在迅速发展&#xff0c;现仍有不少企业陆续涌出&#xff0c;那么如何让你的工具受到目标群体的关注呢&#xff1f;这相比是AI工具营销人员一直在思考的问题。 为什么AI企业难以获客呢&#xff1f; 即使这个市场正蓬勃发展&#xff0c;也无法保证营销就能轻易成功…

英语学习笔记29——Come in, Amy!

Come in, Amy! 进来&#xff0c;艾米&#xff01; shut v. 关严 区别&#xff1a;shut the door 把门关紧 口语&#xff1a;Shut up! 闭嘴&#xff01;    态度强硬&#xff0c;不礼貌 例句&#xff1a;请不要把门关严。    Don’t shut the door, please. bedroom n. …

STM32-12-OLED模块

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 文章目录 1. OLED显示屏介绍2. OLED驱动原理3. OLED驱动芯片简介4…

一年收入大几十个的副业兼职,闲鱼新玩法,新手小白可做,无门槛

在开始分享之前&#xff0c;我想先了解一下&#xff0c;大家是否曾在各大公众号上参与过各种打卡活动&#xff1f;比如减肥打卡、英语阅读打卡、考研考公打卡等等。如今&#xff0c;打卡已经成为现代人生活中不可或缺的一部分。无论是学习、健身还是工作&#xff0c;打卡都能有…

MGR集群模拟故障切换

说明&#xff1a; 1、MGR集群搭建起来&#xff0c;但不知道是否能进行启动切换&#xff0c;故要手动模拟故障并且验证 2、停止主库master服务&#xff0c;登录mysql查看MGR是否进行自动切换。 3、主库切换完成以后&#xff0c;手动将宕机的服务器添加到MGR集群中。 一、模拟故障…

2024年3月电子学会青少年软件编程 中小学生Python编程等级考试一级真题解析(选择题)

2024年3月Python编程等级考试一级真题解析 选择题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 1、下列哪个命令&#xff0c;可以将2024转换成2024呢 A、str(2024) B、int(2024) C、float(2024) D、bool(2024) 答案&#xff1a;A 考点分析&…

C#解析JSON的常用库--Newtonsoft.Json

一、库介绍 在C#中&#xff0c;解析JSON的常用库有Newtonsoft.Json&#xff08;也称为Json.NET&#xff09;和 System.Text.Json&#xff08;从 .NET Core 3.0 开始引入&#xff09;。本文主要介绍 Newtonsoft.Json。 二、下载 官网&#xff1a; https://www.nuget.org/pack…

使用 retrievers 在 Elasticsearch 中进行语义重新排序

作者&#xff1a;来自 Elastic Adam Demjen, Nick Chow 什么是语义重新排序&#xff1f; 语义重新排序&#xff08;semantic reranking&#xff09;是一种方法&#xff0c;它允许我们利用快速检索方法的速度和效率&#xff0c;同时在其上分层语义搜索。它还允许我们立即将语义…

【Python】解决Python报错:TypeError: %d format: a number is required, not str

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

STM32定时器及输出PWM完成呼吸灯

文章目录 一、STM32定时器原理1、基本定时器2、通用定时器&#xff08;1&#xff09;时钟源&#xff08;2&#xff09;预分频器PSC&#xff08;3&#xff09;计数器CNT&#xff08;4&#xff09;自动装载寄存器ARR 3、高级定时器 二、PWM工作原理三、控制LED以2s的频率周期性地…

CyberDAO M级共识交流会·西安站圆满落幕:共筑Web3美好未来

CyberDAO M级共识交流会于2024年5月28日在西安隆重举行&#xff0c;这是一场CyberDAO精英汇聚的盛会&#xff0c;以同心共筑&#xff0c;志在必达为主题口号与DAO精英携手并进&#xff0c;共筑CyberDAO美好宏图。CyberDAO的使命是降低WEB3的门槛&#xff0c;帮助用户轻松抓住行…

【微服务】springboot 构建docker镜像多模式使用详解

目录 一、前言 二、微服务常用的镜像构建方案 3.1 使用Dockerfile 3.2 使用docker plugin插件 3.3 使用docker compose 编排文件 三、环境准备 3.1 服务器 3.2 安装JDK环境 3.2.1 创建目录 3.2.2 下载安装包 3.2.3 配置环境变量 2.2.4 查看java版本 3.3 安装maven …