Apakah ini hal yang wajar untuk mengembalikan Streaming di mana pun kami biasanya akan mengembalikan Koleksi?

19

Saat mengembangkan API saya yang tidak terikat dengan kode warisan apa pun, saya sering menemukan diri saya menulis metode yang murni pipa Streams diakhiri dengan mengumpulkan hasilnya. Seperti yang ini:

ImmutableSet<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfThing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey)
        .collect(MyCustomCollectors.toImmutableSet());
}

Sekarang, sebagian besar klien dari kelas ini biasanya akan membutuhkan Koleksi (dalam hal ini, ImmutableSet) untuk mencari elemen dan beralih di atasnya, tetapi beberapa klien dapat mengambil manfaat dari memiliki Stream sehingga mereka dapat menyalurkan beberapa operasi lebih dari itu Streaming tanpa perlu mendapatkan aliran baru dari Koleksi. Jadi mengembalikan Stream memberi klien superset opsi yang akan mereka miliki jika mereka hanya memiliki Koleksi (setelah semua, mereka selalu dapat collect()Stream sendiri:

Stream<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfthing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey);
        // No collect
}

Pendekatan ini menggoda bagi saya untuk mencoba karena saya tidak melihat adanya kelemahan yang mungkin terjadi. Namun, saya belum pernah melihat pendekatan ini di perpustakaan mana pun (mungkin karena tidak ada banyak perpustakaan yang dirilis setelah munculnya Java 8), jadi saya agak takut untuk mengadopsinya. Kelas perpustakaan yang ada biasanya mengembalikan Koleksi ketika mereka memperoleh sesuatu dari negara bagian.

Adakah sesuatu yang buruk yang dapat terjadi jika saya memutuskan untuk mengembalikan Stream di mana diri saya pra-Jawa-8 akan mengembalikan Koleksi? Atau mungkin saya melakukan sesuatu yang anti-internet di sini dengan semua yang berasal dari negara swasta?

jojman
sumber

Jawaban:

14

Jika myPrivateThingiesbisa berubah, Anda telah membuat ketergantungan tersembunyi antara negara pribadi Anda dan hasil streaming. Jika memungkinkan bagi klien untuk menyebabkan myPrivateThingiesperubahan status secara tidak langsung , maka dia akan mendapatkan hasil yang berbeda saat menelepon collectdaripada yang awalnya ingin Anda berikan.

Jika myPrivateThingiestidak dapat diubah, maka hasilnya akan transparan secara referensi, tetapi ada satu masalah lagi yang harus Anda perhatikan: sampah semantik , yaitu mempertahankan sejumlah besar memori yang tidak lagi diperlukan. Misalkan myPrivateThingiessangat besar dan hasil pengumpulan aliran kecil. Klien mungkin bertahan pada aliran lama setelah membuang semua referensi ke objek yang menghasilkannya, tetapi itu streammasih menjaga myPrivateThingiesdari menjadi sampah yang dikumpulkan. Dengan bersemangat mengumpulkan hasil akan memungkinkan myPrivateThingiesuntuk dibebaskan.

Ini sebenarnya terjadi sebelum Java 7 saat menelepon substring. Oracle memutuskan bahwa penghematan efisiensi potensial dari tidak menyalin substring setiap kali tidak layak kadang-kadang mengejutkan pengguna rata-rata dengan konsumsi memori yang berlebihan. Itu bukan untuk mengatakan tidak ada kasus penggunaan nyata untuk perilaku lama (misalnya parser) tetapi sering mengumpulkan hasil dengan penuh semangat cukup cepat, dan ketika itu terjadi Anda tidak memiliki pro dan potensi kontra.

Di sisi lain, mengembalikan aliran memberi klien kemampuan untuk memilih struktur data mana yang ingin mereka gunakan untuk menyimpan hasil, sebagai lawan dari Anda memilih satu untuknya. Mungkin layak menawarkan kedua opsi.

Doval
sumber
4

Hal yang paling penting untuk dipertimbangkan: Streams hanya dapat diulang satu kali, sedangkan Anda memiliki lebih banyak fleksibilitas daripada Collection: Anda dapat terus membuat lebih banyak Streamatau bahkan Iterators untuk melakukan pemrosesan berulang tambahan pada hasilnya.

Jadi, jika Anda tidak yakin apakah penelepon metode akan menggunakan hasil satu kali dan hanya sekali, lebih baik untuk mengembalikan a Collection.


Kode sampel Anda memiliki satu kesalahan yang jelas: mengapa harus SocialStatusmemiliki konsep seseorang he,?

hjk
sumber
3

Dalam pandangan saya, tidak. Hal-hal yang dapat Anda lakukan dengan stream adalah superset ketat dari hal-hal yang dapat Anda lakukan dengan koleksi, dan sering kali mereka dapat dibuat lebih efisien, sehingga tidak ada alasan untuk tidak menggunakannya kecuali tidak terbiasa. "Ekspresi Lambda adalah obat gerbang ke Java 8, tetapi Streams adalah kecanduan yang sebenarnya." (Venkat Subramaniam, Pemrograman Fungsional di Jawa )

Kilian Foth
sumber