【问题标题】:Why do I need to map IntStream to Stream<Character>为什么我需要将 IntStream 映射到 Stream<Character>
【发布时间】:2019-10-25 07:30:39
【问题描述】:
  public static int construction(String myString) {
      Set<Character> set = new HashSet<>();

      int count = myString.chars()  // returns IntStream
      .mapToObj(c -> (char)c)       // Stream<Character> why is this required?
      .mapToInt(c -> (set.add(c) == true ? 1 : 0)) // IntStream
      .sum();

      return count;
    }

如果没有以下代码,上述代码将无法编译:

.mapObj(c -> (char)c)
// <Character> Stream<Character> java.util.stream.IntStream.mapToObj(IntFunction<? extends Character> mapper)

如果我删除它,我会收到以下错误

The method mapToInt((<no type> c) -> {}) is undefined for the type IntStream

有人能解释一下吗?似乎我从 IntStream 开始,转换为字符流,然后返回 IntStream。

【问题讨论】:

  • 因为你的集合需要Characters
  • 问题仍然缺乏的一件事是您真正想要实现的目标是什么?
  • @naman,试图获取字符串中不同字符的计数。正如下面所指出的,我应该为此使用不同的流。

标签: java collections java-8 set java-stream


【解决方案1】:

方法CharSequence::chars返回的是IntStream,当然没有提供任何转换成int的方法,比如mapToInt,而是mapToObj。因此,由于IntUnaryOperator 的作用与Function&lt;Integer, Integer&gt;UnaryOperator&lt;Integer&gt; 相同,因此应使用同时返回int 的方法IntStream::map(IntUnaryOperator mapper)

int count = myString.chars()                 // IntStream
    .map(c -> (set.add((char) c) ? 1 : 0))   // IntStream
    .sum();

long count = myString.chars()                // IntStream
    .filter(c -> set.add((char) c))          // IntStream
    .count();

另外,使用Set&lt;Integer&gt; 可以帮助您避免转换为字符:

Set<Integer> set = new HashSet<>();

int count = myString.chars()                 // IntStream
    .map(c -> (set.add(c) ? 1 : 0))          // IntStream
    .sum();

long count = myString.chars()                // IntStream
    .filter(set::add)                        // IntStream
    .count();

但是,无论您尝试实现什么,您的代码原则上都是错误的。请参阅Stateless behaviors。考虑使用以下 sn-p,其中 lambda 表达式的结果不依赖非确定性操作的结果,例如Set::add

如果流操作的行为参数是有状态的,则流管道结果可能是不确定的或不正确的。

long count = myString.chars()             // IntStream
                     .distinct()          // IntStream
                     .count();

【讨论】:

  • 高级版:int count = myString.chars().collect(BitSet::new, BitSet::set, BitSet::or).cardinality();
  • @nikolas,感谢您的澄清,并指出使用 distinct() 是更好的选择。我倾向于忽略非并行流的无状态要求,但这是一个需要调整的坏习惯。
【解决方案2】:

因为String.chars() 已经返回IntStreamIntStream 没有mapToInt function

您可以使用过滤器代替计数:

int count = myString.chars()
      .filter(c -> set.add(c) == true)
      .count();

我承认我在上个午夜把这个弄得如此粗犷! 正如 cmets 所提到的,这是所需的修复。

感谢您的提及。

long count = myString.chars()
          .filter(c -> set.add((char)c))
          .count();

【讨论】:

    【解决方案3】:

    您也可以收集到一个集合,然后在不使用显式映射的情况下获取大小。 它不需要使用外部状态来包含字符。

        long count = str.chars().boxed().collect(Collectors.toSet()).size();
    

    但是恕我直言,已经提到的更直接的方法是外观更干净,也是我更喜欢使用的方法。

        long count = str.chars().distinct().count();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-20
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2020-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多