javac confused by generics on class?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Jun 10 16:03:56 UTC 2025


(Adding compiler-dev and dropping core-libs-dev)

I think the compiler is correct here.

In the first example, you call List::stream() on a raw List (because "c" 
has the raw type Child, so "c.getValues()" returns a raw list). This 
gives you a raw stream (Stream), which means the Stream::collect is also 
erased, meaning it just returns Object. But since the method return type 
is String, you get an error as Object cannot be returned if a String 
type is expected.

In the second example you also first stash the result of "c.getValues()" 
(again, a raw list) into a variable of type List<String>. This is an 
unchecked operation -- as you are unsafely adding generic type 
parameters to raw type. The compiler lets you do it, with a warning. 
 From that point on, it's as if there's no raw types. You have a 
List<String>, so calling List::stream gives you a Stream<String>. Which 
means Stream::collect no longer has an erased type, and a String is 
returned from the collect call, as expected. So you get a warning for 
the unchecked operation above, but then no errors.

I hope this helps understanding what is going on.

Maurizio

On 10/06/2025 16:50, Jean-Noël Rouvignac wrote:
> Hello,
>
> When doing refactorings to take advantage of newer Java features, I 
> hit a new and weird edge case. I trimmed down the code several times, 
> and ended up with the following tiny reproducer, and I don't 
> understand what javac is complaining about even with javac 24:
>
> (Note: unlike the original code, this reproducer is very contrived, so 
> there's no need to make comments on how bad it is: I fully agree)
>
> ```java
> 1 import java.util.ArrayList;
> import java.util.List;
> import java.util.stream.Collectors;
>
> public class Main {
>     private static final class Child<T> {
>         public List<String> getValues() {
>             return new ArrayList<>();
>         }
>     }
>
>     @SuppressWarnings("unchecked")
>     private static String getString1(Child c) {
>         // Compilation error:
>         // Main.java:16: error: incompatible types: Object cannot be 
> converted to String
>         return c.getValues().stream().collect(Collectors.joining());
>     }
>
>     private static String getString2(Child c) {
>         // Compilation error:
>         // Main.java:27: warning: [unchecked] unchecked conversion
>         //        List<String> values = c.getValues();
>         //                                         ^
>         //  required: List<String>
>         //  found:    List
>         //1 warning
>         List<String> values = c.getValues();
>         return values.stream().collect(Collectors.joining());
>     }
> }
> ```
>
> It turns out IntelliJ is a bit more eloquent than javac, and when 
> hovering over the warning on `c.getValues()` at the line with 
> `List<String> values = c.getValues();`, it reports the following:
>
> >    Unchecked assignment: 'java.util.List' to 
> 'java.util.List<java.lang.String>'. Reason: 'c' has raw type, so 
> result of getValues is erased
>
> Is it possible that javac is doing early type erasure when analysing 
> this code, erasing a bit too much? Even if the code uses `Child` 
> without type argument, I would expect the return type of `getValues()` 
> to be well defined as `List<String>`?
>
> What do you think?
> I am sure there is some rational explanation that I missed for this 
> behaviour. I could not find a JBS issue showing the same case as here.
>
> Thank you,
> Jean-Noël Rouvignac
>
> /CONFIDENTIALITY NOTICE: This email may contain confidential and 
> privileged material for the sole use of the intended recipient(s). Any 
> review, use, distribution or disclosure by others is strictly 
> prohibited.  If you have received this communication in error, please 
> notify the sender immediately by e-mail and delete the message and any 
> file attachments from your computer. Thank you./ 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20250610/28fc93c0/attachment.htm>


More information about the compiler-dev mailing list