☕ Java
BufferedReader
BufferedReader wraps a Reader (typically InputStreamReader wrapping System.in or a FileReader) and adds an internal buffer that dramatically reduces the number of underlying read operations. It provides readLine() which reads an entire line at once. BufferedReader is significantly faster than Scanner for large-volume input and is the preferred choice in performance-critical scenarios such as competitive programming.
Creating and Using BufferedReader
BufferedReader requires wrapping System.in in an InputStreamReader (which converts bytes to characters using a specified charset) and then wrapping that in a BufferedReader (which adds buffering and readLine()). The result is a chain of decorators — each adding a specific capability on top of the raw byte stream.
Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class BufferedReaderExample {
public static void main(String[] args) throws IOException {
// ── Create BufferedReader for keyboard input: ─────────────────
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
// ── Read a full line of text: ──────────────────────────────────
System.out.print("Enter your name: ");
String name = reader.readLine(); // reads until
, strips
System.out.println("Hello, " + name);
// ── Read and parse an integer: ────────────────────────────────
System.out.print("Enter your age: ");
int age = Integer.parseInt(reader.readLine().trim());
System.out.println("Age: " + age);
// ── Read and parse a double: ──────────────────────────────────
System.out.print("Enter salary: ");
double salary = Double.parseDouble(reader.readLine().trim());
System.out.printf("Salary: %.2f%n", salary);
// ── Read multiple values from one line: ───────────────────────
// Input: "Alice 30"
System.out.print("Enter name and age (space-separated): ");
String[] parts = reader.readLine().trim().split("\s+");
String pName = parts[0];
int pAge = Integer.parseInt(parts[1]);
System.out.printf("%s is %d years old%n", pName, pAge);
reader.close();
}
}
// ── try-with-resources (recommended): ────────────────────────────────
try (BufferedReader br = new BufferedReader(
new InputStreamReader(System.in))) {
System.out.print("Enter a line: ");
String line = br.readLine();
System.out.println("You typed: " + line);
} // br.close() called automaticallyreadLine() and End of Stream
readLine() reads characters until it encounters a line terminator (\n, \r, or \r\n) or end of stream, then returns the line content without the terminator. It returns null when the end of stream is reached — this is the standard loop termination condition. Checking for null rather than using hasNext() (Scanner's approach) is the BufferedReader pattern.
Java
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
// ── Read lines until end of input (Ctrl+D on Linux, Ctrl+Z on Windows): ─
String line;
while ((line = br.readLine()) != null) {
System.out.println("Read: " + line);
}
// ── Read a known number of lines: ────────────────────────────────────
BufferedReader br2 = new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Enter 3 lines:");
for (int i = 0; i < 3; i++) {
String inputLine = br2.readLine();
System.out.println("Line " + (i + 1) + ": " + inputLine);
}
// ── readLine() return values: ────────────────────────────────────────
// Returns:
// String — the line content (without the line terminator)
// "" — an empty line (user pressed Enter with no input)
// null — end of stream (EOF) reached
// Never returns the newline character itself.
// Returns "" for blank lines — NOT null.
// ── Null check is mandatory in loops: ─────────────────────────────────
String l;
while ((l = br.readLine()) != null) { // assignment inside condition
if (l.isBlank()) continue; // skip empty lines
processLine(l);
}
// ── Java 8+ stream of lines: ─────────────────────────────────────────
try (BufferedReader br3 = new BufferedReader(
new FileReader("data.txt"))) {
br3.lines() // Stream<String>
.filter(s -> !s.isBlank())
.map(String::trim)
.forEach(System.out::println);
}BufferedReader for File Reading
BufferedReader is the standard choice for reading text files line by line. Its internal buffer (default 8192 characters) reads large chunks from disk at once, reducing expensive system calls. For very large files, this makes it significantly faster than reading character by character or using an unbuffered reader.
Java
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
// ── Read file line by line: ───────────────────────────────────────────
try (BufferedReader br = new BufferedReader(
new FileReader("employees.txt"))) {
String line;
int lineNumber = 0;
while ((line = br.readLine()) != null) {
lineNumber++;
System.out.printf("%3d: %s%n", lineNumber, line);
}
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
// ── Specify charset explicitly (recommended for non-ASCII files): ─────
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("data.txt"),
StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
// ── Modern Java — Files.newBufferedReader (Java 7+): ──────────────────
Path path = Path.of("employees.csv");
try (BufferedReader br = Files.newBufferedReader(path,
StandardCharsets.UTF_8)) {
String line;
while ((line = br.readLine()) != null) {
String[] fields = line.split(",");
System.out.printf("Name: %-15s Salary: %s%n",
fields[0], fields[1]);
}
}
// ── Read entire file into a List (Java 7+): ───────────────────────────
List<String> allLines = Files.readAllLines(
Path.of("notes.txt"), StandardCharsets.UTF_8);
allLines.forEach(System.out::println);
// ── Stream lines lazily (Java 8+, memory-efficient for large files): ──
try (var lines = Files.lines(Path.of("bigfile.txt"),
StandardCharsets.UTF_8)) {
long errorCount = lines
.filter(l -> l.contains("ERROR"))
.count();
System.out.println("Error lines: " + errorCount);
}BufferedReader vs Scanner — When to Use Which
BufferedReader and Scanner are both used for reading text input but excel at different tasks. Scanner automatically parses tokens into primitives — nextInt(), nextDouble() — but is slower because of the regex-based tokenisation. BufferedReader is faster and simpler but requires manual parsing with Integer.parseInt() and similar methods. For competitive programming or large-file processing, BufferedReader is the clear winner.
Java
// ── Performance comparison — reading 1 million integers: ────────────
//
// Scanner.nextInt() → ~2000ms
// BufferedReader + parseInt → ~300ms
//
// For competitive programming input (large volume):
// ALWAYS use BufferedReader.
// ── Competitive programming template: ────────────────────────────────
import java.io.*;
import java.util.StringTokenizer;
public class FastInput {
static BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
// Read next token from current line:
static String next() throws IOException {
while (st == null || !st.hasMoreTokens()) {
st = new StringTokenizer(br.readLine());
}
return st.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static long nextLong() throws IOException {
return Long.parseLong(next());
}
static double nextDouble() throws IOException {
return Double.parseDouble(next());
}
public static void main(String[] args) throws IOException {
int n = nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = nextInt();
}
// Fast output with StringBuilder:
StringBuilder sb = new StringBuilder();
for (int x : arr) {
sb.append(x).append('
');
}
System.out.print(sb);
}
}
// ── Feature comparison: ───────────────────────────────────────────────
//
// Feature Scanner BufferedReader
// ────────────────────────── ───────────── ──────────────
// Auto-parse int/double ✓ ✗ (manual parse)
// Read full line nextLine() readLine()
// Check availability hasNextXxx() check null
// Speed (large input) Slow Fast
// CSV / custom delimiter useDelimiter() manual split
// File reading ✓ ✓
// String reading ✓ ✗ (use StringReader)
// Password masking ✗ ✗ (use Console)
// Regex matching ✓ ✗Related Topics in Java Basics
Variables in Java
A variable is just a named box in memory that holds a value. Java is strict about what goes in each box — you tell it the type upfront. Once you get this, the rest of Java clicks into place.
Data Types in Java
Java needs to know exactly what kind of data it's dealing with before it can store or process it. Integers, decimals, characters, true/false — each has its own type. Knowing which to use (and why) makes your programs efficient and bug-free.
Primitive Data Types
Java has eight primitive data types — the most basic building blocks for storing data. Unlike objects, primitives are stored directly in memory, making them fast and efficient. Understanding each type, its size, range, and when to use it is fundamental to writing correct Java programs.
Non-Primitive Data Types
Non-primitive data types — also called reference types — are everything beyond Java's eight primitives. Strings, arrays, classes, interfaces, enums, and records all fall into this category. They're more powerful than primitives, but they work differently in memory, comparison, and nullability. Understanding the distinction is essential for writing correct Java.