Di Java 8, apa perbedaan antara Stream.map()
dan Stream.flatMap()
metode?
java
java-8
java-stream
cassiomolin
sumber
sumber
map :: Stream T -> (T -> R) -> Stream R
,flatMap :: Stream T -> (T -> Stream R) -> Stream R
.<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
.map
's mapper lambda kembaliR
, sebuahflatMap
' s mapper lambda pengembalian aStream
dariR
(Stream<R>
). Aliran yang dikembalikan olehflatMap
mapper 'adalah digabungkan secara efektif. Jika tidak, keduanyamap
danflatMap
kembaliStream<R>
; perbedaannya adalah apa lambdas mapper kembali,R
vsStream<R>
.Jawaban:
Keduanya
map
danflatMap
dapat diterapkan keStream<T>
dan mereka berdua mengembalikan aStream<R>
. Perbedaannya adalah bahwamap
operasi menghasilkan satu nilai output untuk setiap nilai input, sedangkanflatMap
operasi menghasilkan nilai angka acak (nol atau lebih) untuk setiap nilai input.Ini tercermin dalam argumen untuk setiap operasi.
The
map
operasi mengambilFunction
, yang disebut untuk setiap nilai dalam aliran input dan menghasilkan satu nilai hasil, yang dikirim ke output stream.The
flatMap
operasi mengambil fungsi yang konseptual ingin mengkonsumsi satu nilai dan menghasilkan jumlah sewenang-wenang nilai-nilai. Namun, di Jawa, sulit untuk sebuah metode untuk mengembalikan jumlah nilai yang berubah-ubah, karena metode hanya dapat mengembalikan nol atau satu nilai. Orang bisa membayangkan API di mana fungsi mapper untukflatMap
mengambil nilai dan mengembalikan array atau aList
nilai, yang kemudian dikirim ke output. Karena ini adalah pustaka stream, cara yang paling tepat untuk mewakili jumlah nilai pengembalian yang berubah-ubah adalah fungsi mapper sendiri untuk mengembalikan aliran! Nilai-nilai dari aliran dikembalikan oleh mapper dikeringkan dari aliran dan diteruskan ke aliran output. "Rumpun" nilai yang dikembalikan oleh setiap panggilan ke fungsi mapper tidak dibedakan sama sekali dalam aliran output, sehingga output dikatakan telah "diratakan."Penggunaan umum adalah untuk fungsi mapper
flatMap
untuk mengembalikanStream.empty()
jika ia ingin mengirim nilai nol, atau sesuatu sepertiStream.of(a, b, c)
jika ia ingin mengembalikan beberapa nilai. Tapi tentu saja aliran apa pun dapat dikembalikan.sumber
flatMap
operasi adalah kebalikan dari flat. Sekali lagi, serahkan kepada Ilmuwan Komputer untuk mengubah istilah di kepala itu. Seperti fungsi yang "transparan" yang berarti Anda tidak dapat melihat apa pun yang dilakukannya, hanya hasilnya, sementara bahasa sehari-hari mengatakan Anda ingin proses menjadi transparan berarti Anda ingin setiap bagian dari itu dilihat.Stream.flatMap
, karena dapat ditebak namanya, adalah kombinasi darimap
danflat
operasi. Itu berarti bahwa Anda pertama-tama menerapkan fungsi ke elemen Anda, dan kemudian meratakannya.Stream.map
hanya menerapkan fungsi ke aliran tanpa meratakan aliran.Untuk memahami apa yang dimaksud dengan meratakan aliran, pertimbangkan struktur seperti
[ [1,2,3],[4,5,6],[7,8,9] ]
yang memiliki "dua tingkat". Merata ini berarti mengubahnya dalam struktur "satu tingkat":[ 1,2,3,4,5,6,7,8,9 ]
.sumber
Saya ingin memberikan 2 contoh untuk mendapatkan sudut pandang yang lebih praktis:
Contoh pertama menggunakan peta:
Tidak ada yang istimewa pada contoh pertama, a
Function
diterapkan untuk mengembalikanString
huruf kapital.Contoh kedua menggunakan
flatMap
:Dalam contoh kedua, Stream Daftar dilewatkan. Ini BUKAN Stream of Integer!
Jika Fungsi transformasi harus digunakan (melalui peta), maka pertama Stream harus diratakan ke sesuatu yang lain (Stream of Integer).
Jika flatMap dihapus maka kesalahan berikut dikembalikan: Operator + tidak terdefinisi untuk daftar tipe argumen, int.
TIDAK mungkin menerapkan +1 pada Daftar Integer!
sumber
Stream<Integer>
daripada StreamInteger
.Silakan melalui pos sepenuhnya untuk mendapatkan ide yang jelas,
peta vs flatMap:
Untuk mengembalikan panjang setiap kata dari daftar, kami akan melakukan sesuatu seperti di bawah ini ..
Versi pendek diberikan di bawah ini
Ketika kami mengumpulkan dua daftar, diberikan di bawah ini
Tanpa peta datar => [1,2], [1,1] => [[1,2], [1,1]] Di sini dua daftar ditempatkan di dalam daftar, sehingga hasilnya adalah daftar yang berisi daftar
Dengan peta datar => [1,2], [1,1] => [1,2,1,1] Di sini dua daftar diratakan dan hanya nilai-nilai yang ditempatkan dalam daftar, sehingga output akan menjadi daftar yang hanya berisi elemen
Pada dasarnya menggabungkan semua objek menjadi satu
## Versi terperinci telah diberikan di bawah ini: -
Misalnya: -
Pertimbangkan daftar ["STACK", "OOOVVVER"] dan kami mencoba mengembalikan daftar seperti ["STACKOVER"] (hanya mengembalikan huruf unik dari daftar itu) Awalnya, kami akan melakukan sesuatu seperti di bawah ini untuk mengembalikan sebuah daftar ["STACKOVER"] dari ["STACK", "OOOVVVER"]
Di sini masalahnya adalah, Lambda diteruskan ke metode peta mengembalikan array String untuk setiap kata, Jadi aliran yang dikembalikan oleh metode peta sebenarnya dari tipe Stream, Tapi yang kita butuhkan adalah Stream untuk mewakili aliran karakter, di bawah gambar menggambarkan masalah.
Gambar A:
Anda mungkin berpikir bahwa, Kita dapat menyelesaikan masalah ini menggunakan flatmap,
OK, mari kita lihat bagaimana menyelesaikannya dengan menggunakan peta dan Array.stream Pertama-tama Anda akan membutuhkan aliran karakter alih-alih aliran array. Ada metode yang disebut Arrays.stream () yang akan mengambil array dan menghasilkan aliran, misalnya:
Hal di atas masih tidak berfungsi, karena sekarang kita berakhir dengan daftar aliran (lebih tepatnya, Stream>), Alih-alih, kita harus terlebih dahulu mengonversikan setiap kata menjadi array dari setiap huruf dan kemudian membuat setiap array menjadi aliran yang terpisah
Dengan menggunakan flatMap kita harus dapat memperbaiki masalah ini seperti di bawah ini:
flatMap akan melakukan pemetaan setiap larik tidak dengan aliran tetapi dengan isi aliran itu. Semua aliran individual yang akan dihasilkan saat menggunakan peta (Array :: stream) digabung menjadi satu aliran. Gambar B menggambarkan efek dari menggunakan metode flatMap. Bandingkan dengan apa yang dilakukan peta pada gambar A. Gambar B
Metode flatMap memungkinkan Anda mengganti setiap nilai aliran dengan aliran lain dan kemudian menggabungkan semua aliran yang dihasilkan menjadi satu aliran.
sumber
Satu jawaban baris:
flatMap
membantu meratakanCollection<Collection<T>>
aCollection<T>
. Dengan cara yang sama, itu juga akan meratakanOptional<Optional<T>>
ke dalamOptional<T>
.Seperti yang Anda lihat,
map()
hanya dengan :Stream<List<Item>>
List<List<Item>>
dan dengan
flatMap()
:Stream<Item>
List<Item>
Ini adalah hasil tes dari kode yang digunakan tepat di bawah ini:
Kode yang digunakan :
sumber
Fungsi yang Anda lewati
stream.map
harus mengembalikan satu objek. Itu berarti setiap objek dalam aliran input menghasilkan tepat satu objek dalam aliran output.Fungsi yang Anda lewati untuk
stream.flatMap
mengembalikan aliran untuk setiap objek. Itu berarti fungsi dapat mengembalikan sejumlah objek untuk setiap objek input (termasuk tidak ada). Aliran yang dihasilkan kemudian disatukan menjadi satu aliran keluaran.sumber
Department
di organisasi Anda. Setiap departemen memiliki antara 0 dan nEmployee
s. Yang Anda butuhkan adalah aliran semua karyawan. Jadi apa yang kamu lakukan? Anda menulis metode flatMap yang mengambil departemen dan mengembalikan aliran karyawannya.flatMap
? Saya menduga itu mungkin insidentil dan tidak menggambarkan kasus penggunaan utama atau alasan mengapaflatMap
ada. (Lanjutan di bawah ...)flatMap
adalah untuk mengakomodasi kesalahan yang akan muncul saat menggunakanmap
. Bagaimana Anda menangani kasus di mana satu atau lebih item dalam set asli tidak dapat dipetakan ke item output? Dengan memperkenalkan set perantara (katakanlahOptional
atauStream
) untuk setiap objek input,flatMap
memungkinkan Anda untuk mengecualikan objek input "tidak valid" (atau yang disebut "apel buruk" dalam semangat stackoverflow.com/a/52248643/107158 ) dari set terakhir.untuk Peta kita memiliki daftar elemen dan (fungsi, tindakan) f sehingga:
dan untuk peta datar kami memiliki daftar daftar elemen dan kami memiliki (fungsi, tindakan) f dan kami ingin hasilnya diratakan:
sumber
Saya merasa bahwa sebagian besar jawaban di sini terlalu rumit untuk masalah sederhana. Jika Anda sudah mengerti bagaimana cara
map
kerjanya itu harus cukup mudah dipahami.Ada kasus di mana kita bisa berakhir dengan struktur bersarang yang tidak diinginkan saat menggunakan
map()
,flatMap()
metode ini dirancang untuk mengatasinya dengan menghindari pembungkus.Contoh:
1
Kami dapat menghindari daftar bersarang dengan menggunakan
flatMap
:2
dimana:
sumber
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());
. SeharusnyaStream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
Artikel Oracle tentang Opsional menyoroti perbedaan antara peta dan flatmap:
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
sumber
Saya tidak begitu yakin saya harus menjawab ini, tetapi setiap kali saya menghadapi seseorang yang tidak mengerti ini, saya menggunakan contoh yang sama.
Bayangkan Anda memiliki sebuah apel. A
map
mentransformasikan apel itu menjadiapple-juice
misalnya atau pemetaan satu-ke-satu .Ambil apel yang sama dan dapatkan hanya biji dari itu, itulah yang
flatMap
dilakukan, atau apel satu ke banyak , satu apel sebagai input, banyak biji sebagai output.sumber
flatMap
kasus ini, apakah Anda pertama-tama mengumpulkan benih dari setiap apel dalam kantong terpisah, satu kantong per apel, sebelum Anda menuangkan semua tas ke dalam satu tas?flatmap
tidak benar-benar malas, tetapi karena java-10 itu malasflatMap + lazy
, saya yakin akan ada beberapa jawaban.map () dan flatMap ()
map()
Hanya membutuhkan sebuah Fungsi lambda param di mana T adalah elemen dan R elemen kembali dibangun menggunakan T. Pada akhirnya kita akan memiliki Stream dengan objek Tipe R. Contoh sederhana dapat:
Ini hanya membutuhkan elemen 1 hingga 5 dari Tipe
Integer
, menggunakan setiap elemen untuk membangun elemen baru dari tipeString
dengan nilai"prefix_"+integer_value
dan mencetaknya.flatMap()
Sangat berguna untuk mengetahui bahwa flatMap () mengambil fungsi di
F<T, R>
manaT adalah jenis dari mana Stream dapat dibangun dari / dengan . Ini bisa berupa Daftar (T.stream ()), array (Arrays.stream (someArray)), dll. Apa pun yang darinya Aliran dapat dengan / atau bentuk. dalam contoh di bawah ini setiap dev memiliki banyak bahasa, jadi dev. Bahasa adalah Daftar dan akan menggunakan parameter lambda.
R adalah Aliran yang dihasilkan yang akan dibangun menggunakan T. Mengetahui bahwa kita memiliki banyak contoh T, kita secara alami akan memiliki banyak Aliran dari R. Semua Aliran ini dari Tipe R sekarang akan digabungkan menjadi satu Aliran 'flat' tunggal dari Tipe R .
Contoh
Contoh-contoh Bachiri Taoufiq lihat jawabannya di sini sederhana dan mudah dimengerti. Hanya untuk kejelasan, katakan saja kami memiliki tim pengembang:
, dengan setiap pengembang mengetahui banyak bahasa:
Menerapkan Stream.map () di dev_team untuk mendapatkan bahasa dari masing-masing dev:
akan memberi Anda struktur ini:
yang pada dasarnya adalah a
List<List<Languages>> /Object[Languages[]]
. Tidak terlalu cantik, tidak seperti Java8 !!dengan
Stream.flatMap()
Anda dapat 'meratakan' hal-hal karena mengambil struktur di atasdan mengubahnya menjadi
{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, yang pada dasarnya dapat digunakan sebagaiList<Languages>/Language[]/etc
...jadi pada akhirnya, kode Anda akan lebih masuk akal seperti ini:
atau hanya:
Kapan menggunakan peta () dan menggunakan flatMap () :
Gunakan
map()
ketika setiap elemen tipe T dari aliran Anda seharusnya dipetakan / diubah menjadi elemen tunggal tipe R. Hasilnya adalah pemetaan tipe (1 elemen awal -> 1 elemen ujung) dan aliran baru elemen tipe R dikembalikan.Gunakan
flatMap()
ketika setiap elemen tipe T dari aliran Anda seharusnya dipetakan / diubah menjadi Koleksi elemen tipe R. Hasilnya adalah pemetaan tipe (1 elemen awal -> n elemen ujung) . Koleksi ini kemudian digabung (atau diratakan ) ke aliran baru elemen tipe R. Ini berguna misalnya untuk mewakili loop bersarang .Pra Jawa 8:
Pos Jawa 8
sumber
Peta: - Metode ini mengambil satu Fungsi sebagai argumen dan mengembalikan aliran baru yang terdiri dari hasil yang dihasilkan dengan menerapkan fungsi yang diteruskan ke semua elemen aliran.
Mari kita bayangkan, saya memiliki daftar nilai integer (1,2,3,4,5) dan satu antarmuka fungsi yang logikanya adalah kuadrat dari bilangan bulat yang dilewati. (e -> e * e).
keluaran:-
Seperti yang Anda lihat, output adalah aliran baru yang nilainya kuadrat dari nilai aliran input.
http://codedestine.com/java-8-stream-map-method/
FlatMap: - Metode ini mengambil satu Fungsi sebagai argumen, fungsi ini menerima satu parameter T sebagai argumen input dan mengembalikan satu aliran parameter R sebagai nilai balik. Ketika fungsi ini diterapkan ke setiap elemen aliran ini, itu menghasilkan aliran nilai-nilai baru. Semua elemen aliran baru yang dihasilkan oleh setiap elemen kemudian disalin ke aliran baru, yang akan menjadi nilai balik dari metode ini.
Mari kita gambar, saya memiliki daftar objek siswa, di mana setiap siswa dapat memilih beberapa mata pelajaran.
keluaran:-
Seperti yang Anda lihat, output adalah aliran baru yang nilainya merupakan kumpulan dari semua elemen aliran yang dikembalikan oleh setiap elemen aliran input.
[S1, S2, S3] -> [{"sejarah", "matematika", "geografi"}, {"ekonomi", "biologi"}, {"sains", "matematika"}] -> ambil mata pelajaran unik - > [ekonomi, biologi, geografi, sains, sejarah, matematika]
http://codedestine.com/java-8-stream-flatmap-method/
sumber
.map untuk pemetaan A -> B
itu mengkonversi item
A
apa saja menjadi item apa sajaB
. Javadoc.flatMap untuk A -> Stream <B> menggabungkan
--1 mengonversi item apa saja
A
menjadiStream< B>
, kemudian --2 menggabungkan semua aliran menjadi satu aliran (datar). JavadocCatatan 1: Meskipun contoh terakhir flat ke aliran primitif (IntStream), bukan aliran objek (Stream), itu masih menggambarkan ide dari
.flatMap
.Catatan 2: Terlepas dari namanya, metode String.chars () mengembalikan int. Jadi koleksi aktualnya adalah:, di
[100, 111, 103, 99, 97, 116]
mana100
kodenya'd'
,111
adalah kodenya'o'
dll. Sekali lagi, untuk tujuan ilustrasi, itu disajikan sebagai [d, o, g, c, a, t].sumber
Jawaban sederhana
The
map
operasi dapat menghasilkanStream
dariStream
.exStream<Stream<Integer>>
flatMap
operasi hanya akan menghasilkanStream
sesuatu. EXStream<Integer>
sumber
Analogi yang bagus juga bisa dengan C # jika Anda terbiasa. Pada dasarnya C #
Select
mirip dengan javamap
dan C #SelectMany
javaflatMap
. Hal yang sama berlaku untuk Kotlin untuk koleksi.sumber
Ini sangat membingungkan bagi pemula. Perbedaan dasarnya adalah
map
memancarkan satu item untuk setiap entri dalam daftar danflatMap
pada dasarnya adalah operasimap
+flatten
. Agar lebih jelas, gunakan flatMap ketika Anda membutuhkan lebih dari satu nilai, misalnya ketika Anda mengharapkan loop untuk mengembalikan array, flatMap akan sangat membantu dalam hal ini.Saya telah menulis blog tentang ini, Anda dapat memeriksanya di sini .
sumber
Alirkan operasi
flatMap
danmap
terima fungsi sebagai input.flatMap
mengharapkan fungsi untuk mengembalikan aliran baru untuk setiap elemen aliran dan mengembalikan aliran yang menggabungkan semua elemen aliran yang dikembalikan oleh fungsi untuk setiap elemen. Dengan kata lain, denganflatMap
, untuk setiap elemen dari sumber, beberapa elemen akan dibuat oleh fungsi. http://www.zoftino.com/java-stream-examples#flatmap-operationmap
mengharapkan fungsi untuk mengembalikan nilai yang diubah dan mengembalikan aliran baru yang mengandung elemen yang diubah. Dengan kata lain, denganmap
, untuk setiap elemen dari sumber, satu elemen yang diubah akan dibuat oleh fungsi. http://www.zoftino.com/java-stream-examples#map-operationsumber
flatMap()
juga mengambil keuntungan dari evaluasi aliran malas sebagian. Ini akan membaca aliran pertama dan hanya jika diperlukan, akan pergi ke aliran berikutnya. Perilaku ini dijelaskan secara rinci di sini: Apakah flatMap dijamin malas?sumber
Jika Anda berpikir
map()
sebagai iterasi (satu tingkatfor
loop),flatmap()
adalah iterasi dua tingkat (sepertifor
loop bersarang ). (Masukkan setiap elemen yang diulangfoo
, dan lakukanfoo.getBarList()
dan ulangi di dalamnyabarList
lagi)map()
: ambil aliran, lakukan sesuatu untuk setiap elemen, kumpulkan hasil tunggal dari setiap proses, keluaran aliran lain. Definisi "melakukan sesuatu fungsi" adalah implisit. Jika proses dari setiap elemen menghasilkannull
,null
digunakan untuk menyusun aliran akhir. Jadi, jumlah elemen dalam aliran yang dihasilkan akan sama dengan jumlah aliran input.flatmap()
: ambil aliran elemen / aliran dan fungsi (definisi eksplisit), terapkan fungsi ke setiap elemen dari setiap aliran, dan kumpulkan semua aliran hasil antara menjadi aliran yang lebih besar ("perataan"). Jika proses dari setiap elemen menghasilkannull
, aliran kosong disediakan untuk langkah terakhir "perataan". Jumlah elemen dalam aliran yang dihasilkan, adalah total dari semua elemen yang berpartisipasi dalam semua input, jika input beberapa aliran.sumber