欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

scala学习笔记 - scala与java集合的互操作

程序员文章站 2022-06-14 20:30:23
...

JavaConversions对象提供了用于在Scala和Java集合之间来回转换的一组方法。
给目标值显式地指定一个类型来触发转换 例如:

import scala col lec ti JavaConversions._
val props: scala.collection.mutable.Map[String, String] = System .getProperties()

如果你担心那些不需要的隐式转换也被引人的话,只引入需要的即可 例如:

import scala.collection.JavaConversions.propertiesAsScalaMap

注意这些转换产出的是包装器,让你可以使用目标接口来访问原本的值。举例来说,如果你用

val props: scala.collection.mutable.Map[String, String] = System.getProperties()

那么props就是一个包装器,其方法将调用底层的Java对象。如果你调用

props ("com.horstmann.scala")= "impatient"

那么包装器将调用底层Properties对象的put("com.horstmann.scala", "impatient")
从Scala集合到Java集合的转换:

隐式函数 从scala.collection的类型 到java.util的类型
asJavaCollection Iterable Collection
asJavaIterable Iterable Iterable
asJavaIterator Iterator Iterator
asJavaEnumeration Iterator Enumeration
seqAsJavaList Seq List
mutableSeqAsJavaList mutable.Seq List
bufferAsJavaList mutable.Buffer List
setAsJavaSet Set Set
mutableSetAsJavaSet mutable.Set Set
mapAsJavaMap Map Map
mutableMapAsJavaMap mutable.Map Map
asJavaDictionary Map Dictionary
asJavaConcurrentMap mutable.ConcurrentMap concurrent.ConcurrentMap

从Java集合到Scala集合的转换:

隐式函数 从java.util的类型 到scala.collection的类型
collectionAsScalaIterable Collection Iterable
iterableAsScalaIterable Iterable Iterable
asScalaIterator Iterator Iterator
enumerationAsScalaIterator Enumeration Iterator
asScalaBuffer List mutable.Buffer
asScalaSet Set mutable.Set
mapAsScalaMap Map mutable.Map
dictionaryAsScalaMap Dictionary mutable.Map
propertiesAsScalaMap Properties mutable.Map
asScalaConcurrentMap concurrent.ConcurrentMap mutable.ConcurrentMap

并行集合

Scala提供的用于操纵大型集合的解决方案十分诱人。这些任务通常可以很自然地并行操作。举例来说,要计算所有元素之和,多个线程可以并发地计算不同分区的和;最后这些部分的结果被汇总到一起。要对这样的并发任务进行排程是很伤脑筋的,但若用Scala ,则你无须担心这个问题。如果coll是个大型集合,那么

val coll = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
println(coll.par.sum)

上述代码会并发地对它求和。par方法产出当前集合的一个并行实现。该实现会尽可能并行地执行集合方法。例如:

coll.par.count(_ % 2 == 0)

将会并行地对偶集合求前提表达式的值,然后将结果组合在一起,得出coll中所有偶数的数量。
你可以通过对要遍历的集合应用.par并行化for循环,就像这样:

for (i <- ((0 until 10)).par) {
      print(s"$i ")
    }
// 输出: 7 9 3 2 1 8 5 4 0 6

数字是按照作用于该任务的线程产出的顺序输出的。而在for/yield循环中,结果是依次组装的。如下:

(for(i<- (0 until 100000).par) yield i) == (0 until 100000)

注意:如果并行运算修改了共享的变量,则结果无法预知。举例来说, 不要更新个共享的计数器:

    var count = 0
    for (c <- coll.par) {
      if (c % 2 == 0) {
        count += 1
      }
    }

par方法返回的并行集合属于扩展自ParSeq、ParSet或ParMap特质的类型。这些并不是Seq、Set、Map 的子类型,你不能向一个预期顺序集合( sequential collection ) 的方法传入并行集合。
你可以用seq方法将并行集合转换回顺序集合:

val result= coll.par.filter(_ % 2 == 0).seq

并非所有方法都能被并行化。例如,reduceLeft和reduceRight要求每个操作符都要按顺序应用。有另一个方法reduce,对集合的部分进行操作然后组合出结果。为了让这个方案可行,操作符必须是结合的( associative ),它必须满足 ( a   o p   b )   o p   c = a   o p   ( b   o p   c ) (a\ op\ b)\ op\ c = a\ op\ (b\ op\ c) (a op b) op c=a op (b op c)的要求。例如,加法是结合的而减法不是: ( a − b ) − c ≠ a − ( b − c ) (a - b) - c \neq a - (b - c) (ab)c=a(bc)
同理,还有一个fold方法对集合的部分进行操作。可惜它并不像foldLeft和foldRight那么灵活,操作符的两个参数都必须是元素。也就是说,你可以执行coll.par.fold(0)(_ + _),但不能执行更复杂的折叠。
要解决这个问题,有个更一般的aggregate方法,将操作符应用到集合的部分,然后用另一个操作符来组合出结果。例如,str.par.aggregate(Set[Char]())(_ + _, _ ++ _)等效于str.foldLeft(Set[Char]())(_ + _),得到str中所有不同字符的集。
说明: 默认情况下,并行集合使用全局的fork-join线程池,该线程池非常适用于高处理器开销的计算。如果你执行的并行步骤包含阻塞调用,就应该另选一种“执行上下文(execution context)”。