Specialized Streams Reference
Besides the everyday stream classes, java.io contains a handful of specialized streams built for particular jobs, such as joining several streams into one, "un-reading" a character, or connecting two threads. You will rarely need them, but you should recognize them when you meet them in older code or an interview. In this lesson, you will find a reference table of these classes and short examples of the two most useful ones.
Reference Table
| Class | Kind | It is used to... |
|---|---|---|
SequenceInputStream | Byte input | Read several input streams one after another, as if they were one. |
PushbackInputStream | Byte input decorator | Push bytes back so the next read returns them again (peeking ahead). |
PushbackReader | Character input decorator | Push characters back, for writing simple parsers. |
PipedInputStream / PipedOutputStream | Bytes between threads | Connect a writing thread to a reading thread. |
PipedReader / PipedWriter | Characters between threads | The same, for text. |
FilterInputStream / FilterOutputStream | Byte decorator base | Serve as the base class for your own byte decorators. |
FilterReader / FilterWriter | Character decorator base | Serve as the base class for your own character decorators. |
LineNumberReader | Character input decorator | Read lines while tracking the current line number. |
StreamTokenizer | Parser | Split input into numbers, words and symbols (old, rarely used). |
ObjectStreamField | Serialization helper | Describe a serializable field when customizing serialization. |
Example: SequenceInputStream
Let's see an example that reads two sources as one continuous stream.
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.nio.charset.StandardCharsets;
public class Joined {
public static void main(String[] args) throws IOException {
InputStream part1 = new ByteArrayInputStream(
"Navika, Srihitha".getBytes(StandardCharsets.UTF_8));
InputStream part2 = new ByteArrayInputStream(
", Advitha".getBytes(StandardCharsets.UTF_8));
try (InputStream both = new SequenceInputStream(part1, part2)) {
System.out.println(new String(both.readAllBytes(),
StandardCharsets.UTF_8));
}
}
}Navika, Srihitha, AdvithaExplanation: SequenceInputStream reads part1 until it ends, then continues with part2, so the reader sees one stream. It is handy for joining files that were split into parts.
Example: PushbackReader for Peeking
import java.io.IOException;
import java.io.PushbackReader;
import java.io.StringReader;
public class Peek {
public static void main(String[] args) throws IOException {
try (PushbackReader r = new PushbackReader(new StringReader("42+7"))) {
StringBuilder number = new StringBuilder();
int c;
while ((c = r.read()) != -1 && Character.isDigit(c)) {
number.append((char) c);
}
if (c != -1) {
r.unread(c);
}
System.out.println("Number: " + number);
System.out.println("Next symbol: " + (char) r.read());
}
}
}Number: 42
Next symbol: +Explanation: The loop reads digits until it meets a non-digit, the +. That character was read too early, so unread pushes it back, and the next read returns it again. This "read one too far, then push back" step is common in simple parsers.
Common Mistakes
Using piped streams in one thread. It can deadlock.
Pushing back more characters than the buffer allows. PushbackReader holds one character by default; pass a larger size to the constructor if needed.
Practice
- Easy: Join three
StringReader-based texts by converting them to byte streams and usingSequenceInputStream. - Harder: Use a
PushbackReaderto split the text "12+34-5" into numbers and operators, printing each token on its own line.
Key Takeaways
Was this tutorial helpful?