1

I have method as below

   void meth(List<?> list) {
       List<Integer> integers = (List<Integer>)list; //how do I make sure am casting correctly to List < Integer >? what if list passed as List< String > , then this will throw some RunTime Exceptions, how to avoid this?
    }

In above snippet, for meth(), am not sure which type of Arraylist will be passed, it could be List or List etc, based on type of list type, I have to assign it to another list correctly, how can I achieve this?

John
  • 45
  • 4
  • You could try bounds-checking as described in https://stackoverflow.com/questions/12515861/how-to-check-if-a-generic-type-implements-a-specific-type-of-generic-interface-i – Love Credit Jul 02 '22 at 07:42
  • You cant, check https://docs.oracle.com/javase/tutorial/java/generics/erasure.html – Tano Jul 02 '22 at 08:04
  • This looks like a badly designed method. If `list` needs to be a `List`, then declare the method parameter as `List` instead of `List>`. Then you won't need to cast. – Jesper Jul 02 '22 at 10:00
  • @Jesper My method has to accept List , List etc, in this case, shall I use meth(List) or meth(List>) , may I know when to use wildcard parameters? – John Jul 02 '22 at 13:09
  • So, your method is really going to be different than what you presented in your question...? Because if you're going to cast it to `List` then it makes no sense that your method should also accept `List` etc. – Jesper Jul 03 '22 at 11:52
  • You should use an unbounded wildcard (`?`) only if the method doesn't care / need to know what the actual type of the elements of the `List` is. Otherwise, use a bounded wildcard (`? extends Something`) or a type parameter (`T`). – Jesper Jul 03 '22 at 11:53

2 Answers2

3

Basically ... you can't. Since you could call meth (as you have written it) with a List<String> parameter, there can always be runtime exceptions.

Solutions:

  • Declare meth as public void meth(List<Integer> list) so that you can't call it like this meth(someStringList). That avoids the unchecked type cast and eliminates the possibility of a class cast exception.

  • Use list like this in meth.

    void meth(List<?> list) {
        for (Object o: list) {
            Integer i = (Integer) o;
            // ...
        }
    }
    

    We can still get the class cast exception, but at least we get rid of the compiler error about unchecked type casts.

  • Use a @SuppressWarning annotation to suppress the compiler warning about the unchecked type cast. Once again, you could get the exceptions.


Unfortunately, given Java's generic type parameter erasure, there is no way that the body of meth (as written) can find out what kind of list it has been called with at runtime. And it won't work with a named type parameter either.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

I verified that it does not throw exception. With type erasure, all generics are convert to Object. Generics are for compiler to enforce type during compile time.

   static List<Integer> meth(List<?> list){
      return (List<Integer>) list;
   }
   
    public static void main(String[] args) {
        List<String> strings = new ArrayList<>();
        strings.add("world");
        strings.add("hello");
        List<Integer> integers = meth(strings);
        System.out.println(integers);
    }

Console:

[world, hello]

You can try the code here: https://onlinegdb.com/z7DmGAJUI

Cheng Thao
  • 1,467
  • 1
  • 3
  • 9