Catching ArrayStoreException at Compile-time

后端 未结 4 1641
悲哀的现实
悲哀的现实 2021-01-20 22:40

Consider the following test of Java\'s ArrayList#toArray method. Note that I borrowed the code from this helpful answer.

public class GenericTest {
         


        
相关标签:
4条回答
  • 2021-01-20 23:14

    The ArrayStoreException is runtime exception not compile time and thrown at run time and it indicates that different type of object is being stored in the array. Object x[] = new String[3]; x[0] = new Integer(0); The only way you can find it at compile time is by using <Integer> type as below

    foo.<Integer>toArray(new String[10]); 
    

    The above will throw compile time error as The parameterized method <Integer>toArray(Integer[]) of type List<Integer> is not applicable for the arguments (String[]).

    0 讨论(0)
  • 2021-01-20 23:23

    The method Collection.toArray cannot be changed for compatibility reasons.

    However for your own code you can create a (more) type-safe helper method which protects you from the ArrayStoreException if you use your method consequently:

    public static <T> T[] toArray(List<? extends T> list, T[] t) {
        return list.toArray(t);
    }
    

    This method will reject String[] s=toArray(new ArrayList<Integer>(), new String[0]); which matches the example case of your question, but beware of the array subtyping rule: it will not reject

    Object[] s=toArray(new ArrayList<Integer>(), new String[0]);
    

    because of the pre-Generics “String[] is a subclass of Object[]” rule. This can’t be solved with the existing Java language.

    0 讨论(0)
  • 2021-01-20 23:25

    ArrayStoreException exists precisely because Java's type system cannot handle this situation properly (IIRC, by the time Generics came along, it was too late to retrofit arrays in the same manner as the collections framework).

    So you can't prevent this problem in general at compile time.

    You can of course create internal APIs to wrap such operations, to reduce the likelihood of accidentally getting the types wrong.

    See also:

    • Dealing with an ArrayStoreException
    • Why are arrays covariant but generics are invariant?
    0 讨论(0)
  • 2021-01-20 23:25

    List#toArray(T[]) is a generic method declared as

    <T> T[] toArray(T[] a);
    

    So the type argument is either inferred from the type of the given array or with the <Type> notation prefixing the method invocation.

    So you could do

    String[] baz = foo.<Integer>toArray(new String[10]); // doesn't compile
    

    But I think that's the best you could do.

    But in that sense, you can clearly see that Integer doesn't match String (or vice-versa).

    Note that this is a documented exception

    ArrayStoreException - if the runtime type of the specified array is not a supertype of the runtime type of every element in this list

    So I don't think you should be trying to find it at compile time.

    0 讨论(0)
提交回复
热议问题