流API--缩减操作

本文介绍了Java8 Stream流API中的缩减操作,包括min(), max(), count()等特例缩减,以及reduce()方法的三种重载形式。通过示例代码详细解释了reduce方法在累加、组合过程中的应用,强调了累加器操作需满足无状态、不干预和结合性的要求,并展示了如何处理不同类型累加结果的情况。" 81388790,7631842,MUI实现缩放式侧滑导航,"['前端开发', 'HTML', 'CSS', 'JavaScript', 'MUI框架', 'APP组件']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Stream流操作中,比如说min(),max(),count()方法,这几个操作都会将一个流缩减成一个值,流API将这些操作称为特例缩减。另外,流API同时泛华了缩减这种概念,提供了reduce()方法,通过使用reduce()方法,可以基于任意条件,从流中返回一个值。根据定义,所有缩减操作都是终端操作。
我们先来翻下api:
Optional<T>	reduce(BinaryOperator<T> accumulator) :Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any. 
T 		reduce(T identity, BinaryOperator<T> accumulator) :Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. 
<U> U 		reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner):Performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions. 

先来看一段代码演示下如果对一个流做缩减操作:
public static void main(String[] args) throws Exception
	{
		List<Integer> list = new ArrayList<>(4);
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		//reduce第一个重载,直接进行缩减
		list.stream().reduce((a, b) -> a + b).ifPresent(System.out::println);
		//reduce第二个重载,可以指定初始值,然后在进行缩减
		System.out.println(list.stream().reduce(0, Integer::sum));
		//reduce第三个重载,可以指定初始值,然后在进行缩减,第3个参数用来处理并行流的操作
		System.out.println(list.stream().reduce(0, (a, b) -> a * 2 + b, (c, d) -> c + d));
		List<String> list1 = Lists.newArrayList("1", "2", "3", "4");
		System.out.println(list1.stream().reduce(1, (a, b) -> a + b.length(), (c, d) -> c + d));
	}

这里我们重点要看下前面2个方法:
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
第一个方法返回一个Optional对象,该对象包含了结果。第二个方法直接返回T类型的对象,这里的这个T类型就是流中元素的类型。在使用这2个方法的时候,要传入一个Lambda表达式,这个表达式要实现BinaryOperator<T>函数式接口,先说下这个接口吧:具体的可以去看我前面有篇博客的,这些函数式接口很容易忘掉了,我晕。
public interface BinaryOperator<T> extends BiFunction<T,T,T> {}
这个函数式接口扩展了BiFunction<T,T,T> 接口,这里只不过赋值方法的参数是同一个类型,然后返回值也是同一个类型而已。对于,BinaryOperator<T> 来说,apply方法现在变成了如下方法:
T apply(T val, T value);其中val将包含前一个结果,然后value包含下一个元素。我们在调用reduce的时候,val将包含单位初始值或者第一个元素。在上面2个方法中,第一个方法将包含第一个元素,第二个方法将包含单位值。


注意:
累加器操作必须满足以下3个约束:
1,无状态
2,不干预
3,结合性
无状态意味着操作不依赖于任何状态信息,不干预意味着操作不会改变数据源,最后操作必须具有关联性。这里的关联性可以理解为加法结合律或者乘法结合律,举个例子,(a+b)+c=a+(b+c);


最后这里整理下reduce的第3个重载方法:
reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)。
考虑如下情景:假设我们现在有一个包含多个对象的流,并且希望对他们的某个属性进行求和。例如求一个流中的所有字符串的总长度,这个时候我们没有办法用上面的2个reduce的重载,因为上面2个方法中需要一个(T,T)->T这样子的函数式接口,但是这里这2个类型是不同的,流中的元素是String的,但是累加的结果是整型的。对于这种情况,我们只能使用重载的第3个方法了。
public static void main(String[] args)
	{
		Stream<String> of = Stream.of("张飞", "关羽");
		//一下代码报错,类型不匹配The method reduce(String, BinaryOperator<String>) in the type Stream<String> 
		//is not applicable for the arguments (int, BinaryOperator<String>)
		of.reduce(0, (a, b) -> a + b.length());
		System.out.println(of.reduce(0, (a, b) -> a + b.length(), Integer::sum));
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值