Java8:使用IntStream作为自定义收集器的供应商参数

时间:2018-05-03 15:54:21

标签: java java-8 functional-programming java-stream collectors

对于流对象,是否无法使用collect方法编写将收集到另一个流对象的自定义Collector对象?我刚刚学到了关于流的知识,并且我试图尽可能多地获得它们的经验,我遇到了这个问题。

我的代码是:

    // method to return how many unique letters are used in
    // the Strings in the given stream
    public int uniqueLetters(Stream<String> stream){
        // transfer Strings to an uppercase char stream
        IntStream allLets = stream.collect(IntStream::empty, 
                          (s1, s2) -> { String toAdd = s2.toUpperCase();
                                        IntStream cs = toAdd.chars();
                                        IntStream.concat(s1, cs); //exception thrown on this line
                                       }, IntStream::concat); 
        // use distinct on char stream and count
        return (int) allLets.distinct().count();
    }

此代码编译并且collect方法对流中的第一个String运行正常,但第二次到达IntStream.concat(s1,cs)时出现以下异常:

  

java.lang.IllegalStateException:stream已经被操作或关闭

我解释这个的方式是,一旦我的第一个String转换为IntStream并且collect方法移动到下一个String,我的第一个IntStream就会被关闭。那是对的吗?为什么会这样?

这是我为自己发明的练习,试图获得更多关于流和函数式编程的经验。我知道这可能不是编写这种方法的最佳方法。我有兴趣知道为什么这不起作用,而不是我采取的其他方法。

1 个答案:

答案 0 :(得分:4)

通过致电concat,您不会改变s1concat 返回连接流。 Streams首先不是可变的。

这意味着您开始的Stream.empty从未更改,并且一次又一次地在concat方法中使用它。但是,您无法concat中使用两次流。这算作“在流上运作”。因此,当您第二次尝试执行此操作时,您会收到非法状态异常,如下所示:

  

应该操作流(调用中间或终端   流操作)只有一次。这排除了,例如,“分叉”   流,相同的源提供两个或多个管道,或   多次遍历同一个流。流实现可以   如果它检测到正在流,则抛出IllegalStateException   重复使用。但是,由于某些流操作可能会返回它们   接收器而不是新的流对象,它可能是不可能的   在所有情况下检测重用。

要解决查找唯一字符的问题,您无需收集到流。就这样做:

public static int uniqueLetters(Stream<String> stream){
    return (int)stream.flatMapToInt(String::chars).distinct().count();
}

flatMap可能是你通过收集流来尝试做的。现在你知道这叫做flatMap