Java Stream 减少泛型类型的 ArrayList
Posted
技术标签:
【中文标题】Java Stream 减少泛型类型的 ArrayList【英文标题】:Java Stream reduce ArrayList of generic types 【发布时间】:2021-07-16 00:58:32 【问题描述】:我有一个名为“Catalog”的文章(通用类型)的 ArrayList。
一篇文章有以下方法:
public int getUnitsInStore()
public long getUnitPrice()
为了获得目录中所有文章的总价值,我尝试使用 Java Stream Api 的 Reduce 方法。
我尝试了以下操作:
long value = 0;
value = catalog.stream().reduce((a,b) -> a.getUnitPrice()*b.getUnitsInStore());
但这给了我错误:
Type mismatch: cannot convert from Optional<Article> to long
我做错了什么?
【问题讨论】:
阅读reduce
的文档:它会告诉您 a 和 b 是什么类型,以及它们究竟代表什么。
您的代码毫无意义。为什么要将一篇文章的价格乘以一篇完全不同文章的单位数?听起来你需要的是long total = catalog.stream().mapToLong(a -> a.getUnitPrice() * a.getUnitsInStore()).sum()
@Andreas:是的,现在我知道了。感谢您的评论。这很有帮助
【参考方案1】:
累加器 lambda 中的 a
和 b
分别是流中的部分结果和下一个元素。由于您正在减少文章列表,因此部分结果是文章,您不能在文章中添加 Long。
所以在你的情况下,你可能想做这样的事情。
value = catalog.stream()
.map(a -> a.getUnitPrice() * a.getUnitsInStore())
.reduce(0L, Long::sum);
【讨论】:
非常感谢。知道我明白.mapToLong(...).sum()
可能效率更高。【参考方案2】:
reduce 方法分为三种类型。 试试这段代码以更好地理解它
/**
* T reduce(T identity, BinaryOperator<T> accumulator)
*
* identity = initial value
* accumulator = first process initial value to first element of the stream,
* then process the result with the next element in the stream
*/
String name = Stream.of("T", "O", "M", "M", "Y")
.reduce("", (a,n) -> a + n);
System.out.println(name);
int sum = Stream.of(1,2,3,4,5,6,7,8,9,10)
.reduce(0, (a,n) -> a + n);
System.out.println(sum);
int multi = Stream.of(1,2,3,4,5,6,7,8,9,10)
.reduce(1, (a,n) -> a * n);
System.out.println(multi);
/**
* Optional<T> reduce(BinaryOperator<T> accumulator)
*
*/
Optional<String> optName = Stream.of("T", "O", "M", "M", "Y")
.reduce((a,n) -> a + n);
if(optName.isPresent())
System.out.println(" get from optional --> " + optName.get());
/**
* <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
*
* This method signature is used when we are dealing with different types.
* It allows Java to create intermediate reductions and then combine them at the end.
*/
int total = Stream.of("R", "a", "z", "v", "a", "n")
.reduce(0, (a,b) -> a + b.length(), (x,y) -> x + y);
// 0 = initial value type int
// a = int, must match the identity type
// b.method() return type must match the a and the identity type
// x,y from BinaryOperator
System.out.println(total);
String names[] = "Bobby", "Mark", "Anthony", "Danna";
int sumAll = Stream.of(names)
.reduce(0, (a,b) -> a + b.length(), (x,y) -> x + y);
System.out.println(sumAll);
String csvNames = Stream.of(names)
.reduce("", (a,b) -> a + b + ";");
System.out.println(csvNames);
【讨论】:
非常感谢。这真的很有帮助 第三个可能有点棘手,但试试看 3 参数示例非常糟糕,因为使用int total = Stream.of("R", "a", "z", "v", "a", "n").mapToInt(String::length).sum()
会更好地实现。 3 参数版本不仅仅用于执行 map()
操作,它在结果确实是不同类型时使用,例如Collection
对象或用于收集多个结果(例如最小值、最大值和平均值)的 stats 对象。【参考方案3】:
我建议您使用 Stream.reduce()
重载,它需要两个参数:
因此,您将通过以下方式获得价值:
value = catalog
.stream()
.reduce(0L, (partialSum, nextElement) -> partialSum + nextElement.getUnitPrice() * nextElement.getUnitsInStore());
【讨论】:
Stream.reduce()
方法需要 1、2 或 3 个参数,具体取决于使用的重载。问题是尝试使用 1 参数版本。如果您愿意,您可以suggest 改用 2 参数版本,并解释您为什么建议这样做,但这不是这个答案的作用,所以它不是一个有用的答案。
没错。在我看来,最好的选择是带有 2 个参数的那个,所以 OP 可以定义初始值。我将更新答案以澄清 其中一个重载需要两个 args以上是关于Java Stream 减少泛型类型的 ArrayList的主要内容,如果未能解决你的问题,请参考以下文章