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?
    - Efisiensi: Dengan mengetahui berapa banyak byte yang sudah siap dibaca, kita bisa menyesuaikan buffer yang dipakai untuk membaca data. Hal ini dapat meningkatkan efisiensi operasi I/O.
- Pencegahan Blocking Berlama-lama: Saat kita melakukan pembacaan data yang berpotensi 
        block (misalnya menunggu data dari socket), kita bisa melakukan pengecekan awal dengan 
        available()untuk melihat apakah ada data yang siap. Meskipun tidak menjamin 100%, tapi bisa membantu menekan kemungkinan thread tertahan terlalu lama.
- Validasi Sederhana: Terkadang kita ingin sekadar tahu apakah masih ada data yang tersisa 
        sebelum melakukan operasi lainnya. available()bisa membantu kita menentukan apakah kita masih perlu melanjutkan pembacaan atau sudah waktunya menutup stream.
Cara Kerja available()
    
        Sebelum kita masuk ke contoh, mari kita sedikit membahas bagaimana available() bekerja di 
        InputStream. Berikut adalah deskripsi singkat:
    
- InputStreamadalah class abstrak yang mendefinisikan kontrak dasar untuk membaca byte dari sebuah sumber, bisa file, socket, array, dan sebagainya.
- Karena InputStreambersifat abstrak,available()di dalamnya biasanya mengembalikan 0 atauthrow IOException.
- Subclass seperti FileInputStreamatauByteArrayInputStreammengoverride methodavailable()untuk memberikan nilai yang lebih relevan dengan konteks sumber data mereka.
        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:
    
- 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.
- 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 memanggilread(). Hal ini dapat menghindari blocking yang tidak perlu, meskipun tidak menutup kemungkinan data akan masuk setelahnya.
- 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:
    
- Pembacaan Data yang Sudah Terstruktur: Jika kita sudah tahu bahwa data yang dikirim 
        akan mengikuti protokol tertentu (misalnya selalu ada header yang mengatakan panjang data), maka 
        available()jadi kurang relevan. Kita bisa membaca data sesuai protokol tanpa harus bergantung padaavailable().
- Streaming Real-time: Saat membaca data real-time dari jaringan yang terus berubah, 
        available()mungkin hanya berguna sesaat. Biasanya kita akan tetap melakukan pembacaan secara blocking atau non-blocking menggunakan mekanisme NIO (New I/O) dengan selektor dan lain-lain.
- Keperluan Large File I/O Khusus: Kalau kita sedang berurusan dengan file 
        berukuran sangat besar, seringkali kita tidak peduli berapa banyak byte yang tersedia. Kita akan melakukan 
        pembacaan per blok atau chunk menggunakan buffer dengan ukuran tertentu. 
        available()tidak banyak membantu di sini, karena kita tetap harus membaca seluruh data hingga selesai.
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:
    
- mark(int readlimit)digunakan untuk menandai posisi saat ini pada stream, sehingga nanti kita bisa- reset()ke posisi tersebut.
- reset()mengembalikan pointer pembacaan ke posisi di mana- mark()pertama kali dipanggil.
- available()tidak ada kaitannya dengan- mark()dan- reset()secara langsung. Ia hanya mengukur ketersediaan data di buffer, bukan posisi pointer pembacaan.
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:
- Gunakan available()dengan Pemahaman yang Tepat: Jangan pernah berasumsi bahwa jumlah byte yang dikembalikan olehavailable()adalah keseluruhan data yang akan datang. Ini hanya perkiraan jumlah byte yang bisa dibaca secara instan.
- Jangan Lupa Tangani IOException: Memanggil available()bisa memunculkanIOException. Meskipun jarang terjadi untuk stream tertentu, tetaplah siap dengantry-catch.
- Tetap Gunakan Mekanisme Baca Standar: Kalau tujuan utama kita hanya membaca seluruh 
        isi file atau stream, mekanisme baca dengan read()atauread(byte[] buffer)berulang sudah lebih dari cukup.
- Buffering Manual vs. Otomatis: Untuk performa yang lebih baik, kita bisa 
        menggabungkan available()dengan alokasi buffer yang dinamis. Namun, Java sudah punyaBufferedInputStreamyang 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:
    
- Mengoptimasi pembacaan file berukuran kecil hingga sedang.
- Melakukan pengecekan cepat untuk data yang siap dibaca pada socket jaringan.
- Menyesuaikan ukuran buffer secara dinamis saat melakukan streaming data dari berbagai sumber.
        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 :