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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 12:49:55  来源:igfitidea点击:

Convert Stream to IntStream

javajava-8java-stream

提问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 Streamto IntStreamvia the mapToInt(Integer::intValue)

我的问题是从StreamIntStream通过的愚蠢转换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 Comparatorbut the question is specifically on the convertion of Streamto IntStream

有没有更好的转换方法?所有这些都是为了避免使用max()from Stream,这需要传递 aComparator但问题是专门针对Streamto的转换IntStream

采纳答案by Holger

Due to type erasure, the Streamimplementation has no knowledge about the type of its elements and can't provide you with neither, a simplified maxoperation nor a conversion to IntStreammethod.

由于类型擦除,Stream实现不知道其元素的类型,因此无法为您提供简化的max操作或转换为IntStream方法。

In both cases it requires a function, a Comparatoror 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 Streamimplementation ifthere is any optimization regarding Comparableelements. 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 Streamto an IntStreamthere is no way around providing a ToIntFunctionand there is no predefined singleton for a Number::intValuekind of function, so using Integer::intValueis already the best choice. You could write i->iinstead, 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 Streaminterface at the same time".

如果问题是“我可以避免在从Stream<T>to转换时传递转换器IntStream吗?” 一个可能的答案可能是“在 Java 中没有办法使这种转换类型安全并同时使其成为Stream接口的一部分”。

Indeed method which converts Stream<T>to IntStreamwithout 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) }
}