代码之家  ›  专栏  ›  技术社区  ›  OddDragon

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

  •  3
  • OddDragon  · 技术社区  · 6 年前

    对于流对象,是否不能使用collect方法写入将收集到另一个流对象的自定义收集器对象?我最近刚刚学习了关于流的知识,正试图获得尽可能多的使用流的经验,我遇到了这个问题。

    我的代码是:

        // 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方法对于流中的第一个字符串运行良好,但在第二次到达IntStream时运行良好。concat(s1,cs)我得到以下异常:

    JAVAlang.IllegalStateException:流已被操作或关闭

    我对此的解释是,一旦我的第一个字符串转换为IntStream,并且collect方法移动到下一个字符串,我的第一个IntStream就会关闭。对吗?为什么会发生这种情况?

    这是我为自己发明的一个练习,旨在获得更多的流和函数编程经验。我知道这可能不是编写此方法的最佳方式。我感兴趣的是知道为什么这不起作用,而不是我可以采取的其他方法。

    1 回复  |  直到 6 年前
        1
  •  4
  •   Sweeper    6 年前

    通过调用 concat ,你没有变异 s1 康卡特 退货 连接的流。首先,流是不可变的。

    这意味着 Stream.empty 您从never changed开始,它用于 康卡特 方法一次又一次。然而,你 不能 在中使用流 康卡特 两次这算是“在溪流上操作”。因此,当您第二次尝试这样做时,您得到了一个非法的状态异常,如文档所示:

    应操作流(调用中间或终端 流操作)仅一次。例如,这排除了“分叉” 流,其中同一个源为两条或多条管道供水,或 同一流的多次遍历。流实现可以 如果检测到流正在 重复使用。然而,由于某些流操作可能返回 接收方而不是新的流对象,可能无法 在所有情况下检测重用。

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

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

    flatMap 可能是你想通过收集数据流来实现的。现在你知道这叫做 平面图