8

Consider the following code which uses the ability to intersect types, which was added in Java 8:

private <E, T extends List<E> & RandomAccess> void takeList(T list) {

}

private void fakingRandomAccess() {
    List<Integer> linkedList = new LinkedList<>();
    takeList((List<Integer> & RandomAccess)linkedList);
}

I have made a takeList method that only takes lists that have (near) constant access times, for whatever reason, but I can imagine that there would be situations where it is indeed warranted to do it such.

Passing an ArrayList<E> into the method should work just fine, however via type intersections you can also pass in a LinkedList<E> by pretending that it has constant access time.

Now my questions are:

  • Is there any way to store (List<Integer> & RandomAccess)linkedList in an object of a specified type?
  • Can I use type intersections to simplify the takeList method?
skiwi
  • 66,971
  • 31
  • 131
  • 216
  • 1
    How would you want `takeList` method to be simplified? Do you want to avoid that cast? Why do you want to pass an argument that doesn't satisfy the bounds? – Rohit Jain Apr 02 '14 at 18:27
  • @RohitJain I was thinking about `private void takeList(List & RandomAccess list)`, but that syntax (obviously?) doesn't work. – skiwi Apr 02 '14 at 18:29
  • 1
    Certainly that is not valid syntax of course. But even if it was allowed, I hardly see that as a simplification. – Rohit Jain Apr 02 '14 at 18:31
  • 2
    To be clear, `private & RandomAccess> void takeList(T list)` has worked ever since Java 6 at least. However, `takeList((List & RandomAccess)linkedList);` only works in Java 8. – Simon Forsberg Apr 02 '14 at 18:41
  • 2
    @SimonAndréForsberg Your statements are true regarding the syntax, but in Java 8 the latter fragment (which comes from skiwi's code) will compile but will fail at runtime with a `ClassCastException`. This is because the cast still does a runtime check, and `LinkedList` does not in fact implement `RandomAccess`. So there's no way to fake it this way. – Stuart Marks Apr 02 '14 at 22:11
  • @StuartMarks What is the difference versus this code then? http://stackoverflow.com/questions/22807912/how-to-serialize-a-lambda (The answer), it seems to use a similar mechanism. – skiwi Apr 03 '14 at 06:02
  • 2
    @skiwi The rules for an AIC are quite limited; see [JLS 15.9.1](http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.9.1). For `new T() { ... }` if T is a class, the AIC is a direct subclass of T, and if T is an interface, the AIC is a subclass of `Object` that implements T. That's it. For lambdas, the class of the resulting instance takes into account the target type, including iterfaces mentioned in intersection types. See [JLS 15.27.4](http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.4). So lambdas are treated quite differently than AICs in this respect. – Stuart Marks Apr 03 '14 at 06:55

1 Answers1

5

You are mixing two different things up.

In the How to serialize a lambda? question & answer there is a lambda expression being cast to an intersection type.

Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");

This tells the compiler to generate a type compatible to the intersection type. Therefore the generated class for the lambda expression will be both, Runnable and Serializable.


Here you are casting an instance of a concrete class to an intersection type:

(List<Integer> & RandomAccess)linkedList

This requests a runtime-check whether the concrete instance’s class implements an appropriate type, i.e. fulfills all interfaces. This runtime-check fails as LinkedList does not implement RandomAccess.

Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765
  • And `List linkedList = (List & RandomAccess)new LinkedList()` also makes no sense, I suppose? – skiwi Apr 03 '14 at 12:18
  • 2
    That’s right. And I think, an IDE should tell you that in a Warning. – Holger Apr 03 '14 at 12:25
  • Interestingly enough it does warn me if I use `new LinkedList()`, and gives an error if I use `new LinkedList<>()` in Netbeans 8.0. – skiwi Apr 03 '14 at 12:26
  • 1
    But does it behave differently for `ArrayList`? I guess, it’s more like type-casts do not work together with the “diamond operator”. – Holger Apr 03 '14 at 12:29