Mik*_*kis 9 java generics intellij-idea variadic-functions
我在JDK 1.8上使用IntelliJ IDEA和javac.我有以下代码:
class Test<T extends Throwable>
{
@SafeVarargs
final void varargsMethod( Collection<T>... varargs )
{
arrayMethod( varargs );
}
void arrayMethod( Collection<T>[] args )
{
}
}
Run Code Online (Sandbox Code Playgroud)
IntelliJ IDEA不会将上述代码中的任何内容突出显示为警告.但是,在编译时,"消息"视图的"生成"选项卡中会显示以下行:
警告:(L,C)java:Varargs方法可能会导致不可恢复的varargs参数varargs造成堆污染
注意#1:我已经指定了@SafeVarargs.
注意#2:Warning:(L,C)指向varargs作为参数传递给arrayMethod()
假设我知道我在做什么,并且假设我非常确定不存在堆污染,或者我保证不会以某种可能导致堆污染的时髦方式调用此方法,我需要什么要压制此警告消息?
注意:有关varargs方法的stackoverflow存在大量问题,但似乎没有解决此特定问题的问题.事实上,整个interwebz对这个特定问题的答案似乎相当差.
0xb*_*7ed 10
我在这个问题上看到的答案似乎都不令人满意所以我认为我会抓住它.
这是我看到它的方式:
@SafeVarargs
[unchecked] Possible heap pollution from parameterized vararg type Foo.@SuppressWarnings("varargs")
[varargs] Varargs method could cause heap pollution from non-reifiable varargs parameter bar.因此,如果我对OP的原始代码采取以下简单的变化:
class Foo {
static <T> void bar(final T... barArgs) {
baz(barArgs);
}
static <T> void baz(final T[] bazArgs) { }
}
Run Code Online (Sandbox Code Playgroud)
$ javac -Xlint:all Foo.java使用Java 9.0.1编译器的输出是:
Foo.java:2: warning: [unchecked] Possible heap pollution from parameterized vararg type T
static <T> void bar(final T... barArgs) {
^
where T is a type-variable:
T extends Object declared in method <T>bar(T...)
1 warning
Run Code Online (Sandbox Code Playgroud)
我可以通过标记bar()来消除警告@SafeVarargs.这两者都会使警告消失,并且通过在方法合同中添加varargs安全性,确保调用的任何人bar都不必禁止任何varargs警告.
但是,它也使Java编译器更仔细地查看方法代码本身 - 我想是为了验证bar()可能违反我刚刚签订的合同的简单情况@SafeVarargs.而且它看到bar()所调用baz()传递barArgs和数据,因为baz()需要一个Object[]因类型擦除,baz()会搞乱了堆,从而导致bar()以传递地做到这一点.
所以我还需要添加@SuppressWarnings("varargs")以便bar()对bar()代码的警告消失.
事实上,您不应该以这种方式编写代码。考虑以下示例:
import java.util.*;
class Test<T extends Throwable>
{
@SafeVarargs
@SuppressWarnings("varargs")
final void varargsMethod( Collection<T>... varargs )
{
arrayMethod( varargs );
}
void arrayMethod( Collection<T>[] args )
{
Object[] array = args;
array[1] = new Integer(1);
//
//ArrayList<Integer> list = new ArrayList<>();
//list.add(new Integer(1));
//array[1] = list;
}
public static void main(String[] args)
{
ArrayList<Exception> list1 = new ArrayList<>();
ArrayList<Exception> list2 = new ArrayList<>();
(new Test<Exception>()).varargsMethod(list1, list2);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您运行代码,您将看到一个 ArrayStoreException,因为您将一个 Integer 放入Collection<T>数组中。
但是,如果替换 array[1] = new Integer(1); 用三个注释行(即把anArrayList<Integer>放入数组),由于类型擦除,不会抛出异常,也不会发生编译错误。
您想要一个Collection<Exception>数组,但现在它包含一个ArrayList<Integer>. 这是非常危险的,因为您不会意识到存在问题。