首页 > 编程语言 >流式编程

流式编程

时间:2023-03-21 16:45:47浏览次数:38  
标签:reduce stream Collectors 累加器 编程 list 流式 collect

创建流

// Stream.of()
Stream.of("hello ", "world").forEach(System.out::print);

// 集合调用stream()方法创建流
List<Integer> list = Arrays.asList(1, 2, 3);
int sum = list.stream().mapToInt(x -> x + 1).sum();
System.out.println(sum);

// 随机数流
new Random(99)
    .ints(1, 10) //产生一个IntStream,并限制最小值和最大值
    .distinct()
    .boxed()//装箱,产生一个Stream<Integer>
    .limit(5)
    .sorted()
    .forEach(System.out::println);

// generate
// x-x-x-x-x
Stream.generate(() -> "x").limit(5).collect(Collectors.joining("-"))

// iterate
Stream.iterate(0, x -> x+1).skip(5).limit(10).forEach(System.out::println);

// Arrays.stream() 把数组转换为流
Arrays.stream(new String[]{"a", "b", "c"}, 0, 2).collect(Collectors.toList())

// 正则
Pattern.compile("\\d").splitAsStream("a1b2c3d4").forEach(System.out::println);

// int long
IntStream.range(1, 5).sum();

中间操作

// 跟踪调试
peek()

// flatmap 扁平化流
List<List<String>> list = new ArrayList<List<String>>();
list.add(Arrays.asList("a", "b", "c"));
list.add(Arrays.asList("d", "e", "f"));

// 获取集合中的所有元素
List<String> all = new ArrayList<>();
for (List<String> temp : list) {
    for (String s : temp) {
        all.add(s);
    }
}
System.out.println(all);

// 一行搞定
List<String> collect = list.stream().flatMap(x -> x.stream()).collect(Collectors.toList());
System.out.println(collect);

// 输出
[a, b, c, d, e, f]
[a, b, c, d, e, f]

终端操作

// 数组
int[] arr1 = Stream.of("1", "2").mapToInt(x -> Integer.valueOf(x)).toArray();
String[] arr2 = Stream.of("1", "2").toArray(String[]::new);

// 集合
Stream.of("a", "b").collect(Collectors.toCollection(HashSet::new))
// tomap
Stream.of("a", "b").collect(Collectors.toMap(x -> x, x -> x + "_" + x))
// join
Stream.of("a", "b").collect(Collectors.joining("-", "[", "]"))
// 分组
Stream.of("a", "b").collect(Collectors.groupingBy(x -> x))

示例 list->map

// 收集字段
public Map<Long, String> getIdNameMap(List<Account> accounts) {
    return accounts.stream().collect(Collectors.toMap(Account::getId, Account::getUsername));
}

// 收集对象
public Map<Long, Account> getIdAccountMap(List<Account> accounts) {
    return accounts.stream().collect(Collectors.toMap(Account::getId, x-> x));
}

// 去除重复key
public Map<String, Account> getNameAccountMap(List<Account> accounts) {
    return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2));
}

示例 分组

# 按订单号分组
Order order1 = new Order();
order1.setOrderId("123");
Order1.setGoodsId("S1");
Order1.setSales(100);

Order order2 = new Order();
order2.setOrderId("123");
Order2.setGoodsId("S2");
Order2.setSales(200);

Order order3 = new Order();
order3.setOrderId("1234");
Order3.setGoodsId("S3");
Order3.setSales(300);

List<Order> list =  new ArrayList();
List.add(order1);
List.add(order2);
List.add(order3);

Map<String,List<Order>> map = list.stream().collect(Collectors.groupingBy(ord -> ord.getOrderId));

// 分组count
Map<String,Long> map = list.stream().collect(Collectors.groupingBy(Order::getOrderId,  Collectors.counting()));

// 分组平均
Map<String,Long> map = list.stream().collect(Collectors.groupingBy(Order::getOrderId,  Collectors.averagingInt(Order::getSales)));

// 分组求和
Map<String,Long> map = list.stream().collect(Collectors.groupingBy(Order::getOrderId,  Collectors.summingLong(Order::getSales)));

reduce

reduce是一种归约操作,将流归约成一个值的操作叫归约操作,将流中的元素通过调用累加器函数完成运算。

// 运算方式:将流中的第一个元素和第二个元素调用累加器函数进行运算,运算结果再与第三个元素调用累加器函数进行运算
// 结果类型:Optional,为了避免流中没有元素,出现空指针异常
Optional<T> reduce(BinaryOperator<T> accumulator);

// 运算方式:用初始值和流中的第一个元素调用累加器函数进行运算,运算结果再与第二个元素调用累加器函数进行运算
// 结果类型:因为带有初始值,所以结果不再是Optional,而是初始值的类型
T reduce(T identity, BinaryOperator<T> accumulator);

// 运算方式:用初始值和流中的第一个元素调用累加器函数进行运算,运算结果再与第二个元素调用累加器函数进行运算
// 结果类型:初始值的类型
// 参数三combiner(组合器)在串行流中没有作用,只在并行流中发挥作用。作用是把并行流中每个线程调用累加器(参数二accumulator)的计算结果进行合并
// 并行时要注意初始值的设定,因为初始值在每个线程中都参与运算,导致结果可能与预期结果不符,参考下面示例3
<U> U reduce(U identity,//初始值
                 BiFunction<U, ? super T, U> accumulator,// 累加器
                 BinaryOperator<U> combiner// 组合器
             );

// BiFunction定义
public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}
// BinaryOperator定义
public interface BinaryOperator<T> extends BiFunction<T,T,T>{
    // 继承了apply方法,但是输入参数和结果类型都是相同的
}

reduce示例1

// 一个参数
List<Integer> list = Arrays.asList(1, 2, 3, 4);
Optional<Integer> result1 = list.stream().reduce((a, b) -> a > b ? a : b);
Optional<Integer> result2 = list.stream().reduce(Integer::max);

// 两个参数
Integer result3 = list.stream().reduce(0, (a, b) -> a + b);
Integer result4 = list.stream().reduce(0, Integer::sum);

reduce示例2-串行

List<Integer> list = Arrays.asList(1, 2, 3, 4);
String result = list.stream()
    .reduce(
        // 初始值,初始值的类型决定了最终结果的类型
        "String: ", 
        // str对应U,与初始值类型保持一致。i对应T,是流中元素的类型Stream<T> 此处应该是Integer类型。str+i对应U,与初始值类型保持一致
        (str, i) -> str + i, 
        // str1,str2和返回值类型对应U,与初始值类型一致,因为在BinaryOperator中把参数和结果的类型已经统一成一种类型了。
        // 参数3在串行流中没有作用,可以随意写个返回值,但是类型必须与初始值类型相同
        (str1, str2) -> ""); 
// 结果:String: 1234

// 简单累加
Integer sum = list.stream().reduce(5, Integer::sum, Integer::sum);

reduce示例3-并行

List<Integer> list = Arrays.asList(1, 2, 3, 4);
Integer result = list.stream().parallel().reduce(5, Integer::sum, Integer::sum);
System.out.println(result);

// 结果为:30,与实际结果15不符。因为计算过程如下:
5+1=6
5+2=7
5+3=8
5+4=9
6+7+8+9=30

// 观察计算过程
List<Integer> list = Arrays.asList(1, 2, 3, 4);
Integer result = list.stream().parallel()
        .reduce(
                5,
                (x, y) -> {
                    int sum = x+y;
                    System.out.printf("[累加器]:%s,%d + %d = %d%n", Thread.currentThread().getName(), x, y, sum);
                    return sum;
                },
                (x, y) -> {
                    int sum = x+y;
                    System.out.printf("[组合器]:%s,%d + %d = %d%n", Thread.currentThread().getName(), x, y, sum);
                    return sum;
                });
System.out.println(result);
// 输出如下:
[累加器]:main,5 + 3 = 8
[累加器]:ForkJoinPool.commonPool-worker-25,5 + 2 = 7
[累加器]:ForkJoinPool.commonPool-worker-18,5 + 4 = 9
[累加器]:ForkJoinPool.commonPool-worker-4,5 + 1 = 6
[组合器]:ForkJoinPool.commonPool-worker-18,8 + 9 = 17
[组合器]:ForkJoinPool.commonPool-worker-4,6 + 7 = 13
[组合器]:ForkJoinPool.commonPool-worker-4,13 + 17 = 30
30

小结

调用这些函数时,参数的数量与类型比较绕,可以进入源码仔细分析函数式接口的参数数量与类型,仔细分析,再进行调用。

标签:reduce,stream,Collectors,累加器,编程,list,流式,collect
From: https://www.cnblogs.com/dylmys/p/stream.html

相关文章