java scala 数组_从Java走进Scala:使用元组、数组和列表(2)

元组和集合

在 C++ 中,我们将之称为结构体。在 Java 编程中,我们称之为数据传输对象或参数对象。在 Scala 中,我们称为元组。实质上,它们是一些将其他数据类型收集到单个实例的类,并且不使用封装或抽象 — 实际上,不 使用任何抽象常常更有用。

在 Scala 创建一个元组类型非常的简单,这只是主体的一部分:如果首先将元素公开给外部,那么在类型内部创建描述这些元素的名称就毫无价值。考虑清单 3:

清单 3. tuples.scala// JUnit test suite

//

classTupleTest

{

importorg.junit._, Assert._

importjava.util.Date

@Testdef simpleTuples() =

{

val tedsStartingDateWithScala = Date.parse("3/7/2006")

val tuple = ("Ted","Scala", tedsStartingDateWithScala)

assertEquals(tuple._1,"Ted")

assertEquals(tuple._2,"Scala")

assertEquals(tuple._3, tedsStartingDateWithScala)

}

}

创建元组非常简单,将值放入一组圆括号内,就好象调用一个方法调用一样。提取这些值只需要调用 “_n” 方法,其中 n 表示相关的元组元素的位置参数:_1 表示第一位,_2 表示第二位,依此类推。传统的 Java java.util.Map 实质上是一个分两部分的元组集合。

元组可以轻松地实现使用单个实体移动多个值,这意味着元组可以提供在 Java 编程中非常重量级的操作:多个返回值。例如,某个方法可以计算 String 中字符的数量,并返回该 String 中出现次数最多的字符,但是如果程序员希望同时 返回最常出现的字符和 它出现的次数,那么程序设计就有点复杂了:或是创建一个包含字符及其出现次数的显式类,或将值作为字段保存到对象中并在需要时返回字段值。无论使用哪种方法,与使用 Scala 相比,都需要编写大量代码;通过简单地返回包含字符及其出现次数的元组,Scala 不仅可以轻松地使用 “_1”、“_2” 等访问元组的各个值,还可以轻松地返回多个返回值。

如下节所示,Scala 频繁地将 Option 和元组保存到集合(例如 Array[T] 或列表)中,从而通过一个比较简单的结构提供了极大的灵活性和威力。

数组带您走出阴霾

让我们重新审视一个老朋友 — 数组 — 在 Scala 中是 Array[T]。和 Java 代码中的数组一样,Scala 的 Array[T] 是一组有序的元素序列,使用表示数组位置的数值进行索引,并且该值不可以超过数组的总大小,如清单 4 所示:

清单 4. array.scalaobject ArrayExample1

{

def main(args : Array[String]) : Unit =

{

for(i 0to args.length-1)

{

System.out.println(args(i))

}

}

}

尽管等同于 Java 代码中的数组(毕竟后者是最终的编译结果),Scala 中的数组使用了截然不同的定义。对于新手,Scala 中的数组实际上就是泛型类,没有增加 “内置” 状态(至少,不会比 Scala 库附带的其他类多)。例如,在 Scala 中,数组一般定义为 Array[T] 的实例,这个类定义了一些额外的有趣方法,包括常见的 “length” 方法,它将返回数组的长度。因此,在 Scala 中,可以按照传统意义使用 Array,例如使用 Int 在 0 到 args.length - 1 间进行迭代,并获取数组的第 i 个元素(使用圆括号而不是方括号来指定返回哪个元素,这是另一种名称比较有趣的方法)。

扩展数组

事实证明 Array 拥有大量方法,这些方法继承自一个非常庞大的 parent 层次结构:Array 扩展 Array0,后者扩展 ArrayLike[A],ArrayLike[A] 扩展 Mutable[A],Mutable[A] 又扩展 RandomAccessSeq[A],RandomAccessSeq[A] 扩展了 Seq[A],等等。实际上,这种层次结构意味着 Array 可以执行很多操作,因此与 Java 编程相比,在 Scala 中可以更轻松地使用数组。

例如,如清单 4 所示,使用 foreach 方法遍历数组更加简单并且更贴近函数的方式,这些都继承自 Iterable 特性:

清单 5. ArrayExample2object

{

def main(args : Array[String]) : Unit =

{

args.foreach( (arg) => System.out.println(arg) )

}

}

看上去您没有节省多少工作,但是,将一个函数(匿名或其他)传入到另一个类中以便获得在特定语义下(在本例中指遍历数组)执行的能力,是函数编程的常见主题。以这种方式使用更高阶函数并不局限于迭代;事实上,还得经常对数组内容执行一些过滤 操作去掉无用的内容,然后再处理结果。例如,在 Scala 中,可以轻松地使用 filter 方法进行过滤,然后获取结果列表并使用 map 和另一个函数(类型为 (T) => U,其中 T 和 U 都是泛型类型),或 foreach 来处理每个元素。我在清单 6 中采取了后一种方法(注意 filter 使用了一个 (T) : Boolean 方法,意味着使用数组持有的任意类型的参数,并返回一个 Boolean)。

清单 6. 查找所有 Scala 程序员classArrayTest

{

importorg.junit._, Assert._

@Testdef testFilter =

{

val programmers = Array(

newPerson("Ted","Neward",37,50000,

Array("C++","Java","Scala","Groovy","C#","F#","Ruby")),

newPerson("Amanda","Laucher",27,45000,

Array("C#","F#","Java","Scala")),

newPerson("Luke","Hoban",32,45000,

Array("C#","Visual Basic","F#")),

newPerson("Scott","Davis",40,50000,

Array("Java","Groovy"))

)

// 查找所有Scala程序员 ...

val scalaProgs =

programmers.filter((p) => p.skills.contains("Scala") )

// 应该只有2

assertEquals(2, scalaProgs.length)

// ... now perform an operation on each programmer in the resulting

// array of Scala programmers (give them a raise, of course!)

//

scalaProgs.foreach((p) => p.salary +=5000)

// Should each be increased by 5000 ...

assertEquals(programmers(0).salary,50000+5000)

assertEquals(programmers(1).salary,45000+5000)

// ... except for our programmers who don't know Scala

assertEquals(programmers(2).salary,45000)

assertEquals(programmers(3).salary,50000)

}

}

创建一个新的 Array 时将用到 map 函数,保持原始的数组内容不变,实际上大多数函数性程序员都喜欢这种方式:

清单 7. Filter 和 map@Testdef testFilterAndMap =

{

val programmers = Array(

newPerson("Ted","Neward",37,50000,

Array("C++","Java","Scala","C#","F#","Ruby")),

newPerson("Amanda","Laucher",27,45000,

Array("C#","F#","Java","Scala")),

newPerson("Luke","Hoban",32,45000,

Array("C#","Visual Basic","F#"))

newPerson("Scott","Davis",40,50000,

Array("Java","Groovy"))

)

// Find all the Scala programmers ...

val scalaProgs =

programmers.filter((p) => p.skills.contains("Scala") )

// Should only be 2

assertEquals(2, scalaProgs.length)

// ... now perform an operation on each programmer in the resulting

// array of Scala programmers (give them a raise, of course!)

//

def raiseTheScalaProgrammer(p : Person) =

{

newPerson(p.firstName, p.lastName, p.age,

p.salary +5000, p.skills)

}

val raisedScalaProgs =

scalaProgs.map(raiseTheScalaProgrammer)

assertEquals(2, raisedScalaProgs.length)

assertEquals(50000+5000, raisedScalaProgs(0).salary)

assertEquals(45000+5000, raisedScalaProgs(1).salary)

}

注意,在清单 7 中,Person 的 salary 成员可以标记为 “val”,表示不可修改,而不是像上文一样为了修改不同程序员的薪资而标记为 “var”。

Scala 的 Array 提供了很多方法,在这里无法一一列出并演示。总的来说,在使用数组时,应该充分地利用 Array 提供的方法,而不是使用传统的 for ... 模式遍历数组并查找或执行需要的操作。最简单的实现方法通常是编写一个函数(如果有必要的话可以使用嵌套,如清单 7 中的 testFilterAndMap 示例所示),这个函数可以执行所需的操作,然后根据期望的结果将该函数传递给 Array 中的 map、filter、foreach 或其他方法之一。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值