Saya menambahkan jawaban kedua ini berdasarkan sunting yang diajukan oleh pengguna srborlongan ke jawaban saya yang lain . Saya pikir teknik yang diusulkan menarik, tetapi itu tidak benar-benar cocok sebagai pengeditan untuk jawaban saya. Yang lain setuju dan pengeditan yang diusulkan dibatalkan. (Aku bukan salah satu pemilih.) Namun, tekniknya pantas. Akan lebih baik jika srborlongan telah memposting jawabannya sendiri. Ini belum terjadi, dan saya tidak ingin teknik itu hilang dalam kabut StackOverflow menolak sejarah edit, jadi saya memutuskan untuk menampilkannya sebagai jawaban terpisah.
Pada dasarnya tekniknya adalah menggunakan beberapa Optional
metode dengan cara yang cerdas untuk menghindari keharusan menggunakan operator ternary ( ? :
) atau pernyataan if / else.
Contoh inline saya akan ditulis ulang dengan cara ini:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
.findFirst();
Contoh saya yang menggunakan metode pembantu akan ditulis ulang dengan cara ini:
/**
* Turns an Optional<T> into a Stream<T> of length zero or one depending upon
* whether a value is present.
*/
static <T> Stream<T> streamopt(Optional<T> opt) {
return opt.map(Stream::of)
.orElseGet(Stream::empty);
}
Optional<Other> result =
things.stream()
.flatMap(t -> streamopt(resolve(t)))
.findFirst();
KOMENTAR
Mari kita bandingkan versi asli vs yang dimodifikasi secara langsung:
// original
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
// modified
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
Yang asli adalah pendekatan langsung jika cekatan: kita mendapatkan Optional<Other>
; jika memiliki nilai, kami mengembalikan aliran yang berisi nilai itu, dan jika tidak memiliki nilai, kami mengembalikan aliran kosong. Cukup sederhana dan mudah dijelaskan.
Modifikasi cerdas dan memiliki keuntungan bahwa ia menghindari persyaratan. (Saya tahu bahwa beberapa orang tidak menyukai operator ternary. Jika disalahgunakan memang dapat membuat kode sulit untuk dipahami.) Namun, kadang-kadang hal-hal bisa terlalu pintar. Kode yang dimodifikasi juga dimulai dengan Optional<Other>
. Kemudian ia memanggil Optional.map
yang didefinisikan sebagai berikut:
Jika suatu nilai hadir, terapkan fungsi pemetaan yang disediakan padanya, dan jika hasilnya bukan nol, kembalikan Opsional yang menggambarkan hasilnya. Kalau tidak, kembalikan Opsional kosong.
The map(Stream::of)
panggilan mengembalikan sebuah Optional<Stream<Other>>
. Jika ada nilai pada input Opsional, Opsional yang dikembalikan berisi Stream yang berisi hasil Other lainnya. Tetapi jika nilainya tidak ada, hasilnya adalah opsional kosong.
Selanjutnya, panggilan untuk orElseGet(Stream::empty)
mengembalikan nilai tipe Stream<Other>
. Jika nilai inputnya ada, itu mendapatkan nilai, yang merupakan elemen tunggal Stream<Other>
. Jika tidak (jika nilai input tidak ada) mengembalikan nilai yang kosong Stream<Other>
. Jadi hasilnya benar, sama dengan kode kondisional asli.
Dalam komentar yang membahas jawaban saya, mengenai hasil edit yang ditolak, saya telah menggambarkan teknik ini sebagai "lebih ringkas tetapi juga lebih tidak jelas". Saya mendukung ini. Butuh beberapa saat untuk mencari tahu apa yang dilakukannya, dan juga butuh waktu untuk menulis deskripsi di atas tentang apa yang dilakukannya. Kehalusan kuncinya adalah transformasi dari Optional<Other>
ke Optional<Stream<Other>>
. Setelah Anda grok ini masuk akal, tetapi itu tidak jelas bagi saya.
Namun, saya akan mengakui bahwa hal-hal yang awalnya tidak jelas dapat menjadi idiomatis dari waktu ke waktu. Mungkin saja teknik ini akhirnya menjadi cara terbaik dalam praktik, setidaknya sampai Optional.stream
ditambahkan (jika pernah ada).
PEMBARUAN: Optional.stream
telah ditambahkan ke JDK 9.
.flatMap(Optional::toStream)
, dengan versi Anda, Anda benar-benar melihat apa yang terjadi.