Is it possible to solve the “A generic array of T is created for a varargs parameter” compiler warning?

前端 未结 8 1549
Happy的楠姐
Happy的楠姐 2020-11-28 04:31

This is a simplified version of the code in question, one generic class uses another class with generic type parameters and needs to pass one of the generic types to a metho

相关标签:
8条回答
  • 2020-11-28 04:55

    Tom Hawtin pointed this out in a comment, but to be more explicit: yes, you can solve this at the declaration-site (rather than the (potentially many) call sites): switch to JDK7.

    As you can see in Joseph Darcy's blog post, the Project Coin exercise to select some small incremental language improvements for Java 7 accepted Bob Lee's proposal to allow something like @SuppressWarnings("varargs") at the method side to make this warning go away in situations where it was known to be safe.

    This has been implemented in OpenJDK with this commit.

    This may or may not be useful to your project (many people wouldn't be happy to switch to a pre-release unstable version of the JVM!) but perhaps it is — or perhaps someone who finds this question later (after JDK7 is out) will find it useful.

    0 讨论(0)
  • 2020-11-28 05:01

    Explicitly casting parameters to Object in vararg method invocation will make the compiler happy without resorting to @SuppressWarnings.

    public static <T> List<T> list( final T... items )
    {
        return Arrays.asList( items );
    }
    
    // This will produce a warning.
    list( "1", 2, new BigDecimal( "3.5" ) )
    
    // This will not produce a warning.
    list( (Object) "1", (Object) 2, (Object) new BigDecimal( "3.5" ) )
    
    // This will not produce a warning either. Casting just the first parameter to 
    // Object appears to be sufficient.
    list( (Object) "1", 2, new BigDecimal( "3.5" ) )
    

    I believe the issue here is that the compiler needs to figure out what concrete type of array to create. If the method is not generic, the compiler can use type information from the method. If the method is generic, it tries to figure out the array type based on parameters used at invocation. If the parameter types are homogenic, that task is easy. If they vary, the compiler tries to be too clever in my opinion and creates a union-type generic array. Then it feels compelled to warn you about it. A simpler solution would have been to create Object[] when type cannot be better narrowed down. The above solution forces just that.

    To understand this better, play around with invocations to the above list method compared to the following list2 method.

    public static List<Object> list2( final Object... items )
    {
        return Arrays.asList( items );
    }
    
    0 讨论(0)
  • 2020-11-28 05:06

    If you're after a fluent-type interface, you could try the builder pattern. Not as concise as varargs but it is type safe.

    A static generically-typed method can eliminate some of the boilerplate when using the builder, while retaining the type safety.

    The builder

    public class ArgBuilder<T> implements Iterable<T> {
    
        private final List<T> args = new ArrayList<T>();
    
        public ArgBuilder<T> and(T arg) {
            args.add(arg);
            return this;
        }
    
        @Override
        public Iterator<T> iterator() {
            return args.iterator();
        }
    
        public static <T> ArgBuilder<T> with(T firstArgument) {
            return new ArgBuilder<T>().and(firstArgument);
        }
    }
    

    Using it

    import static com.example.ArgBuilder.*;
    
    public class VarargsTest {
    
        public static void main(String[] args) {
            doSomething(new ArgBuilder<String>().and("foo").and("bar").and("baz"));
            // or
            doSomething(with("foo").and("bar").and("baz"));
        }
    
        static void doSomething(Iterable<String> args) {
            for (String arg : args) {
                System.out.println(arg);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 05:07

    It is a very easy problem to solve: Use List<T>!

    Arrays of reference type should be avoided.

    In the current version of Java (1.7), you can mark method with @SafeVargs which will remove the warning from the caller. Careful with that though, and you're still better off without legacy arrays.

    See also the Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters with Varargs Methods tech note.

    0 讨论(0)
  • 2020-11-28 05:09

    When workings with arrays of generic type, I am forced to pass a reference to the generic type. With that, I can actually do the generic code, using java.lang.reflect.Array.

    http://java.sun.com/javase/6/docs/api/java/lang/reflect/Array.html

    0 讨论(0)
  • 2020-11-28 05:10

    You can have overload the methods. This does not solve your problem but it minimizes the number of warnings (and yes, it's a hack!)

    class Assembler<X, Y> {
      void assemble(X container, Y a1) { ... }
      void assemble(X container, Y a1, Y a2) { ... }
      void assemble(X container, Y a1, Y a2, Y a3) { ... }
      void assemble(X container, Y a1, Y a2, Y a3, Y a4) { ... }
      void assemble(X container, Y... args) { ... }
    }
    
    0 讨论(0)
提交回复
热议问题