Java未经检查的警告问题,不理解如何修复。

huangapple go评论121阅读模式
英文:

Java unchecked warning issues with understanding how to fix

问题

以下是您要翻译的内容:

我在理解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();
}

现在我创建了这些接口的实现,并出现了一个“unchecked”警告,我正在尝试理解其中的原因。

实现如下

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>'

secondFunction 则没有问题。

为什么会发生这种情况?显然我漏掉了某些东西,我没有注意到以修复它!

注意:JsonProcessingException 继承自 IOException(声明:public class JsonProcessingException extends IOException)。

英文:

I am having hard time to understand the difference between two declarations on java generics.

lets say I have the following two interfaces

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

    &lt;E extends Throwable&gt; CheckedFunction&lt;Object, String, E&gt; firstFunction();

    CheckedFunction&lt;String, DTO, E2&gt; secondFunction();
}

So now I created an implementation of those and an "unchecked" warning popped which is what I am trying to understand.

The implementation is the following

public class TmpImpl implements SomeInterface&lt;TmpObj, IOException&gt; {

    final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public CheckedFunction&lt;Object, String, JsonProcessingException&gt; firstFunction() {
        return objectMapper::writeValueAsString;
    }

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

    public static class TmpObj {
        String s;
    }
}

for this example I am using com.fasterxml.jackson.databind.ObjectMapper as it does exactly what I want and generates the warning.

So the firstFunction now has a warning

Unchecked overriding: return type requires unchecked conversion. Found &#39;CheckedFunction&lt;java.lang.Object,java.lang.String,com.fasterxml.jackson.core.JsonProcessingException&gt;&#39;, required &#39;CheckedFunction&lt;java.lang.Object,java.lang.String,E&gt;

while the second is just fine.

Why is this happening ? I am clearly missing something which I haven't noticed in order to fix it!

note JsonProcessingException extends IOException (declaration: public class JsonProcessingException extends IOException )

答案1

得分: 2

你的实现强制使用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;
}

然而,上面的代码会因未处理的JsonProcessingException而失败,我怀疑这导致了你的实现问题。

这只是意味着你对泛型的Throwable参数的使用是错误的。

解决这个问题的第一个尝试是使用SomeInterfaceE2变量:

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,以及其他类型)。

英文:

The short answer is that your implementation is dictating JsonProcessingException whereas the interface allows for E to be inferred.

In other words, according to the interface, this should be possible:

SomeInterface&lt;String, RuntimeException&gt; runtimeExceptionSomeInterface = null;
CheckedFunction&lt;Object, String, RuntimeException&gt; function = 
                     runtimeExceptionSomeInterface.firstFunction();

This declaration:

&lt;E extends Throwable&gt; CheckedFunction&lt;Object, String, E&gt; firstFunction();

allows the caller to specify the concrete argument for E, which is exactly what I did in the above example (using RuntimeException).

However, your implementation is statically forcing JsonProcessingException:

public CheckedFunction&lt;Object, String, JsonProcessingException&gt; firstFunction() {
	return objectMapper::writeValueAsString;
}

That is to say you've disregarded the incoming E type argument and forcefully substituting it with JsonProcessingException.


In short, if you want the firstFunction() to be generic, then implement it accordingly:

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

However, the above fails return objectMapper::writeValueAsString; with an unhandled JsonProcessingException, which I suspect led to your implementation.

That simply means that your use of a generic Throwable parameter is wrong.

A first attempt at solving it would be to use SomeInterface's E2 variable:

interface SomeInterface&lt;DTO, E2 extends Throwable&gt; {
	CheckedFunction&lt;Object, String, E2&gt; firstFunction();
	CheckedFunction&lt;String, DTO, E2&gt; secondFunction();
}

which will solve the problem if implemented with:

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

However, you would still have a problem because it's not the user of SomeInterface that knows what exception will be thrown, but the implementation. This means that you should declare the exception type on the API, rather than making it a generic argument:

interface SomeInterface&lt;DTO&gt; {
	CheckedFunction&lt;Object, String, IOException&gt; firstFunction();
    //...
}

class TmpImpl implements SomeInterface&lt;TmpObj&gt; {

	//...

	@Override
	public CheckedFunction&lt;Object, String, IOException&gt; firstFunction() {
		return objectMapper::writeValueAsString;
	}
}

Which is to say that SomeInterface and its implementations know the range of exceptions to be dealt with, therefore the functions they return know of, in this case, IOException (which is selected because you know it includes JsonProcessingException, among other types)

huangapple
  • 本文由 发表于 2020年8月31日 17:03:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/63667847.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定