java 将流转换为 IntStream
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28015278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert Stream to IntStream
提问by Hilikus
I have a feeling I'm missing something here. I found myself doing the following
我有一种感觉,我在这里错过了一些东西。我发现自己做了以下事情
private static int getHighestValue(Map<Character, Integer> countMap) {
return countMap.values().stream().mapToInt(Integer::intValue).max().getAsInt();
}
My problem is with the silly conversion from Stream
to IntStream
via the mapToInt(Integer::intValue)
我的问题是从Stream
到 IntStream
通过的愚蠢转换mapToInt(Integer::intValue)
Is there a better way of doing the conversion? all this is to avoid using max()
from Stream
, which requires passing a Comparator
but the question is specifically on the convertion of Stream
to IntStream
有没有更好的转换方法?所有这些都是为了避免使用max()
from Stream
,这需要传递 aComparator
但问题是专门针对Stream
to的转换IntStream
采纳答案by Holger
Due to type erasure, the Stream
implementation has no knowledge about the type of its elements and can't provide you with neither, a simplified max
operation nor a conversion to IntStream
method.
由于类型擦除,Stream
实现不知道其元素的类型,因此无法为您提供简化的max
操作或转换为IntStream
方法。
In both cases it requires a function, a Comparator
or a ToIntFunction
, respectively, to perform the operation using the unknown reference type of the Stream
's elements.
在这两种情况下,它分别需要一个函数 aComparator
或 aToIntFunction
来使用Stream
的元素的未知引用类型执行操作。
The simplest form for the operation you want to perform is
您要执行的操作的最简单形式是
return countMap.values().stream().max(Comparator.naturalOrder()).get();
given the fact that the natural ordercomparator is implemented as a singleton. So it's the only comparator which offers the chance of being recognized by the Stream
implementation ifthere is any optimization regarding Comparable
elements. If there's no such optimization, it will still be the variant with the lowest memory footprint due to its singleton nature.
鉴于自然顺序比较器是作为单例实现的。因此,如果对元素有任何优化,它是唯一提供被Stream
实现识别的机会的比较器。如果没有这样的优化,由于其单例特性,它仍然是具有最低内存占用的变体。Comparable
If you insist on doing a conversion of the Stream
to an IntStream
there is no way around providing a ToIntFunction
and there is no predefined singleton for a Number::intValue
kind of function, so using Integer::intValue
is already the best choice. You could write i->i
instead, which is shorter but just hiding the unboxing operation then.
如果您坚持将 the 转换Stream
为 an IntStream
,则无法提供 aToIntFunction
并且没有为Number::intValue
某种函数预定义的单例,因此 usingInteger::intValue
已经是最佳选择。你可以改写i->i
,它更短,但只是隐藏了拆箱操作。
回答by Todd
I realize you are trying to avoid a comparator, but you could use the built-in for this by referring to Integer.compareTo
:
我意识到您正试图避免使用比较器,但您可以通过参考以下内容来使用内置的Integer.compareTo
:
private static int getHighestValue(Map<Character, Integer> countMap) {
return countMap.values().stream().max(Integer::compareTo).get();
}
Or as @fge suggests, using ::compare
:
或者如@fge 所建议的那样,使用::compare
:
private static int getHighestValue(Map<Character, Integer> countMap) {
return countMap.values().stream().max(Integer::compare).get();
}
回答by Alex
Another way you could do the conversion is with a lambda: mapToInt(i -> i)
.
Whether you should use a lambda or a method reference is discussed in detail here, but the summary is that you should use whichever you find more readable.
另一种可以进行转换的方法是使用 lambda: mapToInt(i -> i)
。此处详细讨论了您应该使用 lambda 还是方法引用,但总而言之,您应该使用您认为更具可读性的任何一个。
回答by Lu55
If the question is "Can I avoid passing converter while converting from Stream<T>
to IntStream
?" one possible answer might be "There is no way in Java to make such conversion type-safe and make it part of the Stream
interface at the same time".
如果问题是“我可以避免在从Stream<T>
to转换时传递转换器IntStream
吗?” 一个可能的答案可能是“在 Java 中没有办法使这种转换类型安全并同时使其成为Stream
接口的一部分”。
Indeed method which converts Stream<T>
to IntStream
without a converter might be looked like this:
不使用转换器转换Stream<T>
为的Indeed 方法IntStream
可能如下所示:
public interface Stream<T> {
// other methods
default IntStream mapToInt() {
Stream<Integer> intStream = (Stream<Integer>)this;
return intStream.mapToInt(Integer::intValue);
}
}
So it suppose to be called on Stream<Integer>
and will fail on other types of streams. But because streams are lazy evaluated and because of the type erasure (remember that Stream<T>
is generic) code will fail at the place where stream is consumed which might be far from the mapToInt()
call. And it will fail in a way that is extremely difficult to locate source of the problem.
所以它假设被调用Stream<Integer>
并且会在其他类型的流上失败。但是因为流是惰性求值的,并且因为类型擦除(记住这Stream<T>
是通用的),代码将在流被消耗的地方失败,这可能远离mapToInt()
调用。并且它会以一种极难定位问题根源的方式失败。
Suppose you have code:
假设你有代码:
public class IntStreamTest {
public static void main(String[] args) {
IntStream intStream = produceIntStream();
consumeIntStream(intStream);
}
private static IntStream produceIntStream() {
Stream<String> stream = Arrays.asList("1", "2", "3").stream();
return mapToInt(stream);
}
public static <T> IntStream mapToInt(Stream<T> stream) {
Stream<Integer> intStream = (Stream<Integer>)stream;
return intStream.mapToInt(Integer::intValue);
}
private static void consumeIntStream(IntStream intStream) {
intStream.filter(i -> i >= 2)
.forEach(System.out::println);
}
}
It will fail on consumeIntStream()
call with:
它会在consumeIntStream()
通话时失败:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:210)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateSequential(ForEachOps.java:189)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.IntPipeline.forEach(IntPipeline.java:404)
at streams.IntStreamTest.consumeIntStream(IntStreamTest.java:25)
at streams.IntStreamTest.main(IntStreamTest.java:10)
Having this stacktrace do you able to quickly identify that the problem is in produceIntStream()
because mapToInt()
was called on the stream of the wrong type?
有了这个堆栈跟踪,您是否能够快速确定问题所在,produceIntStream()
因为mapToInt()
在错误类型的流上调用了?
Of course one can write converting method which is type safe because it accepts concrete Stream<Integer>
:
当然,可以编写类型安全的转换方法,因为它接受具体的Stream<Integer>
:
public static IntStream mapToInt(Stream<Integer> stream) {
return stream.mapToInt(Integer::intValue);
}
// usage
IntStream intStream = mapToInt(Arrays.asList(1, 2, 3).stream())
but it's not very convenient because it breaks fluent interface nature of the streams.
但这不是很方便,因为它破坏了流的流畅界面特性。
BTW:
顺便提一句:
Kotlin's extension functions allow to call some code as it is a part of the class' interface. So you are able to call this type-safe method as a Stream<java.lang.Integer>
's method:
Kotlin 的扩展函数允许调用一些代码,因为它是类接口的一部分。因此,您可以将此类型安全的方法称为 aStream<java.lang.Integer>
的方法:
// "adds" mapToInt() to Stream<java.lang.Integer>
fun Stream<java.lang.Integer>.mapToInt(): IntStream {
return this.mapToInt { it.toInt() }
}
@Test
fun test() {
Arrays.asList<java.lang.Integer>(java.lang.Integer(1), java.lang.Integer(2))
.stream()
.mapToInt()
.forEach { println(it) }
}