Java Lambda 迭代 JPA 的 List

5
我发现在使用JPA时,lambda表达式存在一些奇怪的行为,似乎Java 8的lambda在从另一个对象获取列表时不进行迭代。
例如:
    List<MyObject> list = anotherObject.getMyObjectList(); // Get The List

    list.foreach(myobject -> System.out.println("NOT PRINTED"));

    System.out.println("Size?: " + list.size()); // Print The Size = 2

我尝试使用list.stream().foreach()得到了相同的结果...
经过数小时的测试,我发现了一个窍门。
    List<MyObject> copyList = new ArrayList<>(list); // copy The List 
    copyList.foreach(myobject -> System.out.println("OMG IS PRINTED!"));

哦?有什么想法吗?这是一个错误吗?还是我做错了什么?
我的实体类工作得很好,所有的关系都很好... :)
提前感谢。

2
似乎 List 代理未能像应该的那样拦截 forEach 调用。 - Sotirios Delimanolis
在能正常工作的示例中,我们知道该列表是一个“ArrayList”。在不能正常工作的示例中,我们没有足够的信息来知道它是哪种类型的对象。它是List的自定义实现吗?如果是这样,那么错误很可能在于该自定义实现中。 - Enwired
是的,anotherObject.getMyObjectList(); 返回一个 List<MyObject>,它是同一个对象,不是列表的自定义实现,而是 java.util.List。 :P - DarkZaioN
java.util.List 是一个接口,而不是一个类。getMyObjectList() 返回的具体列表类型是什么? - azurefrog
这是一个惰性集合吗?你可以尝试在 list.foreach(...) 之前调用 list.size(),看看会发生什么吗?只是为了初始化集合。 - gadget
1
@DarkZaioN 执行 System.out.println(list.getClass()) 命令,以查找由 anotherObject.getMyObjectList() 返回的 List 具体类。 - Stuart Marks
2个回答

3

了解anotherObject.getMyObjectList()返回的List具体类别会很有帮助,因为它的迭代器可能有bug。

当你使用new ArrayList<>(list)将其复制到ArrayList中时,该构造函数的代码会使用toArray从源列表中复制元素,然后将其复制到ArrayList内部包含的新数组中。

当你调用list.forEach时,除非被具体类重写,否则会调用Iterable的默认方法forEach,其实现方法如下:

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

这只是一个标准的增强型for循环,没有什么神奇的。但是这个for循环是通过列表的迭代器实现的。尝试编写一个for循环来代替调用list.forEach(lambda),或者尝试调用list.iterator()并查看可以获取多少个元素。如果toArray可以工作,但迭代技术不行,那么似乎是JPA列表类迭代器实现中的一个bug。

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接