Java 8:如何基于java.io.Reader </character>创建java.util.stream.Stream <character>

时间:2015-02-16 23:26:57

标签: java mapreduce java-8 inputstream

阅读Java 8文档似乎它的目标java.util.stream.Stream最终可以由I / O java.io.InputStream支持。

所以,我想读取一个字符流,并使用新功能将其提供给map-reduce管道。我无法找到任何实用方法来做到这一点,所以我不得不自己动手:

public static Stream<Character> charStream(Reader r) {
    Iterator<Character> iter = new Iterator<Character>() {
        Character nextChar = null;

        @Override
        public boolean hasNext() {
            if (nextChar != null) {
                return true;
            } else {
                try {
                    int readChar = r.read();
                    if(readChar == -1) { 
                        return false;
                    }
                    nextChar = Character.valueOf((char) readChar);
                    return true;
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            }
        }

        @Override
        public Character next() {
            if (nextChar != null || hasNext()) {
                Character theChar = nextChar;
                nextChar = null;
                return theChar;
            } else {
                throw new NoSuchElementException();
            }
        }
    };
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
            iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
}

是否有可以实现相同或相似的实用方法?

2 个答案:

答案 0 :(得分:2)

我发现在这种情况下,Spliterator而不是Iterator更容易实现:

public static IntStream charStream(Reader r) {
    Spliterator.OfInt split = new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) {
        @Override
        public boolean tryAdvance(IntConsumer action) {
            try {
                int c = r.read();
                if (c == -1) {
                    return false;
                } else {
                    action.accept(c);
                    return true;
                }
            } catch (IOException ex) {
                throw new UncheckedIOException(ex);
            }
        }
    };

    return StreamSupport.intStream(split, false);
}

实施IntStream以避免拳击更好。您随时可以使用IntStream

Stream<Character>变为.mapToObj(i->(char) i)

答案 1 :(得分:2)

您可以使用

创建代表字符的IntStream
new BufferedReader(r).lines().flatMapToInt(CharSequence::chars)

如果真的必须是(拳击)Stream<Character>,您可以mapToObj(c -> (char)c)使用IntStream

public static Stream<Character> chars(Reader r) {
    return new BufferedReader(r).lines().flatMapToInt(CharSequence::chars)
      .mapToObj(c -> (char)c);
}

但对大多数情况而言

public static IntStream chars(Reader r) {
    return new BufferedReader(r).lines().flatMapToInt(CharSequence::chars);
}

应该足够了。