Weird Java 8 issue with Lists.newArrayList

2,686 views
Skip to first unread message

ryan.b...@gmail.com

unread,
Jan 21, 2015, 5:39:31 PM1/21/15
to guava-...@googlegroups.com
Hi while upgrading an app to Java 8 I ran into a weird issue with newArrayList in a couple of places which is concerning me.

Take a look at this example:

import com.google.common.collect.UnmodifiableIterator;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import java.util.ArrayList;

import static com.google.common.collect.Iterators.forEnumeration;
import static com.google.common.collect.Lists.newArrayList;

public class NewArrayListIssue {
    public static void main(String[] args) throws NamingException {

        UnmodifiableIterator<?> elements = forEnumeration(getEnumeration().getAll());
        System.out.println("declarefirst = " + newArrayList(elements)); // calls newArrayList(Iterator<? extends E> elements)

        ArrayList directCopy = newArrayList(forEnumeration(getEnumeration().getAll()));
        System.out.println("useDirectly = " + directCopy); //calls newArrayList(E... elements)
    }

    public static Attribute getEnumeration(){
        return new BasicAttribute("foo",1);
    }
}


In the first example when I get the UnmodifiableIterator first into it's own variable and then call newArrayList I get what I expect, which is the Iterators values copied into a new list

In the second example where the forEnumeration goes directly into the newArrayList method I get back a instance of com.google.common.collect.Iterators containing a list with the value.

According to Intellij it *thinks* that both method calls should be to newArrayList(Iterator<? extends E> elements) but I found when debugging that the second call actually goes to newArrayList(E... elements) 

Is this a known issue? A issue with the Java compiler?

It only happens when I compile with the Oracle JDK8 targeted to Java8. If I target to 7 it works fine.

Thanks

Tim Peierls

unread,
Jan 21, 2015, 8:16:12 PM1/21/15
to ryan.b...@gmail.com, guava-discuss
Did you mean to have raw ArrayList?

If so: All bets are off when you use raw types. I get a compiler warning about unchecked array creation.

If not, what did you mean?

--tim

--
guava-...@googlegroups.com
Project site: https://github.com/google/guava
This group: http://groups.google.com/group/guava-discuss
 
This list is for general discussion.
To report an issue: https://github.com/google/guava/issues/new
To get help: http://stackoverflow.com/questions/ask?tags=guava
---
You received this message because you are subscribed to the Google Groups "guava-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to guava-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/guava-discuss/c577bfa1-fd9a-43f4-8a79-97f407ef7baf%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Joachim Durchholz

unread,
Jan 21, 2015, 8:57:31 PM1/21/15
to guava-...@googlegroups.com
Am 22.01.2015 um 02:16 schrieb Tim Peierls:
> Did you mean to have raw ArrayList?
>
> If so: All bets are off when you use raw types. I get a compiler warning
> about unchecked array creation.

It's not really "all bets are off", in fact the rule about that kind of
situation are quite explicit.

The situation is that the compiler cannot check that this combination is
always typesafe, and manual checking is awkward and beyond the abilities
of most Java programmers.
Sections with full gory details start at
http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ300
.

Joachim Durchholz

unread,
Jan 21, 2015, 9:01:16 PM1/21/15
to guava-...@googlegroups.com
> According to Intellij it *thinks* that both method calls should be to
> newArrayList(Iterator<? extends E> elements) but I found when
> debugging that the second call actually goes to
> newArrayList(E... elements)

That's ambiguous if E extends Iterator.
There's a disambiguation rule for that kind of situation in the language
specification, but I'm too lazy to look it up.

You can force the expected interpretation by writing
<Iterator <? extends E>>newArrayList(elements)

Anyway, this ambiguity is why I started removing all varargs from my
APIs, it's just too much hassle (and if people really want a list they
can still use Arrays.asList(), which is not overloaded).

> Is this a known issue? A issue with the Java compiler?
>
> It only happens when I compile with the Oracle JDK8 targeted to
> Java8. If I target to 7 it works fine.

I wouldn't expect a compiler error with that one, it's the same compiler
after all; this sounds like an intentional change.
Though that's weird. Did they change the ambiguity resolution between 7
an 8?
Or maybe my analysis is totally off the mark.

Tim Peierls

unread,
Jan 21, 2015, 9:04:58 PM1/21/15
to Joachim Durchholz, guava-discuss
On Wed, Jan 21, 2015 at 8:57 PM, Joachim Durchholz <j...@durchholz.org> wrote:
Am 22.01.2015 um 02:16 schrieb Tim Peierls:
Did you mean to have raw ArrayList?

If so: All bets are off when you use raw types. I get a compiler warning
about unchecked array creation.

It's not really "all bets are off", in fact the rule about that kind of situation are quite explicit.

The situation is that the compiler cannot check that this combination is always typesafe, and manual checking is awkward and beyond the abilities of most Java programmers.

Including newbies like me. :-) Bottom line: avoid raw types.

--tim

ryan.b...@gmail.com

unread,
Jan 21, 2015, 10:10:02 PM1/21/15
to guava-...@googlegroups.com


On Wednesday, January 21, 2015 at 8:01:16 PM UTC-6, Toolforger wrote:

I wouldn't expect a compiler error with that one, it's the same compiler
after all; this sounds like an intentional change.
Though that's weird. Did they change the ambiguity resolution between 7
an 8?
Or maybe my analysis is totally off the mark.

No, I think you're right, or at least close. There are some other interesting ways to force Java to use the right method. Getting a typed enumeration from the Attribute does the trick (even if it's just of Object) Also, If I were to make the getEnumeration return the UnmodifiableIterator (raw or typed) then it also starts working as expected.

In any case, I've run into quite a few other issues with varargs in this adventure, particularly with mockito (but at least that's just tests). I agree that I'm close to trying to rid my life of them.
Reply all
Reply to author
Forward
0 new messages