首页 > 解决方案 > 了解如何修复的 Java 未经检查的警告问题

问题描述

我很难理解关于 java 泛型的两个声明之间的区别。

假设我有以下两个接口

@FunctionalInterface
public interface CheckedFunction<T, R, E extends Throwable> {
   R apply(T t) throws E;
}
public interface SomeInterface<DTO, E2 extends Throwable> {

    <E extends Throwable> CheckedFunction<Object, String, E> firstFunction();

    CheckedFunction<String, DTO, E2> secondFunction();
}

所以现在我创建了一个实现,并弹出了一个“未经检查”的警告,这是我想要理解的。

实现如下

public class TmpImpl implements SomeInterface<TmpObj, IOException> {

    final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public CheckedFunction<Object, String, JsonProcessingException> firstFunction() {
        return objectMapper::writeValueAsString;
    }

    @Override
    public CheckedFunction<String, TmpObj, IOException> secondFunction() {
        return json -> objectMapper.readValue(json, TmpObj.class);
    }

    public static class TmpObj {
        String s;
    }
}

对于这个例子,我正在使用com.fasterxml.jackson.databind.ObjectMapper它,因为它完全符合我的要求并生成警告。

所以 firstFunction 现在有一个警告

Unchecked overriding: return type requires unchecked conversion. Found 'CheckedFunction<java.lang.Object,java.lang.String,com.fasterxml.jackson.core.JsonProcessingException>', required 'CheckedFunction<java.lang.Object,java.lang.String,E>

而第二个很好。

为什么会这样?为了修复它,我显然遗漏了一些我没有注意到的东西!

注意JsonProcessingException扩展IOException(声明public class JsonProcessingException extends IOException:)

标签: javagenericsexceptionlambda

解决方案


简短的回答是您的实现是口授JsonProcessingException,而接口允许E推断。

换句话说,根据界面,这应该是可能的:

SomeInterface<String, RuntimeException> runtimeExceptionSomeInterface = null;
CheckedFunction<Object, String, RuntimeException> function = 
                     runtimeExceptionSomeInterface.firstFunction();

本声明:

<E extends Throwable> CheckedFunction<Object, String, E> firstFunction();

允许调用者为 指定具体参数E,这正是我在上面的示例中所做的(使用RuntimeException)。

但是,您的实现是静态强制的JsonProcessingException

public CheckedFunction<Object, String, JsonProcessingException> firstFunction() {
    return objectMapper::writeValueAsString;
}

也就是说,您忽略了传入的E类型参数并用JsonProcessingException.


简而言之,如果您希望firstFunction()是通用的,则相应地实现它:

@Override
public <E extends Throwable> CheckedFunction<Object, String, E> firstFunction() {
    return objectMapper::writeValueAsString;
}

但是,上述失败return objectMapper::writeValueAsString;并出现 unhandled JsonProcessingException,我怀疑这导致了您的实施。

这仅仅意味着您使用泛型Throwable参数是错误的。

解决它的第一次尝试是使用SomeInterface'E2变量:

interface SomeInterface<DTO, E2 extends Throwable> {
    CheckedFunction<Object, String, E2> firstFunction();
    CheckedFunction<String, DTO, E2> secondFunction();
}

如果使用以下方法实现,这将解决问题:

class TmpImpl implements SomeInterface<TmpObj, IOException> {
    //...
    @Override
    public CheckedFunction<Object, String, IOException> firstFunction() {
        return objectMapper::writeValueAsString;
    }

但是,您仍然会遇到问题,因为SomeInterface知道将引发什么异常的不是用户,而是实现。这意味着您应该在 API 上声明异常类型,而不是使其成为通用参数:

interface SomeInterface<DTO> {
    CheckedFunction<Object, String, IOException> firstFunction();
    //...
}

class TmpImpl implements SomeInterface<TmpObj> {

    //...

    @Override
    public CheckedFunction<Object, String, IOException> firstFunction() {
        return objectMapper::writeValueAsString;
    }
}

也就是说,SomeInterface它的实现知道要处理的异常范围,因此它们返回的函数知道,在这种情况下,IOException(选择它是因为你知道它包括JsonProcessingException,以及其他类型)


推荐阅读