0

In the snippet below, [1] seems to yield the expected result whereas, [2] throws a ClassCastException as shown in the results below.

Why is a ClassCastException thrown when calling iterator() and not when using method reference?

 List<String> philosophers = Arrays.asList("Seneca", "Epictetus");
 // [1]
 for (String s : (Iterable<? extends String>) philosophers::iterator) {
     System.out.println(s);
 }

 // [2]
 for (String s: (Iterable<? extends String>) philosophers.iterator()) {
     System.out.println(s);
 }

[1] (Result when using method reference)

`Seneca`
`Epictetus`

[2] (Result when calling iterator())

Exception in thread "main" java.lang.ClassCastException: class java.util.Arrays$ArrayItr cannot be cast to class java.lang.Iterable` 
Michael
  • 41,989
  • 11
  • 82
  • 128
George
  • 457
  • 4
  • 14

1 Answers1

2

They are two different things.

philosophers::iterator is a function which when invoked, takes 0 arguments and returns an Iterator. As it happens, this is compatible with the definition of Iterable, since that interface has a single abstract method which does just that.

philosophers.iterator() does not return a function; it returns an Iterator. An Iterator is not an Iterable so the cast fails.


It is worth nothing that there's no good reason to do either of these. The first is basically only working by accident. That's a very unintuitive way to use a method reference. Just do

for (String s : philosophers)
Michael
  • 41,989
  • 11
  • 82
  • 128
  • Since Iterable has a single abstract method, why isn't it annotated with FunctionalInterface ? – George Jun 01 '21 at 12:02
  • 1
    @George Because `FunctionalInterface` is designed to specify *intent*. The intent of Iterable was not to be one, it just happens to qualify. See https://stackoverflow.com/questions/28166187/why-isnt-functionalinterface-used-on-all-the-interfaces-in-the-jdk-that-qualif – Michael Jun 01 '21 at 12:06