Scala中操作Java集合
两种情况需要在Scala中操作Java集合。一种是Scala调用了其他的Java库,针对Java集合需要转换为Scala集合,如此才能享受Scala集合提供的福利;另一种是编写了Scala程序,但需要提供给Java库,为了更好地无缝集成,要让Java库体会不到Scala的存在。
Scala调用Java库
我在编写spark批量导入mongodb的程序中,用到伪代码:
val client : MongoClient = new MongoClient("192.168.1.150")
val findIterable:FindIterable[Document] = client.getDatabase("test").getCollection("test").find( new BasicDBObject("id","791279468"))
for( doc:Document <- findIterable ){
}
这时编译会报miss parameter type for expanded function, the argument types of an anonymous function must be fully known(SLS 8.5)
经过查阅资料,才知道导入该包:需要进行隐式转换
import scala.collection.JavaConversions._
Scala的代码以Java库的形式提供给Java调用者
在JVM平台下进行多语言开发时,多数情况下会以Java为主,而对于一些特定场景,能够更好发挥Scala特性的,例如并发处理等,则会选择Scala。此时,若要做到对Java友好,则对于Scala的方法返回值,应尽量屏蔽Scala的类型信息。
Java中操作Scala集合
Java要调用Scala代码,而不幸的,这个需要调用的Scala代码不够体贴,直接返回了Scala的集合类型。由于Java不提供自定义隐式转换的功能,因此,只能调用Scala提供的转换类进行显式转换。例如Scala中的XmlConfigure类,其readSoftInfos()返回的是Scala的Seq:
import scala.collection.JavaConversions;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
public class XmlConfigureJavaTest {
@Test
public void should_load_xml_file() {
XmlConfigure xmlConfigure = new XmlConfigure();
List softInfos = JavaConversions.asJavaList(xmlConfigure.readSoftInfos(“/config.xml”, “version number”));
assertThat(softInfos.size(), is(7));
}
}
在readSoftInfos()函数返回的为Scala集合类型的情况下,若不进行显示转换,则无法通过编译。
Scala的隐式转换
Scala对Java集合与Scala集合之间的互相转换都用到了Scala提供的隐式转换功能。我们导入的JavaConversions就是承担这种转换的一个Facade Object。它扩展了两个trait:WrapAsScala和WrapAsJava。在JavaConversions对象中定义的方法实际上是将请求委派自它继承的trait的隐式转换函数。例如将Seq转换为java的List:
object JavaConversions extends WrapAsScala with WrapAsJava {
def asJavaList[A](b : Seq[A]): ju.List[A] = seqAsJavaListA
}
seqAsJavaList就是定义在WrapAsJava中的隐式转换函数。在这个函数中又作了一个模式匹配。如果匹配JListWrapper,则调用传入的wrapped参数的asInstanseOf进行类型转换;否则,就将该seq作为参数传递给包装器SeqWrapper。包装器SeqWrapper是Scala定义的样例类(case class),扩展自Java的AbstractList