gpt4 book ai didi

java - 无法在不指定类型参数的情况下将 Java 8 方法与 lambda 参数一起使用

转载 作者:搜寻专家 更新时间:2023-10-30 19:43:03 27 4
gpt4 key购买 nike

我创建了一个带有类型参数的方法,使用这些类型参数返回泛型类型,并采用 Function 参数,这也取决于类型参数。当我使用 lambda 作为参数时,编译器强制我指定方法的参数类型,这感觉不对。

我正在设计一个实用程序类,其中包含与 Stream.flatMap 一起使用的方法。它将每种集合条目映射到包含键和值元素的 FlatEntry,并且可以使用构建器在多个级别上执行此操作。受影响的方法是 flatEntryMapperBuilder。这是代码:

import java.util.function.Function;
import java.util.stream.Stream;

public class GdkStreams
{
public static <T, K, V> Function<T, Stream<FlatEntry<K, V>>> flatEntryMapper(Function<T, K> keyMapper,
Function<T, Stream<V>> valueMapper)
{
return input -> {
K key = keyMapper.apply(input);
return valueMapper.apply(input).map(value -> new FlatEntry<>(key, value));
};
}

public static <T, K, V> FlatEntryMapperBuilder<T, K, V> flatEntryMapperBuilder(Function<T, K> keyMapper,
Function<T, Stream<V>> valueMapper)
{
return new FlatEntryMapperBuilder<>(keyMapper, valueMapper);
}

public static class FlatEntryMapperBuilder<T, K, V>
{
private Function<T, K> keyMapper;

private Function<T, Stream<V>> valueMapper;

private FlatEntryMapperBuilder (Function<T, K> keyMapper, Function<T, Stream<V>> valueMapper)
{
this.keyMapper = keyMapper;
this.valueMapper = valueMapper;
}

public Function<T, Stream<FlatEntry<K, V>>> build()
{
return flatEntryMapper(keyMapper, valueMapper);
}

public <K2, V2> FlatEntryMapperBuilder<T, K, FlatEntry<K2, V2>> chain(Function<V, K2> keyMapper2,
Function<V, Stream<V2>> valueMapper2)
{
return new FlatEntryMapperBuilder<>(keyMapper,
valueMapper.andThen(stream -> stream.flatMap(flatEntryMapper(keyMapper2,
valueMapper2))));
}
}

public static class FlatEntry<K, V>
{
public final K key;

public final V value;

public FlatEntry (K key, V value)
{
this.key = key;
this.value = value;
}
}
}

问题在于它的使用。假设我有:

Map<String, Set<String>> level1Map;

我可以通过以下方式将子 Sets 中的每个元素映射到 FlatEntry:

level1Map.entrySet().stream().flatMap(GdkStreams.flatEntryMapper(Entry::getKey, entry -> entry.getValue().stream()));

而且效果很好。但是当我尝试这样做时:

level1Map.entrySet()
.stream()
.flatMap(GdkStreams.flatEntryMapperBuilder(Entry::getKey, entry -> entry.getValue().stream()).build());

eclipse (Mars 4.5.0) 编译器中断:

- The type Map.Entry does not define getKey(Object) that is applicable here
- The method getValue() is undefined for the type Object
- Type mismatch: cannot convert from GdkStreams.FlatEntryMapperBuilder<Object,Object,Object> to
<unknown>

javac (1.8.0_51) 中断:

MainTest.java:50: error: incompatible types: cannot infer type-variable(s) T,K#1,V#1
.flatMap(GdkStreams.flatEntryMapperBuilder(Entry::getKey, entry -> entry.getValue().stream()).build());
^
(argument mismatch; invalid method reference
method getKey in interface Entry<K#2,V#2> cannot be applied to given types
required: no arguments
found: Object
reason: actual and formal argument lists differ in length)
where T,K#1,V#1,K#2,V#2 are type-variables:
T extends Object declared in method <T,K#1,V#1>flatEntryMapperBuilder(Function<T,K#1>,Function<T,Stream<V#1>>)
K#1 extends Object declared in method <T,K#1,V#1>flatEntryMapperBuilder(Function<T,K#1>,Function<T,Stream<V#1>>)
V#1 extends Object declared in method <T,K#1,V#1>flatEntryMapperBuilder(Function<T,K#1>,Function<T,Stream<V#1>>)
K#2 extends Object declared in interface Entry
V#2 extends Object declared in interface Entry
MainTest.java:50: error: invalid method reference
.flatMap(GdkStreams.flatEntryMapperBuilder(Entry::getKey, entry -> entry.getValue().stream()).build());
^
non-static method getKey() cannot be referenced from a static context
where K is a type-variable:
K extends Object declared in interface Entry
2 errors

如果我将 Entry::getKey 替换为 entry -> entry.getKey(),javac 会显着改变其输出:

MainTest.java:51: error: cannot find symbol
.flatMap(GdkStreams.flatEntryMapperBuilder(entry -> entry.getKey(), entry -> entry.getValue().stream()).build());

^
symbol: method getKey()
location: variable entry of type Object
MainTest.java:51: error: cannot find symbol
.flatMap(GdkStreams.flatEntryMapperBuilder(entry -> entry.getKey(), entry -> entry.getValue().stream()).build());

^
symbol: method getValue()
location: variable entry of type Object
2 errors

它通过指定类型参数编译得很好,这是我所期望的:

level1Map.entrySet()
.stream()
.flatMap(GdkStreams.<Entry<String, Set<String>>, String, String> flatEntryMapperBuilder(Entry::getKey,
entry -> entry.getValue()
.stream())
.build());

或指定参数类型参数之一:

Function<Entry<String, Set<String>>, String> keyGetter = Entry::getKey;
level1Map.entrySet()
.stream()
.flatMap(GdkStreams.flatEntryMapperBuilder(keyGetter, entry -> entry.getValue().stream()).build());

但这很笨拙!现在想象一下,使用 chain 方法(这是我的目标用法)在映射中编写具有 2 个级别的所有类型参数会有多笨拙:

Map<String, Map<String, Set<String>>> level2Map;

我已经阅读了许多关于 lambda 和泛型类型推断的其他问题,但没有一个能回答我的特殊情况。

我错过了什么吗?我可以更正我的 API 以使其使用起来不那么笨拙,还是我总是坚持指定类型参数?谢谢!

最佳答案

我认为 Holger 在评论部分给出了最佳答案:

This is a known limitation of Java 8’s type inference: it doesn’t work with chained method invocations like genericFactoryMethod().build().

谢谢!关于我的 API,我将在将它们用作参数之前指定函数,如下所示:

Function<Entry<String, Set<String>>, String> keyMapper = Entry::getKey;
Function<Entry<String, Set<String>>, Stream<String>> valueMapper = entry -> entry.getValue().stream();

编辑:由于 Holger 的评论(再次感谢!),我重新设计了 API。它保留原始元素而不是键,以及扁平化的值。

public static <T, R> Function<? super T, Stream<FlatEntry<T, R>>> flatEntryMapper(Function<? super T, ? extends Stream<? extends R>> mapper)
{
return element -> mapper.apply(element).map(value -> new FlatEntry<>(element, value));
}

public static class FlatEntry<E, V>
{
/** The original stream element */
public final E element;

/** The flattened value */
public final V value;

private FlatEntry (E element, V value)
{
this.element = element;
this.value = value;
}
}

它是可链接的,从第 2 级开始,映射器必须处理一个 FlatEntry。用法类似于一个简单的flatMap:

Map<String, Map<String, Map<String, Set<String>>>> level3Map;

// gives a stream of all the flattened values
level3Map.entrySet()
.stream()
.flatMap(entry -> entry.getValue().entrySet().stream())
.flatMap(entry -> entry.getValue().entrySet().stream())
.flatMap(entry -> entry.getValue().stream());

// gives a stream of FlatEntries with flattened values and all their original elements in nested FlatEntries
level3Map.entrySet()
.stream()
.flatMap(GdkStreams.flatEntryMapper(entry -> entry.getValue().entrySet().stream()))
.flatMap(GdkStreams.flatEntryMapper(flatEntry -> flatEntry.value.getValue().entrySet().stream()))
.flatMap(GdkStreams.flatEntryMapper(flatEntry -> flatEntry.value.getValue().stream()));

关于java - 无法在不指定类型参数的情况下将 Java 8 方法与 lambda 参数一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33016329/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com