7
Set<Object> removedObjs = new HashSet<>();
List<? extends MyEntity> delObjs = (List<? extends MyEntity>) new ArrayList<>(removedObjs);

MyEntity is marker interface.

Above code is working fine in (java version "1.7.0_91", to be precise) but not in (java version "1.8.0_77")

In Java8, I am getting the following exception:

incompatible types: ArrayList<Object> cannot be converted to List< ? extends MyEntity>

Abigail Fox
  • 1,623
  • 3
  • 16
  • 22
  • 4
    If you remove the `<>` you should get just a warning. If it doesn't work in Java 8, then it probably shouldn't have worked in Java 7. – Peter Lawrey May 16 '16 at 08:18
  • It can be compiler in my environment JAVA1.8.0_92 in eclipse with only warning:Type safety: Unchecked cast from ArrayList to List extends MyEntity> but cannot javac – andy May 16 '16 at 08:48
  • 3
    Looking at the code, it seems logical that it shouldn't work. just insert a `removedObjs.add("42");` between the two lines to see why. – biziclop May 16 '16 at 10:50
  • 1
    Any chance of improving the title to make it more useful to people searching for this issue in future? – Tom Fenech May 16 '16 at 15:21

2 Answers2

11

Your code should neither work in Java 7 nor in Java 8, because you are trying to cast an ArrayList<Object> (type returned from the constructor) to a List<? extends MyEntity> and it has no sense even at compile time (see this question). That's why the compiler is complaining.

The following code will compile:

Set<Object> removedObjs = new HashSet<>();
List<? extends Integer> delObjs = (List) new ArrayList<>(removedObjs);

However, the compiler will throw a warning since you are performing an unsafe conversion.

EDIT: As @Tom points out:

"Your code should not work in java 7" It shouldn't, but it worked, because the compiler checks were still a bit faulty in that version. This has been fixed in Java 8, that is why it now fails.

Community
  • 1
  • 1
zequihg50
  • 349
  • 2
  • 13
  • 14
    *"Your code should not work in java 7"* It shouldn't, but it worked, because the compiler checks were still a bit faulty in that version. This has been fixed in Java 8, that is why it now fails. (just a note) – Tom May 16 '16 at 11:19
  • ^ this should be added to the answer. – Lightness Races in Orbit May 16 '16 at 14:13
  • @Tom: I don’t have a `jdk1.7.0_91` at hand, but I tested with `jdk1.7.0_13`, `jdk1.7.0_40`, `jdk1.7.0_51`, `jdk1.7.0_80`, and Eclipse (with Java7 conformity). None of them accepted the code of the question. – Holger May 17 '16 at 12:16
  • The Java Language Specification discourages the use of raw types except for working with legacy code predating generics. See also http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it – meriton May 22 '16 at 18:07
8

Java 8 changed a lot about type inference and related subjects. As such, it's not surprising if some edge cases (such as shady casts) suddenly become invalid.

Whatever the reason is, you can still cast your list, but it's slightly more ugly than before:

(List<? extends MyEntity>) (List) new ArrayList<>(removedObjs);

As pointed out by Peter Lawrey's comment, this can be written even shorter as

(List) new ArrayList<>(removedObjs);

BambooleanLogic
  • 7,530
  • 3
  • 30
  • 56
  • The Java Language Specification discourages the use of raw types except for working with legacy code predating generics. See also http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it – meriton May 22 '16 at 18:04