为什么需要将IntStream映射到Stream <Character>

时间:2019-06-10 22:14:05

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

  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。

3 个答案:

答案 0 :(得分:7)

方法CharSequence::chars返回IntStream,它当然不提供任何转换为​​int的方法,例如mapToInt,而是提供mapToObj。因此,也应同时使用都返回int的方法IntStream::map(IntUnaryOperator mapper),因为IntUnaryOperator的作用与Function<Integer, Integer>UnaryOperator<Integer>相同:

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<Integer>可以帮助您避免转换为字符:

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();

但是,无论您要实现什么目标,原则上您的代码都是错误的,确切地说是NO Stateless behaviors。考虑使用以下代码段,这些代码段的lambda表达式的结果与不依赖的操作无关,例如Set::add

  

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

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

答案 1 :(得分:2)

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

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

但是恕我直言,已经提到的更直接的方法是在外观上更简洁,也是我更愿意使用的方法。

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

答案 2 :(得分:1)

因为#include <memory> #if defined(__GLIBC__) && ((__GLIBC__>=2 && __GLIBC_MINOR__>=8) || __GLIBC__>2) \ && defined(__LP64__) #define GLIBC_MALLOC_ALREADY_ALIGNED 1 #else #define GLIBC_MALLOC_ALREADY_ALIGNED 0 #endif #if defined(__FreeBSD__) && !defined(__arm__) && !defined(__mips__) #define FREEBSD_MALLOC_ALREADY_ALIGNED 1 #else #define FREEBSD_MALLOC_ALREADY_ALIGNED 0 #endif #if (defined(__APPLE__) \ || defined(_WIN64) \ || GLIBC_MALLOC_ALREADY_ALIGNED \ || FREEBSD_MALLOC_ALREADY_ALIGNED) #define MALLOC_ALREADY_ALIGNED 1 #else #define MALLOC_ALREADY_ALIGNED 0 #endif #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) \ && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0) #define HAS_POSIX_MEMALIGN 1 #else #define HAS_POSIX_MEMALIGN 0 #endif namespace sc2d::memory { void* _aligned_malloc(size_t size, size_t alignment) { void* res = nullptr; void* ptr = malloc(size + alignment); if (ptr!=nullptr) { res = reinterpret_cast<void*>((reinterpret_cast<size_t>(ptr) & ~(size_t(alignment-1))) + alignment); *(reinterpret_cast<void**>(res) - 1) = ptr; } return res; } void* aligned_malloc(size_t size, size_t alignment) { #if MALLOC_ALREADY_ALIGNED return malloc(size); #elif HAS_POSIX_MEMALIGN void* res; const int failed = posix_memalign(&res,size,alignment); if(failed) res = 0; return res; #elif (defined _MSC_VER) return _aligned_malloc(size, alignment); #else return sc2d::memory::_aligned_malloc(size, alignment); #endif } void _aligned_free(void* ptr) { if (ptr != nullptr) free(*(reinterpret_cast<void**>(ptr) - 1)); } void aligned_free(void* ptr) { #if MALLOC_ALREADY_ALIGNED free(ptr); #elif HAS_POSIX_MEMALIGN free(ptr); #elif defined(_MSC_VER) _aligned_free(ptr); #else sc2d::memory_aligned_free(ptr); #endif } } 已经返回了String.chars(),而IntStream没有IntStream mapToInt

您可以改用过滤器然后计数:

function

我承认我在上个午夜做的如此卑鄙! 如评论所述,这是必需的修复程序。

谢谢您的提及。

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