Pola nextLine() diikuti Integer.parseInt pada Chapter sebelumnya sebenarnya adalah cara kerja alat input yang lebih tua dan lebih cepat: BufferedReader. Class dari package java.io ini telah lama menjadi pilihan utama untuk input berbasis teks sejak versi awal Java, dan hingga kini masih dipakai luas untuk membaca baris demi baris — dari keyboard, berkas, hingga koneksi jaringan. Chapter ini membahas cara menyusun lapisan BufferedReader, arti IOException yang wajib ditangani, serta cara memilih antara BufferedReader dan Scanner.

Membungkus System.in dengan BufferedReader #

BufferedReader tidak bisa membaca System.in secara langsung karena System.in menghasilkan byte, sedangkan BufferedReader bekerja dengan karakter. Karena itu kita perlu dua lapisan: InputStreamReader menerjemahkan byte menjadi karakter (proses decoding), lalu BufferedReader menambahkan penyangga (buffer) di atasnya. Tanpa buffer, setiap pembacaan karakter dapat memicu panggilan sistem operasi yang mahal; dengan buffer, data dibaca dalam potongan besar sekali jalan lalu dibagikan sedikit demi sedikit oleh method readLine().

Mari kita lihat bentuk lengkapnya pada program sapaan sederhana:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BacaNamaBuffer {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Nama: ");
        String nama = br.readLine();

        System.out.print("Umur: ");
        String umurTeks = br.readLine();
        int umur = Integer.parseInt(umurTeks);

        System.out.println("Halo, " + nama + "! Tahun depan Anda berumur " + (umur + 1) + " tahun.");
    }
}

Output yang Dihasilkan:

text
Nama: Umur: Halo, Budi! Tahun depan Anda berumur 18 tahun.

Mari kita telaah baris-baris kode di atas:

  1. Baris 1-3 (import java.io.*): ketiga class pendukung diimpor dari package java.io — BufferedReader, IOException, dan InputStreamReader.
  2. Baris 6 (throws IOException): readLine() dideklarasikan dapat melempar checked exception, sehingga compiler memaksa kita menyatakan niat: diteruskan dengan throws seperti di sini, atau ditangani dengan try-catch seperti contoh kedua di bawah.
  3. Baris 7 (new BufferedReader(new InputStreamReader(System.in))): dua lapisan disusun dari dalam ke luar — InputStreamReader membungkus System.in, BufferedReader membungkus InputStreamReader.
  4. Baris 10 dan 13 (br.readLine()): setiap panggilan mengembalikan satu baris ketikan sebagai String tanpa tanda baris barunya.
  5. Baris 14 (Integer.parseInt(umurTeks)): konversi teks menjadi int dilakukan manual — di sinilah letak perbedaan utama dengan Scanner.nextInt() yang mengonversi otomatis.

IOException sebagai Checked Exception #

Mengapa readLine() sampai wajib menangani exception? Jawabannya ada pada kenyataan bahwa pembacaan input adalah operasi terhadap perangkat: keyboard bisa terputus, berkas bisa hilang saat dibaca, koneksi bisa terputus di tengah jalan. Perancang java.io memutuskan kegagalan semacam ini terlalu serius untuk disembunyikan, sehingga IOException dibuat sebagai checked exception — compiler menolak kode yang membacanya tanpa throws atau try-catch.

Pada contoh pertama, klausa throws IOException di main berarti “biarkan JVM yang menangani”. Jika exception benar-benar terjadi, JVM mencetak stack trace lalu menghentikan program — perilaku yang dapat diterima untuk program kecil, tetapi kurang sopan bagi pengguna aplikasi sungguhan. Sebagai perbandingan, class Scanner menelan IOException di dalam implementasinya dan menampilkannya sebagai kegagalan pembacaan biasa; itulah salah satu alasan Scanner terasa lebih “bersih” bagi pemula.

Membaca Banyak Baris dengan Try-with-Resources #

Untuk input yang panjang, pola yang tepat adalah loop while dengan dua syarat berhenti: baris bernilai null atau baris berisi kata kunci penutup. Nilai null adalah cara readLine() menyatakan bahwa stream telah habis — tidak ada lagi data yang bisa dibaca. Program berikut menjumlahkan angka sampai pengguna mengetik kata selesai, melompati baris yang bukan angka, sekaligus memakai try-with-resources agar reader tertutup otomatis:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class BacaAngkaBuffer {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
            int total = 0;
            int jumlah = 0;
            String baris;

            while ((baris = br.readLine()) != null && !baris.equalsIgnoreCase("selesai")) {
                try {
                    total += Integer.parseInt(baris);
                    jumlah++;
                } catch (NumberFormatException e) {
                    System.out.println("Dilewati (bukan angka): " + baris);
                }
            }
            System.out.println("Jumlah angka: " + jumlah);
            System.out.println("Total       : " + total);
        } catch (IOException e) {
            System.out.println("Gagal membaca input: " + e.getMessage());
        }
    }
}

Output yang Dihasilkan:

text
Dilewati (bukan angka): abc
Jumlah angka: 2
Total       : 40

Poin penting dari program ini dapat diuraikan begini:

  1. Baris 8-9 (try (BufferedReader br = ...)): try-with-resources menjamin close() dipanggil otomatis saat blok berakhir — kebocoran resource tidak mungkin terjadi walau exception meloncat di tengah proses.
  2. Baris 9 (StandardCharsets.UTF_8): charset dinyatakan secara eksplisit sehingga decoding byte ke karakter tidak bergantung pada pengaturan platform tempat program berjalan.
  3. Baris 14 ((baris = br.readLine()) != null): assignment di dalam kondisi membaca satu baris sekaligus menyimpannya; saat stream habis, readLine() mengembalikan null dan loop berhenti rapi tanpa exception.
  4. Baris 15-20 (Integer.parseInt dan NumberFormatException): baris non-angka tidak menghentikan program — NumberFormatException ditangkap, baris tersebut dilewati dengan pesan, lalu loop berlanjut ke baris berikutnya.

Scanner atau BufferedReader #

Kedua alat tersebut tumpang tindih fungsinya, tetapi masing-masing punya wilayah yang paling pas:

AspekScannerBufferedReader
Satuan bacaantoken (kata) atau barisbaris saja
Konversi angkaotomatis (nextInt dan sejenisnya)manual (Integer.parseInt)
Input salah tipeInputMismatchExceptionNumberFormatException dari parseInt
Exception pembacaanditelan implementasiIOException wajib dideklarasikan
Kekuatan khasparsing token campuran, delimiter kustomvolume baris besar, minimal overhead

Untuk form interaktif dengan campuran angka dan teks, Scanner lebih ringkas. Untuk pipeline data baris demi baris — menjumlahkan log, membaca CSV sederhana, memproses keluaran program lain — BufferedReader lebih ringan dan lebih mudah dikendalikan. Dengan input yang sudah terbaca, langkah berikutnya adalah menampilkan hasil yang rapi; Chapter Mencetak Output membahas sisi lawannya: print, println, dan escape sequence.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

BacaAngkaBuffer.java

Unduh berkas
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class BacaAngkaBuffer {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
            int total = 0;
            int jumlah = 0;
            String baris;

            while ((baris = br.readLine()) != null && !baris.equalsIgnoreCase("selesai")) {
                try {
                    total += Integer.parseInt(baris);
                    jumlah++;
                } catch (NumberFormatException e) {
                    System.out.println("Dilewati (bukan angka): " + baris);
                }
            }
            System.out.println("Jumlah angka: " + jumlah);
            System.out.println("Total       : " + total);
        } catch (IOException e) {
            System.out.println("Gagal membaca input: " + e.getMessage());
        }
    }
}

BacaNamaBuffer.java

Unduh berkas
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BacaNamaBuffer {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Nama: ");
        String nama = br.readLine();

        System.out.print("Umur: ");
        String umurTeks = br.readLine();
        int umur = Integer.parseInt(umurTeks);

        System.out.println("Halo, " + nama + "! Tahun depan Anda berumur " + (umur + 1) + " tahun.");
    }
}