【问题标题】:Stream collect with Generic type使用通用类型进行流收集
【发布时间】:2016-10-27 14:22:57
【问题描述】:

我正在尝试在将 json 反序列化为 pojo 的方法中使用泛型,以便它可以返回任何对象类型。

这是我的代码:

private Bla(List<A> as, List<B> bs)
{
    this.as = as;
    this.bs = bs;
}

public static Bla from(JsonObject json)
{
    return new Bla(Bla.<A>load(json, As), Bla.<B>load(json, Bs));
}

private static <T> List<T> load(JsonObject jsonObject, String param)
{
    return jsonObject.getJsonArray(param).stream()
                                         .map(Bla::getItem)
                                         .collect(Collectors.toList());
}

private static <T> T getItem(Object json)
{
    try {
        return mapper.readValue(json.toString(), new TypeReference<T>() {
        });
    } catch (IOException e) {
        throw new RuntimeException("Error parsing json items", e);
    }
}

问题是.collect(Collectors.toList());似乎没有编译导致无法解析实例类型。

编译错误是:

错误:(43、25)java:不兼容的类型:推理变量 T 具有不兼容的边界 等式约束:T 下界:java.lang.Object

为了避免在我的示例中混淆 A 和 B 是 Pojos

问候。

【问题讨论】:

  • 这对于类型推断来说可能太多了,因为您需要将 Tcollect 传播回 map。试试map(x -&gt; Bla.&lt;T&gt;getItem(x))。另一种选择是在现有的map 之后添加第二个map(x -&gt; (T) x)
  • 并不是说这段代码无论如何都行不通。在你实例化的地方,new TypeReference&lt;T&gt;() {},没有人知道T 实际上是什么。甚至它的调用者load 也不知道AB
  • @Marko Topolnik:它会编译,因为T是可具体化的要求不能表达为TypeReference。它会在运行时失败。
  • @Marko Topolnik:不,从编译器的角度来看,它不需要是可具体化的类型,只要可以证明正确性即可,这对于实际上不使用的类来说很容易T。在运行时检查T 的尝试对此处的编译器不可见。那么它将是TypeVariable,Json 映射器希望在其中获得Class...
  • @Tunaki : Bla 不必是使此代码正确的泛型类型。如果Bla 是非泛型类型,那么从泛型类型系统的角度来看,代码是正确的。然而,由于类型擦除,在运行时根据需要创建 AB 实例的愿望将无法实现。

标签: java java-8


【解决方案1】:

让我们来看看这个方法:

private static <T> List<T> load(JsonObject jsonObject, String param)
{
    return jsonObject.getJsonArray(param).stream()
                                         .map(Bla::getItem)
                                         .collect(Collectors.toList());
}

上一步的类型,Collectors.toList()必须是List&lt;T&gt;,但是要得到上一步的类型,Bla::getItem必须推断为T getItem。由于getItem 是一个通用方法,这需要一个复杂的类型约束传播模式,这显然超出了Java 的类型推断所能处理的范围。为了解决这个问题,给编译器一个提示:

.map(Bla::<T>getItem)

(此句法变体归功于用户 Nándor Előd Fekete)。

第二个问题是你的getItem 方法:

private static <T> T getItem(Object json)
{
    return mapper.readValue(json.toString(), new TypeReference<T>() {};
}

在这里使用TypeReference 没有帮助,因为T 不是具体类型。它将在编译器在这里创建的匿名类中保持非具体化,因此杰克逊不会从中得到任何有用的提示。您可以只使用不采用TypeReference 的更简单的readValue 签名。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    相关资源
    最近更新 更多