Fungsi available() Pada Java

Dalam pemrograman Java, khususnya saat bekerja dengan InputStream, ada satu method yang sering bikin penasaran, yaitu available(). Method ini kadang dianggap sepele, tapi sebenarnya cukup berguna dalam situasi tertentu. Kalau kita perhatikan, available() dapat membantu mengetahui perkiraan jumlah byte yang siap dibaca tanpa harus menunggu. Walaupun tidak selalu akurat 100%, tetapi informasi ini sangat bermanfaat untuk mengoptimasi pembacaan data atau bahkan sekadar memastikan apakah masih ada data yang bisa dibaca sebelum kita benar-benar menutup stream.

Artikel ini akan membahas secara menyeluruh tentang apa itu available(), bagaimana cara kerjanya, dan kapan kita bisa memanfaatkannya. Kita juga akan melihat beberapa contoh penggunaan di berbagai kasus—mulai dari penggunaan sederhana dengan FileInputStream hingga skenario yang lebih kompleks seperti streaming data dari socket jaringan.

Apa Itu available()?

Secara umum, available() adalah sebuah method yang terdapat di InputStream (dan turunan-turunannya) di Java. Method ini mengembalikan nilai integer yang merepresentasikan jumlah byte yang “mungkin” dapat dibaca tanpa melakukan blocking. Artinya, kalau kita memanggil InputStream.available(), kita akan mendapatkan informasi tentang seberapa banyak data yang ready to read pada saat itu.

Penting untuk dicatat bahwa nilai yang dikembalikan oleh available() bukanlah jaminan bahwa selalu tepat sama dengan jumlah byte yang betul-betul tersedia, karena kondisi streaming data bisa berubah kapan saja. Namun, biasanya jika kita hanya membaca data dari sumber statis seperti file, nilai available() cenderung cukup akurat (selama file itu tidak dimodifikasi oleh proses lain). Dalam konteks jaringan, karena data bisa masuk dan keluar secara dinamis, hasilnya bisa lebih fluktuatif.

Kenapa available() Penting?

Cara Kerja available()

Sebelum kita masuk ke contoh, mari kita sedikit membahas bagaimana available() bekerja di InputStream. Berikut adalah deskripsi singkat:

Contohnya, pada ByteArrayInputStream, method available() akan mengembalikan sisa byte yang masih bisa dibaca dari buffer internal. Sementara itu, pada FileInputStream, available() berusaha mengembalikan perkiraan jumlah byte yang masih tersedia untuk dibaca dari file sistem, meskipun itu bukan jaminan final (karena file bisa berubah-ubah jika ada proses lain yang memodifikasinya, walaupun hal ini tergolong kasus khusus).

Contoh Penggunaan Sederhana dengan FileInputStream

Mari kita mulai dengan contoh termudah. Kita akan menggunakan FileInputStream untuk membaca sebuah file teks sederhana. Anggaplah kita punya file bernama contoh.txt yang isinya tidak terlalu besar.

import java.io.FileInputStream;
import java.io.IOException;

public class AvailableExample {
    public static void main(String[] args) {
        String filePath = "contoh.txt";

        try (FileInputStream fis = new FileInputStream(filePath)) {
            
            // Cek jumlah byte yang tersedia
            int availableBytes = fis.available();
            System.out.println("Bytes yang tersedia sebelum pembacaan: " + availableBytes);

            // Baca data sampai selesai
            int data;
            while ((data = fis.read()) != -1) {
                // Lakukan sesuatu dengan data
            }

            // Cek kembali
            System.out.println("Bytes yang tersedia setelah pembacaan: " + fis.available());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Pada contoh di atas, kita membuka file contoh.txt menggunakan FileInputStream. Lalu kita panggil fis.available() untuk melihat berapa byte yang siap dibaca. Biasanya, available() akan mengembalikan nilai sama dengan ukuran file (jika file-nya belum dibaca sama sekali). Setelah kita membaca semua data dari file, nilai available() biasanya menjadi 0, menandakan sudah tidak ada data lagi yang tersisa di stream.

Contoh Penggunaan dengan ByteArrayInputStream

ByteArrayInputStream sering dipakai saat kita ingin melakukan simulasi pembacaan data dari sumber memori (array of bytes). Bagi yang sering melakukan unit testing, ByteArrayInputStream sangat berguna. Bagaimana dengan available() di class ini? Yuk kita lihat contohnya:

import java.io.ByteArrayInputStream;
import java.io.IOException;

public class ByteArrayAvailableExample {
    public static void main(String[] args) {
        byte[] data = "Halo, ini data simulasi!".getBytes();

        try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
            
            System.out.println("Bytes tersedia di awal: " + bais.available());

            // Baca 5 byte pertama
            for (int i = 0; i < 5; i++) {
                bais.read();
            }
            
            System.out.println("Bytes tersedia setelah baca 5 byte: " + bais.available());

            // Baca sisa byte
            while (bais.read() != -1) {
                // Proses data
            }

            System.out.println("Bytes tersedia setelah semua data dibaca: " + bais.available());
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Di sini, data adalah array byte yang berisi string "Halo, ini data simulasi!". Ketika baru pertama kali kita membuat ByteArrayInputStream, isi bais.available() akan sama dengan panjang string tersebut (dalam satuan byte). Saat kita membaca sebagian data, nilai available() akan berkurang. Ketika semua byte sudah habis dibaca, nilainya akan jadi 0.

Penggunaan pada Socket (Stream Jaringan)

Situasi menjadi lebih menarik saat kita bekerja dengan socket. Data yang mengalir melalui jaringan bisa datang kapan saja, dan available() bisa memberikan kita petunjuk apakah ada data yang siap dibaca di buffer. Namun, kita harus hati-hati karena available() tidak menjamin bahwa jumlah byte yang dilaporkan sudah mencakup semua data yang akan datang, terutama jika data dikirim secara bertahap oleh server atau klien.

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketAvailableExample {
    public static void main(String[] args) {
        // Contoh sangat sederhana: kita bikin server socket di port 1234
        try (ServerSocket serverSocket = new ServerSocket(1234)) {
            System.out.println("Menunggu koneksi di port 1234...");
            
            // Terima koneksi
            Socket clientSocket = serverSocket.accept();
            System.out.println("Klien terhubung: " + clientSocket.getInetAddress());

            // Dapatkan input stream dari socket
            InputStream input = clientSocket.getInputStream();

            // Cek ketersediaan data
            int availableBytes = input.available();
            System.out.println("Bytes tersedia saat ini: " + availableBytes);

            // Baca data jika ada
            if (availableBytes > 0) {
                byte[] buffer = new byte[availableBytes];
                int read = input.read(buffer);
                System.out.println("Data diterima: " + new String(buffer, 0, read));
            }
            
            // Tutup koneksi
            clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Pada contoh di atas, kita membuat server socket sederhana di port 1234. Setelah menerima koneksi dari klien, kita memanggil input.available() untuk mengetahui berapa banyak byte yang “kemungkinan” siap dibaca. Kalau nilai tersebut lebih besar dari nol, kita langsung baca semuanya. Kalau tidak, kita bisa menunggu sejenak atau melakukan hal lain.

Kelemahannya, data bisa saja datang setelah kita memanggil available(). Jadi, kalau kita memperlakukan nilai available() sebagai patokan final, kita mungkin berisiko tidak membaca data yang datang setelahnya. Oleh karena itu, untuk data streaming, kita tetap biasanya menggunakan mekanisme blocking read dengan read() atau read(byte[] buffer) secara berulang sambil memantau apakah stream masih menyuplai data.

Kapan available() Sebaiknya Dipakai?

Meskipun available() kelihatannya gampang digunakan, kita perlu tahu waktu yang tepat untuk menggunakannya. Beberapa skenario yang masuk akal untuk memanfaatkan available() antara lain:

  1. Mengoptimasi Pembacaan File: Saat bekerja dengan file yang ukurannya tidak terlalu besar atau saat kita ingin tahu berapa sisa byte yang belum dibaca, available() bisa membantu penyesuaian buffer untuk membaca file secara efisien.
  2. Validasi Cepat Sebelum Read Non-Blocking: Di beberapa situasi, kita bisa melakukan pengecekan cepat di mana jika available() mengembalikan 0, kita bisa memutuskan untuk tidak memanggil read(). Hal ini dapat menghindari blocking yang tidak perlu, meskipun tidak menutup kemungkinan data akan masuk setelahnya.
  3. Debugging: Terkadang available() dipakai untuk keperluan debugging, misalnya sekadar ingin tahu apakah stream-nya masih mengandung data atau tidak pada titik tertentu dalam kode.

Kapan Sebaiknya Menghindari available()?

Di sisi lain, ada situasi di mana available() tidak terlalu bermanfaat atau bahkan bisa menimbulkan kebingungan:

Perbedaan dengan mark() dan reset()

Meskipun sedikit melenceng, tapi sering kali available(), mark(), dan reset() disebut secara bersamaan dalam pembahasan tentang InputStream di Java. Hanya sekadar untuk meluruskan:

Contoh Penggunaan Lain: SequenceInputStream

Selain FileInputStream dan ByteArrayInputStream, Java juga punya SequenceInputStream. Class ini menggabungkan beberapa InputStream menjadi satu stream berkesinambungan. available() di SequenceInputStream akan mengembalikan jumlah byte yang tersedia di stream aktif saat itu, bukan total seluruh InputStream yang digabung. Berikut contohnya:

import java.io.*;

public class SequenceAvailableExample {
    public static void main(String[] args) {
        byte[] data1 = "Data Pertama".getBytes();
        byte[] data2 = "Data Kedua".getBytes();

        try (ByteArrayInputStream bais1 = new ByteArrayInputStream(data1);
             ByteArrayInputStream bais2 = new ByteArrayInputStream(data2);
             SequenceInputStream sis = new SequenceInputStream(bais1, bais2)) {

            System.out.println("Bytes tersedia diawal: " + sis.available());
            
            // Baca data pertama
            while (bais1.available() > 0) {
                sis.read();
            }
            // Sekarang stream internal berganti ke data2
            System.out.println("Bytes tersedia setelah data1 habis: " + sis.available());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Pada contoh ini, SequenceInputStream akan membaca semua byte dari bais1 terlebih dahulu, baru kemudian beralih ke bais2. Nilai available() yang kita dapat bisa berubah begitu bais1 selesai dibaca dan stream pindah ke bais2.

Tips dan Trik Seputar available()

Setelah melihat beberapa contoh, berikut adalah beberapa tips dan trik yang mungkin berguna:

  1. Gunakan available() dengan Pemahaman yang Tepat: Jangan pernah berasumsi bahwa jumlah byte yang dikembalikan oleh available() adalah keseluruhan data yang akan datang. Ini hanya perkiraan jumlah byte yang bisa dibaca secara instan.
  2. Jangan Lupa Tangani IOException: Memanggil available() bisa memunculkan IOException. Meskipun jarang terjadi untuk stream tertentu, tetaplah siap dengan try-catch.
  3. Tetap Gunakan Mekanisme Baca Standar: Kalau tujuan utama kita hanya membaca seluruh isi file atau stream, mekanisme baca dengan read() atau read(byte[] buffer) berulang sudah lebih dari cukup.
  4. Buffering Manual vs. Otomatis: Untuk performa yang lebih baik, kita bisa menggabungkan available() dengan alokasi buffer yang dinamis. Namun, Java sudah punya BufferedInputStream yang cukup cerdas mengelola buffer secara internal.

Studi Kasus: Membaca File Biner dengan Ukuran Sedang

Misalnya kita ingin membaca file biner dengan ukuran sekitar 2MB dan menampilkannya dalam bentuk heksadesimal di layar. Kita bisa memanfaatkan available() untuk memberi petunjuk seberapa banyak data yang tersisa, meskipun sebenarnya tidak wajib. Contoh kode berikut hanya untuk ilustrasi:

import java.io.FileInputStream;
import java.io.IOException;

public class BinaryFileHexDump {
    public static void main(String[] args) {
        if (args.length < 1) {
            System.out.println("Usage: java BinaryFileHexDump ");
            return;
        }

        String filePath = args[0];

        try (FileInputStream fis = new FileInputStream(filePath)) {
            
            int availableBytes;
            byte[] buffer = new byte[1024];
            int bytesRead;
            
            while ((bytesRead = fis.read(buffer)) != -1) {
                // Cetak heksadesimal
                for (int i = 0; i < bytesRead; i++) {
                    System.out.printf("%02X ", buffer[i]);
                }
                System.out.println();
                
                availableBytes = fis.available();
                System.out.println("Bytes tersisa menurut available(): " + availableBytes);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Pada kode di atas, setelah setiap kali kita membaca chunk data sebesar 1024 byte (atau kurang di putaran terakhir), kita mencetak data tersebut dalam format heksadesimal, lalu menanyakan lagi berapa jumlah byte yang masih tersedia. Meskipun ini tidak esensial untuk proses pembacaan, ini sekadar menunjukkan bagaimana available() bisa memberikan snapshot singkat tentang status sisa data di stream.

Method available() dalam InputStream di Java adalah fitur yang relatif sederhana, tetapi cukup berguna dalam skenario tertentu. Kita bisa memakainya untuk:

Namun, perlu diingat bahwa available() bukanlah metode yang bisa dijadikan patokan mutlak untuk menilai total jumlah data yang akan datang, terutama dalam konteks jaringan dan file yang bisa dimodifikasi oleh proses lain. Menggunakannya secara bijak dan memahami keterbatasannya adalah kunci untuk menghindari kesalahpahaman.

Jadi, kalau kamu sedang ngulik stream di Java dan bertanya-tanya berapa banyak data yang masih bisa dibaca saat ini, available() bisa memberikan jawabannya—walaupun tidak harus lengkap, setidaknya cukup untuk memberikan heads up sebelum kamu melanjutkan operasi I/O selanjutnya.

Semoga artikel ini membantu kamu memahami available() lebih dalam dan kapan kamu bisa memanfaatkan fitur ini. Selamat mencoba dan semoga sukses dalam pemrograman Java kamu!


Baca Juga :