В этом конкретном примере вообще нет необходимости создавать промежуточное хранилище:
Map<T, V> transform(List<T> item) {
return item.stream().collect(toMap(x -> x, x -> doTransform(x)));
}
Но если вам это нужно, Java 9 предлагает более простой фабричный метод,
Map<T, V> transform(List<T> item) {
return item.stream()
.map(x -> Map.entry(x, doTransform(x)))
.collect(toMap(x -> x.getKey(), x -> x.getValue()));
}
до тех пор, пока вам не нужно иметь дело с null
.
Здесь вы можете использовать анонимный внутренний класс,
Map<T, V> transform(List<T> item) {
return item.stream()
.map(x -> new Object(){ T t = x; V v = doTransform(x); })
.collect(toMap(x -> x.t, x -> x.v));
}
, но он менее эффективен.Это внутренний класс, который захватывает ссылку на окружающий this
, также он захватывает x
, поэтому у вас есть два поля, t
и синтетическое для захвата x
, для одной и той же вещи.
Последний можно обойти с помощью метода, например
Map<T, V> transform(List<T> item) {
return item.stream()
.map(x -> new Object(){ T getKey() { return x; } V v = doTransform(x); })
.collect(toMap(x -> x.getKey(), x -> x.v));
}
Но это не добавляет читабельности.
Единственными истинными анонимными типами являются типы, сгенерированные для лямбда-выражений,который может быть использован для хранения информации с помощью функций более высокого порядка:
Map<T, V> transform(List<T> item) {
return item.stream()
.map(x -> capture(x, doTransform(x)))
.collect(HashMap::new, (m,f) -> f.accept(m::put), HashMap::putAll);
}
public static <A,B> Consumer<BiConsumer<A,B>> capture(A a, B b) {
return f -> f.accept(a, b);
}
, но вы скоро столкнетесь с ограничениями системы типов Java (она по-прежнему не является функциональным языком программирования), если вы попытаетесьэто с более сложными сценариями.