Java: Gibt es eine Kartenfunktion?

140

Ich brauche eine Kartenfunktion . Gibt es so etwas schon in Java?

(Für diejenigen, die sich fragen: Ich weiß natürlich, wie man diese triviale Funktion selbst implementiert ...)

Albert
quelle
1
Wenn nicht, ist es trivial, sich selbst zu definieren. Aber ich nehme an, Google kennt ein Dutzend Implementierungen?
2
Dupliziert (eher besser) unter stackoverflow.com/questions/3907412/…
Chowlett
6
@ Chris: Wie ist es die gleiche Frage?
Albert
1
Wenn die Antwort auf diese Frage Ja lautet, wird auch die andere verknüpfte Frage beantwortet. Wenn die Antwort nein ist (und es scheint so), sind sie völlig unabhängig.
Albert
1
Ab Java8 hat sich @delnan möglicherweise auf leveluplunch.com/java/examples/… bezogen
Eternalcode

Antworten:

86

Es gibt keine Vorstellung von einer Funktion im JDK ab Java 6.

Guava verfügt jedoch über eine Funktionsschnittstelle und die Methode bietet die von Ihnen benötigte Funktionalität.
Collections2.transform(Collection<E>, Function<E,E2>)

Beispiel:

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

Ausgabe:

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

Heutzutage gibt es mit Java 8 tatsächlich eine Kartenfunktion, daher würde ich den Code wahrscheinlich präziser schreiben:

Collection<String> hex = input.stream()
                              .map(Integer::toHexString)
                              .collect(Collectors::toList);
Sean Patrick Floyd
quelle
8
Es ist erwähnenswert, dass , während sie mit Guava Sie können dies tun, werden Sie nicht möchten: code.google.com/p/guava-libraries/wiki/FunctionalExplained (Lesen Sie den Abschnitt „Vorsichtsmaßnahmen“).
Adam Parkin
2
@AdamParkin stimmt, aber ich bin mir ziemlich sicher, dass sich dies auf fortgeschrittenere Funktionskonzepte bezieht, sonst hätten sie die transform ( ) -Methoden gar nicht erst entwickelt
Sean Patrick Floyd
2
Nein, es gibt oft einen eindeutigen Leistungseinbruch bei funktionalen Redewendungen, weshalb sie betonen, dass Sie die Einrichtungen nur verwenden sollten, wenn Sie sicher sind, dass sie die beiden genannten Kriterien erfüllen: Nettoeinsparungen von LOC für die gesamte Codebasis und bewiesen Leistungssteigerungen durch verzögerte Bewertung (oder zumindest keine Leistungstreffer). Nicht gegen deren Verwendung argumentieren, sondern nur darauf hinweisen, dass Sie die Warnungen der Implementierer beachten sollten, wenn Sie dies tun.
Adam Parkin
3
@SeanPatrickFloyd Jetzt, da Java 8 verfügbar ist, möchten Sie dies mit einem Beispiel für Lambdas aktualisieren? Gefällt Collections2.transform(input -> Integer.toHexString(intput.intValue())
mir
2
@ Daniel In Java 8 sehe ich keinen Grund, dies mit Guava zu tun. Stattdessen würde ich mich für Leventovs Antwort entscheiden
Sean Patrick Floyd,
91

Seit Java 8 gibt es einige Standardoptionen, um dies in JDK zu tun:

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

Siehe java.util.Collection.stream()und java.util.stream.Collectors.toList().

leventov
quelle
140
Das ist so ausführlich, dass es mich innerlich verletzt.
Natix
1
@ Natix stimme zu toList(). Ersetzen auf einen anderen Typ:(List<R>)((List) list).replaceAll(o -> doMap((E) o));
Leventov
2
Kann e -> doMap(e)durch nur ersetzt werden doMap?
Jameshfisher
3
@ Jameshfisher, ja, so etwas wie foo::doMapoder Foo::doMap.
Leventov
9
Ich denke, deshalb gibt es Scala. Warten Sie, bis Java 12 lesbar ist.
JulienD
26

Es gibt eine wunderbare Bibliothek namens Functional Java, die viele der Dinge behandelt, die Java haben soll, aber nicht. Andererseits gibt es auch diese wunderbare Sprache Scala, die alles tut, was Java hätte tun sollen, aber nicht mit allem kompatibel ist, was für die JVM geschrieben wurde.

Wheaties
quelle
Ich bin daran interessiert, wie sie die folgende Syntax aktiviert haben: a.map({int i => i + 42});Haben sie den Compiler erweitert? oder Präprozessor hinzugefügt?
Andrey
@Andrey - Sie können sie entweder selbst fragen oder den Quellcode überprüfen, um zu sehen, wie es gemacht wird. Hier ist ein Link zur Quelle: Functionaljava.org/source
Wheaties
1
@Andrey: Beispiele verwenden die Syntax aus dem Vorschlag für BGGA-Schließungen. Während es einen laufenden Prototyp gibt, ist er noch nicht in 'offiziellem' Java.
Peter Štibraný
@Andrey: Diese Syntax ist Teil einer vorgeschlagenen Spezifikation für Schließungen in Java (siehe vorletzten Absatz auf der Homepage). Es gibt nur eine prototypische Implementierung.
Michael Borgwardt
2
Scala Thread Hijack :( Ich hoffe, SO wird nicht wie die JavaPosse Mailingliste;)
Jorn
9

Seien Sie sehr vorsichtig mit Collections2.transform()Guaven. Der größte Vorteil dieser Methode ist auch ihre größte Gefahr: ihre Faulheit.

Schauen Sie sich die Dokumentation an Lists.transform(), von der ich glaube, dass sie auch gilt für Collections2.transform():

Die Funktion wird träge angewendet und bei Bedarf aufgerufen. Dies ist erforderlich, damit die zurückgegebene Liste eine Ansicht ist. Dies bedeutet jedoch, dass die Funktion für Massenoperationen wie List.contains (java.lang.Object) und List.hashCode () mehrmals angewendet wird. Damit dies gut funktioniert, sollte die Funktion schnell sein. Kopieren Sie die zurückgegebene Liste in eine neue Liste Ihrer Wahl, um eine verzögerte Auswertung zu vermeiden, wenn die zurückgegebene Liste keine Ansicht sein muss.

Auch in der Dokumentation wird Collections2.transform()erwähnt, dass Sie eine Live-Ansicht erhalten, die sich in der Quellliste auf die transformierte Liste auswirkt. Diese Art von Verhalten kann zu schwer zu verfolgenden Problemen führen, wenn der Entwickler nicht erkennt, wie es funktioniert.

Wenn Sie eine klassischere "Karte" möchten, die nur einmal ausgeführt wird, sind Sie besser dran FluentIterable, auch von Guava aus, die eine viel einfachere Operation hat. Hier ist das Google-Beispiel dafür:

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

transform()Hier ist die Kartenmethode. Es verwendet die gleiche Funktion <> "Rückrufe" wie Collections.transform(). Die Liste, die Sie zurückerhalten, ist schreibgeschützt. Verwenden Sie diese Option, copyInto()um eine Lese- / Schreibliste abzurufen.

Andernfalls ist dies natürlich veraltet, wenn Java8 mit Lambdas herauskommt.

Emmanuel Touzery
quelle
2

Obwohl es eine alte Frage ist, möchte ich eine andere Lösung zeigen:

Definieren Sie einfach Ihre eigene Operation mit Java Generics und Java 8 Streams:

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

Dann können Sie Code wie folgt schreiben:

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