首先,你必须重新定义你的任务。您正在读取字符,因此您不想将 a 但 a 转换为 .InputStream
Reader
Stream
您无法重新实现发生的字符集转换,例如在 中使用 操作,因为在 s 和生成的 s 之间可能存在 n:m 映射。InputStreamReader
Stream
byte
InputStream
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
int[] tally = new int[26];
Files.lines(Paths.get(file))
.flatMapToInt(CharSequence::chars)
.map(Character::toLowerCase)
.filter(c -> c>='a'&&c<='z')
.map(c -> c-'a')
.forEach(i -> tally[i]++);