Java PushbackReader Class
Last modified: April 16, 2025
The java.io.PushbackReader
class is a character stream reader that
allows characters to be pushed back into the stream. This provides lookahead
functionality when parsing input. It wraps another Reader
and adds
pushback capability.
PushbackReader
maintains an internal buffer for pushed-back
characters. When reading, pushed-back characters are returned first before
reading from the underlying stream. The default pushback buffer size is 1
character, but can be customized.
PushbackReader Class Overview
PushbackReader
extends FilterReader
and provides
character-based pushback operations. Key methods include read operations and
unread (pushback) methods. The class is useful for parsing scenarios where
lookahead is needed.
public class PushbackReader extends FilterReader { public PushbackReader(Reader in); public PushbackReader(Reader in, int size); public int read(); public int read(char[] cbuf, int off, int len); public void unread(int c); public void unread(char[] cbuf); public void unread(char[] cbuf, int off, int len); public boolean ready(); public void close(); }
The code above shows key methods provided by PushbackReader
. The
unread methods allow pushing characters back into the stream. The read methods
consume pushed-back characters first before reading from the underlying stream.
Creating a PushbackReader
PushbackReader is created by wrapping it around another Reader
. You
can specify a buffer size or use the default (1 character). The buffer size
determines how many characters can be pushed back.
import java.io.FileReader; import java.io.IOException; import java.io.PushbackReader; import java.io.Reader; public class Main { public static void main(String[] args) { try { // Create with default buffer size (1 character) Reader fileReader = new FileReader("data.txt"); PushbackReader pushbackReader1 = new PushbackReader(fileReader); // Create with custom buffer size (10 characters) Reader fileReader2 = new FileReader("data.txt"); PushbackReader pushbackReader2 = new PushbackReader(fileReader2, 10); System.out.println("Default pushback reader created"); System.out.println("Custom pushback reader (size 10) created"); pushbackReader1.close(); pushbackReader2.close(); } catch (IOException e) { e.printStackTrace(); } } }
This example demonstrates different ways to create PushbackReader. The first uses default buffer size (1 character), while the second specifies 10 characters. Always close readers when done to release resources. The underlying FileReader is automatically closed when closing PushbackReader.
Reading and Pushing Back Characters
The basic operation of PushbackReader involves reading characters and optionally pushing them back. The unread method pushes characters back into the stream. Subsequent reads will return these characters first.
import java.io.IOException; import java.io.PushbackReader; import java.io.StringReader; public class Main { public static void main(String[] args) { String data = "ABCD"; try (PushbackReader reader = new PushbackReader(new StringReader(data))) { // Read first character int firstChar = reader.read(); System.out.println("First character: " + (char) firstChar); // Push it back reader.unread(firstChar); System.out.println("Character pushed back"); // Read again int sameChar = reader.read(); System.out.println("Read again: " + (char) sameChar); // Read next character int nextChar = reader.read(); System.out.println("Next character: " + (char) nextChar); } catch (IOException e) { e.printStackTrace(); } } }
This example shows basic pushback functionality. The first character is read, then pushed back, and read again. The unread method allows putting characters back into the stream. The pushback buffer operates as a LIFO (last-in-first-out) structure.
Pushing Back Multiple Characters
PushbackReader can push back multiple characters when created with a larger buffer. The unread method accepts character arrays for bulk pushback operations. Characters are pushed back in the order they appear in the array.
import java.io.IOException; import java.io.PushbackReader; import java.io.StringReader; public class Main { public static void main(String[] args) { String data = "1234567890"; try (PushbackReader reader = new PushbackReader(new StringReader(data), 5)) { // Read first 5 characters char[] buffer = new char[5]; reader.read(buffer); System.out.println("First read: " + new String(buffer)); // Push them back reader.unread(buffer); System.out.println("5 characters pushed back"); // Read again reader.read(buffer); System.out.println("Read again: " + new String(buffer)); // Try to push back more than buffer size try { char[] bigBuffer = new char[6]; reader.unread(bigBuffer); // Will throw IOException } catch (IOException e) { System.out.println("Cannot push back more than buffer size"); } } catch (IOException e) { e.printStackTrace(); } } }
This example demonstrates pushing back multiple characters. The reader is created with a 5-character buffer. Attempting to push back more than the buffer size throws an IOException. The unread operation with arrays is efficient for bulk pushback scenarios.
Using PushbackReader for Parsing
PushbackReader is particularly useful for parsing scenarios where you need to look ahead in the stream. After examining characters, you can push them back if they don't match what you're looking for. This enables flexible parsing logic.
import java.io.IOException; import java.io.PushbackReader; import java.io.StringReader; public class Main { public static void main(String[] args) { String data = "123abc456"; try (PushbackReader reader = new PushbackReader(new StringReader(data), 3)) { StringBuilder numbers = new StringBuilder(); int c; while ((c = reader.read()) != -1) { if (Character.isDigit((char) c)) { numbers.append((char) c); } else { // Push back non-digit and break reader.unread(c); break; } } System.out.println("Numbers found: " + numbers); // Read remaining characters char[] remaining = new char[6]; reader.read(remaining); System.out.println("Remaining: " + new String(remaining)); } catch (IOException e) { e.printStackTrace(); } } }
This example shows how PushbackReader can be used for parsing. It reads digits until a non-digit is found, then pushes it back. This allows the non-digit to be processed separately. The pushback capability simplifies many parsing tasks.
Handling Mark and Reset
Unlike some other readers, PushbackReader does not support mark and reset operations. Attempting to use these methods will result in exceptions. The pushback functionality serves a similar purpose for many use cases.
import java.io.IOException; import java.io.PushbackReader; import java.io.StringReader; public class Main { public static void main(String[] args) { String data = "test data"; try (PushbackReader reader = new PushbackReader(new StringReader(data))) { // Check if mark is supported System.out.println("Mark supported: " + reader.markSupported()); // Try to mark (will not throw exception but does nothing) reader.mark(10); // Read some data int c = reader.read(); System.out.println("Read: " + (char) c); // Try to reset (will throw IOException) try { reader.reset(); } catch (IOException e) { System.out.println("Reset not supported: " + e.getMessage()); } } catch (IOException e) { e.printStackTrace(); } } }
This example demonstrates that PushbackReader doesn't support mark/reset. The markSupported method returns false. Attempting to reset throws an IOException. For similar functionality, use the pushback capability instead of mark/reset.
Reading Lines with Pushback
PushbackReader can be used to implement custom line reading logic. This example shows how to read lines while handling line endings consistently. Pushback helps examine line ending characters.
import java.io.IOException; import java.io.PushbackReader; import java.io.StringReader; public class Main { public static void main(String[] args) { String data = "Line 1\r\nLine 2\nLine 3\rLine 4"; try (PushbackReader reader = new PushbackReader(new StringReader(data), 2)) { StringBuilder line = new StringBuilder(); int c; while ((c = reader.read()) != -1) { if (c == '\n') { System.out.println("Line found: " + line); line.setLength(0); } else if (c == '\r') { // Check for \r\n sequence int next = reader.read(); if (next != '\n') { reader.unread(next); } System.out.println("Line found: " + line); line.setLength(0); } else { line.append((char) c); } } // Print last line if not empty if (line.length() > 0) { System.out.println("Last line: " + line); } } catch (IOException e) { e.printStackTrace(); } } }
This example implements custom line reading that handles different line endings (\n, \r, \r\n). The pushback capability allows examining the character after \r to determine if it's part of \r\n sequence. This demonstrates practical use of PushbackReader for text processing.
Source
Java PushbackReader Class Documentation
In this article, we've covered the essential methods and features of the Java PushbackReader class. Understanding these concepts is crucial for working with character streams that require lookahead capability in Java applications.
Author
List all Java tutorials.