Haruskah Kami Menutup Aliran Java?

1. Ikhtisar

Dengan pengenalan ekspresi lambda di Java 8, dimungkinkan untuk menulis kode dengan cara yang lebih ringkas dan fungsional. Stream dan Antarmuka Fungsional adalah inti dari perubahan revolusioner dalam platform Java ini.

Dalam tutorial singkat ini, kita akan belajar apakah kita harus menutup aliran Java 8 secara eksplisit dengan melihatnya dari perspektif sumber daya.

2. Menutup Stream

Aliran Java 8 mengimplementasikan antarmuka AutoCloseable :

public interface Stream extends BaseStream { // omitted } public interface BaseStream extends AutoCloseable { // omitted }

Sederhananya, kita harus memikirkan aliran sebagai sumber daya yang dapat kita pinjam dan kembalikan setelah kita selesai menggunakannya. Berbeda dengan sebagian besar sumber daya, kami tidak harus selalu menutup aliran.

Ini mungkin terdengar kontra-intuitif pada awalnya, jadi mari kita lihat kapan kita harus dan kapan kita tidak harus menutup aliran Java 8.

2.1. Koleksi, Array, dan Generator

Sebagian besar waktu, kami membuat instance Stream dari koleksi Java, array, atau fungsi generator. Misalnya, di sini, kami mengoperasikan kumpulan String melalui Stream API:

List colors = List.of("Red", "Blue", "Green") .stream() .filter(c -> c.length() > 4) .map(String::toUpperCase) .collect(Collectors.toList());

Terkadang, kami menghasilkan aliran berurutan terbatas atau tak terbatas:

Random random = new Random(); random.ints().takeWhile(i -> i < 1000).forEach(System.out::println);

Selain itu, kami juga dapat menggunakan aliran berbasis larik:

String[] colors = {"Red", "Blue", "Green"}; Arrays.stream(colors).map(String::toUpperCase).toArray()

Saat berurusan dengan aliran semacam ini, kita tidak boleh menutupnya secara eksplisit. Satu-satunya sumber daya berharga yang terkait dengan aliran ini adalah memori, dan Pengumpulan Sampah (GC) mengurusnya secara otomatis.

2.2. Sumber Daya IO

Namun, beberapa aliran didukung oleh sumber daya IO seperti file atau soket. Misalnya, metode Files.lines () mengalirkan semua baris untuk file yang diberikan:

Files.lines(Paths.get("/path/to/file")) .flatMap(line -> Arrays.stream(line.split(","))) // omitted

Di balik terpal, metode ini membuka instance FileChannel dan kemudian menutupnya setelah aliran ditutup. Oleh karena itu, jika kita lupa untuk menutup aliran, saluran yang mendasarinya akan tetap terbuka dan akan berakhir dengan kebocoran sumber daya .

Untuk mencegah kebocoran sumber daya seperti itu, sangat disarankan untuk menggunakan idiom coba-dengan-sumber daya untuk menutup aliran berbasis IO:

try (Stream lines = Files.lines(Paths.get("/path/to/file"))) { lines.flatMap(line -> Arrays.stream(line.split(","))) // omitted }

Dengan cara ini, kompilator akan menutup saluran secara otomatis. Kuncinya di sini adalah menutup semua aliran berbasis IO .

Perhatikan bahwa menutup aliran yang sudah tertutup akan memunculkan IllegalStateException .

3. Kesimpulan

Dalam tutorial singkat ini, kami melihat perbedaan antara aliran sederhana dan aliran berat IO. Kami juga mempelajari bagaimana perbedaan tersebut memengaruhi keputusan kami tentang apakah akan menutup aliran Java 8 atau tidak.

Seperti biasa, kode sampel tersedia di GitHub.