Potrzebuję funkcji mapy . Czy jest już coś takiego w Javie?
(Dla tych, którzy się zastanawiają: oczywiście wiem, jak sam zaimplementować tę banalną funkcję ...)
Potrzebuję funkcji mapy . Czy jest już coś takiego w Javie?
(Dla tych, którzy się zastanawiają: oczywiście wiem, jak sam zaimplementować tę banalną funkcję ...)
Odpowiedzi:
W JDK nie ma pojęcia funkcji od wersji java 6.
Guava ma jednak interfejs funkcji , a
metoda zapewnia wymaganą funkcjonalność.
Collections2.transform(Collection<E>, Function<E,E2>)
Przykład:
// 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);
Wynik:
[a, 14, 1e, 28, 32]
W dzisiejszych czasach, w Javie 8, istnieje funkcja mapy, więc prawdopodobnie napisałbym kod w bardziej zwięzły sposób:
Collection<String> hex = input.stream()
.map(Integer::toHexString)
.collect(Collectors::toList);
Collections2.transform(input -> Integer.toHexString(intput.intValue())
Od wersji Java 8 istnieje kilka standardowych opcji umożliwiających to w 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());
Zobacz java.util.Collection.stream()
i java.util.stream.Collectors.toList()
.
toList()
. Wymiana na inny typ:(List<R>)((List) list).replaceAll(o -> doMap((E) o));
e -> doMap(e)
można zastąpić tylko doMap
?
foo::doMap
lub Foo::doMap
.
Istnieje wspaniała biblioteka o nazwie Functional Java, która obsługuje wiele rzeczy, które chciałbyś mieć Java, ale tak nie jest. Z drugiej strony jest też ten wspaniały język Scala, który robi wszystko, co powinna była zrobić Java, ale nie robi tego, jednocześnie będąc kompatybilnym ze wszystkim, co napisano dla JVM.
a.map({int i => i + 42});
czy rozszerzyli kompilator? lub dodany preprocesor?
Uważaj Collections2.transform()
na guawy. Największą zaletą tej metody jest też największe niebezpieczeństwo: jej lenistwo.
Spójrz na dokumentację Lists.transform()
, która moim zdaniem dotyczy również Collections2.transform()
:
Funkcja jest stosowana leniwie, wywoływana w razie potrzeby. Jest to konieczne, aby zwrócona lista była widokiem, ale oznacza to, że funkcja będzie stosowana wiele razy do operacji zbiorczych, takich jak List.contains (java.lang.Object) i List.hashCode (). Aby to działało dobrze, funkcja powinna być szybka. Aby uniknąć leniwej oceny, gdy zwracana lista nie musi być widokiem, skopiuj zwróconą listę do nowej wybranej listy.
Również w dokumentacji Collections2.transform()
wspominają, że masz podgląd na żywo, że zmiana na liście źródeł wpływa na przekształconą listę. Takie zachowanie może prowadzić do trudnych do wyśledzenia problemów, jeśli programista nie zdaje sobie sprawy, jak to działa.
Jeśli chcesz mieć bardziej klasyczną „mapę”, która będzie działać tylko raz, to lepiej będzie, jeśli chcesz FluentIterable
, również z Guawy, która ma znacznie prostszą operację. Oto przykład google:
FluentIterable
.from(database.getClientList())
.filter(activeInLastMonth())
.transform(Functions.toStringFunction())
.limit(10)
.toList();
transform()
tutaj jest metoda mapy. Używa tej samej funkcji <> "wywołania zwrotne" co Collections.transform()
. Lista, którą otrzymujesz, jest jednak tylko copyInto()
do odczytu , użyj jej, aby uzyskać listę do odczytu i zapisu.
W przeciwnym razie, oczywiście, gdy java8 wyjdzie z lambdami, będzie to przestarzałe.
To jest kolejna funkcjonalna biblioteka, z którą możesz korzystać z mapy: http://code.google.com/p/totallylazy/
sequence(1, 2).map(toString); // lazily returns "1", "2"
Choć to stare pytanie, chciałbym pokazać inne rozwiązanie:
Po prostu zdefiniuj własną operację za pomocą generycznych java i strumieni Java 8:
public static <S, T> List<T> map(Collection<S> collection, Function<S, T> mapFunction) {
return collection.stream().map(mapFunction).collect(Collectors.toList());
}
Niż możesz napisać taki kod:
List<String> hex = map(Arrays.asList(10, 20, 30, 40, 50), Integer::toHexString);