2

这编译得很好,但在运行时会爆炸:

线程“主”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);
4

4 回答 4

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 的人显示“定义类”。

这可能是java 泛型签名不一致的症状,讨论分析没完没了

scalac -Ycheck:jvm TraversableLike.scala不抱怨过滤器。(我对该 ML 线程的评论是“编译器在发出警告后退出 addGenericSignature”。我的解决方法是在 Scala 中添加一个强制转换以支持互操作。)

于 2012-12-13T01:47:22.100 回答
2

我们可以使用FunctionN它们及其AbstractFunctionN子类来执行操作,例如filter()对 Java 中的 Scala 列表进行操作。这是创建 Scala 列表并对其进行过滤的方法。

// List(8, 3, 2, 1)
List<Integer> list4a = list3.toTraversable().filter(filterFn).toList(); 

这种技术可以访问 trait 提供的方法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()方法定义实际上返回 a scala.Boolean,但 Java 执行not know aboutscala.Boolean . Instead, we defineapply() to return ajava.lang.Boolean 并且返回值的类型参数声明为java.Object我想了解这是如何更正确地工作的。

于 2012-12-13T22:01:43.617 回答
2

通过javap,终于在scala.collection.TraversableLike中找到了一个过滤方法

编辑

编译并运行:

    List<Integer> list4 = (List<Integer>)
(((scala.collection.TraversableLike) list3).filter(filterFn));
于 2012-12-13T00:31:04.577 回答
1

这一切对我来说听起来可能很可疑。

首先,让我声明,特征的使用不应该与它有任何关系。当您使用 trait 时,Scala 会为实现这些 trait 的静态方法创建转发器,因此调用由 trait 或类定义的方法根本不会有任何区别。

其次,我认为filteras 给出的定义没有问题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 邮件列表中,尽管我愿意打赌已经有一些问题已经解决了。

于 2012-12-18T11:45:30.727 回答