Java: apakah ada fungsi peta?

140

Saya membutuhkan fungsi peta . Apakah sudah ada yang seperti ini di Jawa?

(Bagi mereka yang bertanya-tanya: Saya tentu saja tahu sendiri bagaimana mengimplementasikan fungsi sepele ini ...)

Albert
sumber
1
Jika tidak, itu sepele untuk mendefinisikan diri sendiri. Tapi saya kira google tahu selusin implementasi?
2
Digandakan (agak lebih baik) di stackoverflow.com/questions/3907412/…
Chowlett
6
@ Chris: Bagaimana pertanyaannya sama?
Albert
1
Jika jawaban untuk pertanyaan ini adalah ya, itu menjawab juga pertanyaan terkait lainnya. Jika jawabannya tidak (dan tampaknya demikian), mereka sama sekali tidak terkait.
Albert
1
Pada Java8, Inilah yang mungkin merujuk @delnan
Eternalcode

Jawaban:

86

Tidak ada gagasan tentang fungsi di JDK pada java 6.

Jambu memiliki antarmuka fungsi dan metode menyediakan fungsionalitas yang Anda butuhkan.
Collections2.transform(Collection<E>, Function<E,E2>)

Contoh:

// example, converts a collection of integers to their
// hexadecimal string representations
final Collection<Integer> input = Arrays.asList(10, 20, 30, 40, 50);
final Collection<String> output =
    Collections2.transform(input, new Function<Integer, String>(){

        @Override
        public String apply(final Integer input){
            return Integer.toHexString(input.intValue());
        }
    });
System.out.println(output);

Keluaran:

[a, 14, 1e, 28, 32]

Saat ini, dengan Java 8, sebenarnya ada fungsi peta, jadi saya mungkin akan menulis kode dengan cara yang lebih ringkas:

Collection<String> hex = input.stream()
                              .map(Integer::toHexString)
                              .collect(Collectors::toList);
Sean Patrick Floyd
sumber
8
Perlu dicatat bahwa sementara dengan Guava Anda dapat melakukan ini, Anda mungkin tidak ingin: code.google.com/p/guava-libraries/wiki/FunctionalExplained (baca bagian "Peringatan").
Adam Parkin
2
@ AdamParkin benar, tapi saya cukup yakin itu merujuk pada konsep fungsional yang lebih maju daripada ini, kalau tidak mereka tidak akan mengembangkan metode transform ( ) di tempat pertama
Sean Patrick Floyd
2
Sebenarnya, tidak, sering ada kinerja yang pasti dipukul dengan idiom fungsional, itulah sebabnya mereka menekankan Anda hanya boleh menggunakan fasilitas jika Anda yakin itu memenuhi dua kriteria yang diuraikan: penghematan bersih LOC untuk basis kode secara keseluruhan, dan terbukti peningkatan kinerja karena evaluasi yang malas (atau setidaknya tidak mencapai kinerja). Tidak memperdebatkan penggunaannya, hanya menunjukkan bahwa jika Anda akan melakukannya, Anda harus memperhatikan peringatan dari pelaksana.
Adam Parkin
4
@SeanPatrickFloyd sekarang setelah Java 8 keluar, ingin memperbarui ini dengan contoh yang melibatkan lambdas? SepertiCollections2.transform(input -> Integer.toHexString(intput.intValue())
Daniel Lubarov
2
@Aniel Di Java 8, saya tidak melihat alasan untuk melakukan itu dengan Guava. Sebagai gantinya saya akan mencari jawaban leventov
Sean Patrick Floyd
92

Sejak Java 8, ada beberapa opsi standar untuk melakukan ini di JDK:

Collection<E> in = ...
Object[] mapped = in.stream().map(e -> doMap(e)).toArray();
// or
List<E> mapped = in.stream().map(e -> doMap(e)).collect(Collectors.toList());

Lihat java.util.Collection.stream()dan java.util.stream.Collectors.toList().

leventov
sumber
140
Ini sangat banyak verbose yang menyakitkan saya di dalam.
Natix
1
@Natix setuju tentang toList(). Mengganti ke jenis yang berbeda:(List<R>)((List) list).replaceAll(o -> doMap((E) o));
leventov
2
Bisakah e -> doMap(e)diganti dengan adil doMap?
jameshfisher
3
@ jameshfisher, ya, sesuatu seperti foo::doMapatau Foo::doMap.
leventov
9
Saya kira inilah sebabnya Scala ada. Tunggu Java 12 untuk memiliki sesuatu yang dapat dibaca.
JulienD
26

Ada perpustakaan indah yang disebut Java Fungsional yang menangani banyak hal yang Anda ingin memiliki Jawa tetapi tidak. Kemudian lagi, ada juga bahasa Scala yang luar biasa ini yang melakukan semua yang seharusnya dilakukan oleh Java tetapi tetap kompatibel dengan apa pun yang ditulis untuk JVM.

wheaties
sumber
Saya tertarik pada bagaimana mereka mengaktifkan sintaks berikut: a.map({int i => i + 42});apakah mereka memperpanjang compiler? atau menambahkan preprosesor?
Andrey
@ Andrew - Anda dapat menanyakannya sendiri atau memeriksa kode sumber untuk melihat bagaimana hal itu dilakukan. Berikut tautan ke sumber: functionaljava.org/source
wheaties
1
@ Andrew: contoh menggunakan sintaksis dari proposal penutupan BGGA. Meskipun ada menjalankan prototipe, itu belum di Jawa 'resmi'.
Peter Štibraný
@Andrey: sintaks itu adalah bagian dari spesifikasi yang diusulkan untuk penutupan di Jawa (lihat paragraf kedua hingga terakhir di beranda). Hanya ada implementasi prototipikal.
Michael Borgwardt
2
Scala thread hijack :( Saya harap SO tidak akan menjadi seperti mailing list JavaPosse;)
Jorn
9

Berhati-hatilah dengan Collections2.transform()dari jambu biji. Keuntungan terbesar metode itu juga bahaya terbesarnya: kemalasannya.

Lihatlah dokumentasi Lists.transform(), yang saya percaya berlaku juga untuk Collections2.transform():

Fungsi ini diterapkan dengan malas, dipanggil saat dibutuhkan. Ini diperlukan untuk daftar yang dikembalikan menjadi tampilan, tetapi itu berarti bahwa fungsi akan diterapkan berkali-kali untuk operasi massal seperti List.contains (java.lang.Object) dan List.hashCode (). Agar ini berfungsi dengan baik, fungsinya harus cepat. Untuk menghindari evaluasi malas ketika daftar yang dikembalikan tidak perlu dilihat, salin daftar yang dikembalikan ke daftar baru yang Anda pilih.

Juga dalam dokumentasi Collections2.transform()mereka menyebutkan Anda mendapatkan tampilan langsung, bahwa perubahan dalam daftar sumber mempengaruhi daftar yang diubah. Perilaku semacam ini dapat menyebabkan masalah yang sulit dilacak jika pengembang tidak menyadari cara kerjanya.

Jika Anda menginginkan "peta" yang lebih klasik, yang akan berjalan sekali dan sekali saja, maka Anda lebih baik FluentIterable, juga dari Guava, yang memiliki operasi yang jauh lebih sederhana. Ini adalah contoh google untuk itu:

FluentIterable
       .from(database.getClientList())
       .filter(activeInLastMonth())
       .transform(Functions.toStringFunction())
       .limit(10)
       .toList();

transform()di sini adalah metode peta. Ini menggunakan Fungsi yang sama <> "callbacks" seperti Collections.transform(). Daftar yang Anda dapatkan hanya baca-saja, gunakan copyInto()untuk mendapatkan daftar baca-tulis.

Kalau tidak tentu saja ketika java8 keluar dengan lambdas, ini akan usang.

Emmanuel Touzery
sumber
2

Meskipun ini adalah pertanyaan lama, saya ingin menunjukkan solusi lain:

Cukup tentukan operasi Anda sendiri menggunakan java generics dan java 8 stream:

public static <S, T> List<T> map(Collection<S> collection, Function<S, T> mapFunction) {
   return collection.stream().map(mapFunction).collect(Collectors.toList());
}

Daripada Anda dapat menulis kode seperti ini:

List<String> hex = map(Arrays.asList(10, 20, 30, 40, 50), Integer::toHexString);
IPP Nerd
sumber