如何将Java 8 Streams与InputStream一起使用?

时间:2014-05-23 17:27:48

标签: java io java-8 java-stream

我想在java.util.streams.Stream周围包裹一个InputStream来一次处理一个字节或一个字符。我没有找到任何简单的方法。

请考虑以下练习:我们希望计算每个字母在文本文件中出现的次数。我们可以将其存储在一个数组中,以便tally[0]存储文件中显示的次数,tally[1]存储b出现的时间数等等。由于我无法找到直接传输文件的方法,我这样做了:

 int[] tally = new int[26];
 Stream<String> lines = Files.lines(Path.get(aFile)).map(s -> s.toLowerCase());
 Consumer<String> charCount = new Consumer<String>() {
   public void accept(String t) {
      for(int i=0; i<t.length(); i++)
         if(Character.isLetter(t.charAt(i) )
            tall[t.charAt(i) - 'a' ]++;
   }
 };
 lines.forEach(charCount);

有没有办法在不使用lines方法的情况下完成此操作?我可以直接将每个字符作为Stream或Stream处理,而不是为文本文件中的每一行创建字符串。

我可以更直接地将java.io.InputStream转换为java.util.Stream.stream吗?

1 个答案:

答案 0 :(得分:19)

首先,您必须重新定义您的任务。您正在阅读字符,因此您不希望将InputStream而非Reader转换为Stream

您无法重新实现发生的字符集转换,例如在InputStreamReader中进行Stream次操作,因为byte的{​​{1}}与生成的InputStream之间可能存在n:m映射。

char创建流有点棘手。您将需要一个迭代器来指定获取项目和结束条件的方法:

Reader

获得迭代器后,您可以使用分离器的绕行创建流并执行所需的操作:

PrimitiveIterator.OfInt it=new PrimitiveIterator.OfInt() {
    int last=-2;
    public int nextInt() {
      if(last==-2 && !hasNext())
          throw new NoSuchElementException();
      try { return last; } finally { last=-2; }
    }
    public boolean hasNext() {
      if(last==-2)
        try { last=reader.read(); }
        catch(IOException ex) { throw new UncheckedIOException(ex); }
      return last>=0;
    }
};

请注意,虽然迭代器更为常见,但实现新的int[] tally = new int[26]; StreamSupport.intStream(Spliterators.spliteratorUnknownSize( it, Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false) // now you have your stream and you can operate on it: .map(Character::toLowerCase) .filter(c -> c>='a'&&c<='z') .map(c -> c-'a') .forEach(i -> tally[i]++); 接口可以直接简化操作,因为它不需要在两个可以按任意顺序调用的方法之间维护状态。相反,我们只有一个Spliterator方法可以直接映射到tryAdvance调用:

read()

但请注意,如果您改变主意并愿意使用Spliterator.OfInt sp = new Spliterators.AbstractIntSpliterator(1000L, Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) { public boolean tryAdvance(IntConsumer action) { int ch; try { ch=reader.read(); } catch(IOException ex) { throw new UncheckedIOException(ex); } if(ch<0) return false; action.accept(ch); return true; } }; StreamSupport.intStream(sp, false) // now you have your stream and you can operate on it: … ,您可以过上更轻松的生活:

Files.lines