这编译很好,但在运行时会爆炸:
线程“main”中的异常java.lang.NoSuchMethodError:scala.collection.immutable.List.filter(Lscala / Function1;)Lscala / collection / immutable / List
import scala.Function1;
import scala.collection.immutable.List;
import scala.collection.immutable.Nil$;
import scala.runtime.AbstractFunction1;
public class FunProc {
List nil = Nil$.MODULE$; // the empty list
List<Integer> list1 = nil.$colon$colon(1); // append 1 to the empty list
List<Integer> list2 = list1.$colon$colon(2); // append 2 to List(1)
List<Integer> list3 = list2.$colon$colon(3).$colon$colon(14).$colon$colon(8); // List(8, 14, 3, 2, 1)
Function1<Integer, Object> filterFn = new AbstractFunction1<Integer, Object>() {
public Boolean apply(Integer value) { return value<10; }
};
List<Integer> list4 = list3.filter(filterFn); // List(8, 3, 2, 1)
public void doIt() {
System.out.println("Filtered List is " + list4);
}
}
在尝试了idonnie的回答之后,我想出了这个:
List<Integer> list4 = list3.toTraversable().filter(filterFn).toList();
这与idonnie的答案基本相同,只是使用转换而不是强制转换。我仍然想知道为什么toTraversable()是必要的,因为以下编译很好:
List<Integer> list4 = list3.filter(filterFn);
答案 0 :(得分:5)
对我来说,
$ javac -cp O\:/scala-2.10.0-RC2/lib/scala-library.jar jfilter/FunProc.java
jfilter\FunProc.java:19: error: incompatible types
List<Integer> list4 = list3.filter(filterFn); // List(1, 2, 3, 8)
^
required: List<Integer>
found: Traversable<Integer>
Note: jfilter\FunProc.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
idonnie的Traversable还可以。
FWIW,scaladoc为那些厌恶IDE的人展示了“定义类”。
这可能是inconsistent java generics signature的症状,discussion和analysis interminable。
但scalac -Ycheck:jvm TraversableLike.scala
并没有抱怨过滤器。 (我对ML线程的评论是“编译器在发出警告后退出addGenericSignature”。我的修复方法是在Scala中添加一个强制转换来支持互操作。)
答案 1 :(得分:2)
通过javap
,终于找到了scala.collection.TraversableLike中的过滤方法
修改
编译并运行:
List<Integer> list4 = (List<Integer>)
(((scala.collection.TraversableLike) list3).filter(filterFn));
答案 2 :(得分:2)
我们可以使用FunctionN
及其AbstractFunctionN
子类在Java上的Scala列表中执行filter()
等操作。以下是创建Scala列表并对其进行过滤的方法。
// List(8, 3, 2, 1)
List<Integer> list4a = list3.toTraversable().filter(filterFn).toList();
此技术可以访问TraversableLike
特征提供的方法,以便在列表上调用toTraversable()
,从而返回Traversable<Integer>
个实例。然后可以调用filter()
,返回另一个Traversable<Integer>
实例。 Traversable
有一个名为toList()
的方法,然后将Traversable<Integer>
实例转换回List<Integer>
。
我不明白som-snytt引用的Scala编译器错误如何通过以下方式得到缓解:
// this produces the same result: List(8, 3, 2, 1)
List<Integer> list4b =
(List<Integer>) ((scala.collection.TraversableLike) list3).filter(filterFn));
filterFn()
是Function1
子类AbstractFunction1
的一个实例。此实例的定义为Java Function1<Integer, Object>
,这意味着它接受Integer
并返回Object
。在Scala中编写的apply()
方法定义实际上返回scala.Boolean
,但Java确实not know about
scala.Boolean . Instead, we define
apply()to return a
java.lang .Boolean和返回值的类型参数声明为java.Object
。 我想了解这项工作的正确性。
答案 3 :(得分:1)
这听起来很可疑。
首先,我要说明使用特征不应该与它有任何关系。当您使用traits时,Scala会为实现这些traits的静态方法创建转发器,因此调用由trait或class定义的方法应该没有任何区别。
其次,我认为filter
给出的javap
定义没有问题:
public scala.collection.immutable.List<A> filter(scala.Function1<A, java.lang.Object>);
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokestatic #1103 // Method scala/collection/TraversableLike$class.filter:(Lscala/collection/TraversableLike;Lscala/Function1;)Ljava/lang/Object;
5: areturn
LineNumberTable:
line 76: 0
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lscala/collection/immutable/List;
0 6 1 p Lscala/Function1;
Signature: #1104 // (Lscala/Function1<TA;Ljava/lang/Object;>;)Lscala/collection/immutable/List<TA;>;
所以方法就在那里,类型签名似乎正确。我会把这个问题带到scala邮件列表,虽然我愿意打赌已经有一些问题已经打开了。