Java: Bir harita işlevi var mı?


140

Bir harita fonksiyonuna ihtiyacım var . Java'da zaten böyle bir şey var mı?

(Merak edenler için: Elbette bu önemsiz işlevi kendim nasıl uygulayacağımı biliyorum ...)


1
Değilse, kendinizi tanımlamak önemsizdir. Ama sanırım google bir düzine uygulamayı biliyor?


6
@Chris: Aynı soru nasıl?
Albert

1
Bu sorunun cevabı evet ise, diğer bağlantılı soruya da cevap verir. Cevap hayır ise (ve öyle görünüyorsa), tamamen ilgisizdirler.
Albert

1
Java8'den itibaren, @delnan'ın leveluplunch.com/java/examples/…
Eternalcode

Yanıtlar:


86

Java 6'dan itibaren JDK'da bir işlev fikri yoktur.

Guava'da bir İşlev arayüzü var ve yöntem ihtiyacınız olan işlevselliği sağlıyor.
Collections2.transform(Collection<E>, Function<E,E2>)

Misal:

// 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);

Çıktı:

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

Bu günlerde, Java 8 ile aslında bir harita işlevi var, bu yüzden muhtemelen kodu daha özlü bir şekilde yazardım:

Collection<String> hex = input.stream()
                              .map(Integer::toHexString)
                              .collect(Collectors::toList);

8
Guava ile bunu yapabilirken şunu yapmak istemeyebilirsiniz: code.google.com/p/guava-libraries/wiki/FunctionalExplained ("Uyarılar" bölümünü okuyun).
Adam Parkin

2
@AdamParkin doğru, ancak bundan daha gelişmiş fonksiyonel kavramlara atıfta bulunduğundan eminim, aksi takdirde ilk önce transform ( ) yöntemlerini geliştirmezlerdi
Sean Patrick Floyd

2
Aslında, hayır, genellikle fonksiyonel deyimlerle belirli bir performans isabeti vardır, bu yüzden tesisleri yalnızca belirtilen iki kriteri karşıladığından eminseniz kullanmanız gerektiğini vurgularlar: kod tabanı için bir bütün olarak LOC'un net tasarrufu ve kanıtlanmış tembel değerlendirmeye bağlı performans kazançları (veya en azından performans isabetleri). Bunların kullanımına karşı tartışmamak, sadece giderseniz, uygulayıcıların uyarılarını dikkate almanız gerektiğini belirtmek.
Adam Parkin

4
@SeanPatrickFloyd şimdi Java 8 çıktı, bunu lambdas içeren bir örnekle güncellemek mi istiyorsunuz? BeğenCollections2.transform(input -> Integer.toHexString(intput.intValue())
Daniel Lubarov

2
@Daniel Java 8'de Guava ile bunu yapmak için bir neden göremiyorum. Onun yerine leventov'un cevabına giderdim
Sean Patrick Floyd

92

Java 8'den beri, bunu JDK'da yapmak için bazı standart seçenekler vardır:

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());

Bkz java.util.Collection.stream()ve java.util.stream.Collectors.toList().


140
Bu o kadar fazla ayrıntı ki içimde canım yanıyor.
Natix

1
@Natix katılıyorum toList(). Farklı tipe değiştirme:(List<R>)((List) list).replaceAll(o -> doMap((E) o));
leventov

2
Sadece e -> doMap(e)ile değiştirilebilir doMap?
jameshfisher

3
@jameshfisher, evet, foo::doMapya da benzeri bir şey Foo::doMap.
leventov

9
Sanýrým bu yüzden Scala var. Java 12'nin okunabilir bir şey olmasını bekleyin.
JulienD

26

Java'nın sahip olmasını istediğiniz şeylerin çoğunu işleyen Fonksiyonel Java adlı harika bir kütüphane var ama öyle değil. Sonra tekrar, Java'nın yapması gereken her şeyi yapan ama yine de JVM için yazılmış bir şeyle uyumlu olmayan bu harika dil Scala da var.


Aşağıdaki sözdizimini nasıl etkinleştirdikleri ile ilgileniyorum: a.map({int i => i + 42});derleyiciyi genişlettiler mi? veya önişlemci eklediniz mi?
Andrey

@Andrey - Onlardan kendiniz isteyebilir veya nasıl yapıldığını görmek için kaynak koduna bakabilirsiniz. İşte kaynağa bir bağlantı: functionjava.org/source
wheaties

1
@Andrey: örnekler, BGGA kapanış teklifinin sözdizimini kullanır. Çalışan prototip olsa da, henüz 'resmi' Java'da değil.
Peter Štibranı

@Andrey: sözdizimi, Java'daki kapaklar için önerilen spesifikasyonun bir parçasıdır (ana sayfadaki sondan ikinci paragrafa bakın). Sadece prototip bir uygulama var.
Michael Borgwardt

2
Scala iplik kaçırmak :( Umarım SO JavaPosse posta listesi gibi olmayacak;)
Jorn

9

Collections2.transform()Guava'dan çok dikkatli olun . Bu yöntemin en büyük avantajı aynı zamanda en büyük tehlikesidir: tembellik.

Aşağıdakiler için de Lists.transform()geçerli olduğuna inandığım belgelere bakın Collections2.transform():

İşlev tembel olarak uygulanır, gerektiğinde çağrılır. Bu, döndürülen listenin bir görünüm olması için gereklidir, ancak bu, List.contains (java.lang.Object) ve List.hashCode () gibi toplu işlemler için işlevin birçok kez uygulanacağı anlamına gelir. Bunun iyi çalışması için işlev hızlı olmalıdır. Döndürülen listenin bir görünüm olması gerekmediğinde tembel değerlendirmeyi önlemek için, döndürülen listeyi seçtiğiniz yeni bir listeye kopyalayın.

Ayrıca belgelerinde Collections2.transform()canlı bir görünüm aldığınızı belirtiyorlar, kaynak listesindeki bu değişiklik dönüştürülmüş listeyi etkiliyor. Bu tür davranışlar, geliştirici çalışma şeklini fark etmezse izlemesi zor sorunlara yol açabilir.

Daha klasik bir "harita" istiyorsanız, bu sadece bir kez ve bir kez çalışır, o zaman FluentIterableçok daha basit bir operasyonu olan Guava'dan daha iyi durumdasınız. İşte bunun için google örneği:

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

transform()İşte harita yöntemi. İle aynı İşlev <> "geri aramalar" kullanır Collections.transform(). Geri aldığınız liste salt okunurdur, copyInto()okuma-yazma listesi almak için kullanın .

Aksi takdirde java8 lambdalarla ortaya çıktığında, bu eski olacak.



2

Eski bir soru olmasına rağmen başka bir çözüm göstermek istiyorum:

Java jeneriklerini ve java 8 akışlarını kullanarak kendi işleminizi tanımlamanız yeterlidir:

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

Bundan böyle kod yazabilirsiniz:

List<String> hex = map(Arrays.asList(10, 20, 30, 40, 50), Integer::toHexString);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.