2.4 调用方法时使用参数名
1. 问题描述
当调用方法时,你更喜欢使用参数名
2. 解决方案
常用的指定参数来调用方法格式如下
methodName(param1=value1, param2=value2, ...)
有如下类
class Pizza { var crustSize = 12 var crustType = "Thin" def update(crustSize: Int, crustType: String) { this.crustSize = crustSize this.crustType = crustType } override def toString = { "A %d inch %s crust pizza.".format(crustSize, crustType) } }
可以使用如下方法调用
p.update(crustSize = 16, crustType = "Thick") p.update(crustType = "Pan", crustSize = 14)
3. 讨论
使用参数名调用方法显得冗长,但是具有更好的可读性,当参数类型相同时,其显得尤为有用,可比较如下两种调用
engage(true, true, true, false)
engage(speedIsSet = true, directionIsSet = true, picardSaidMakeItSo = true, turnedOffParkingBrake = false)
显然第二种具有更好的可读性
2.5 定义返回多项(元组)的方法
1. 问题描述
你想要从一个方法中返回多个值,但是你不想将这些值封装在类中
2. 解决方案
Scala可以使用tuple,让你从方法中返回多个值,如下返回三元组
def getStockInfo = { // other code here ... ("NFLX", 100.00, 101.00) // this is a Tuple3 }
然后调用该方法并将返回值赋值给变量
val (symbol, currentPrice, bidPrice) = getStockInfo
3. 讨论
在Java中也可以从方法中返回多个值,但是其是将多个值封装在类中而并非使用tuple
getStockInfo方法返回的是三元组tuple3,tuple最多可以容纳22个变量,即22元组tuple22,如下定义的是二元组
当然也可以直接使用一个val变量来存储方法返回值,然后通过._1、._2符号来访问对应的值
2.6 强制调用者不使用括号调用方法
1. 问题描述
你想强调如下编程风格,在调用访问方法时不使用括号
2. 解决方案
在定义访问方法名后不使用括号,如下例所示
class Pizza { // no parentheses after crustSize def crustSize = 12 }
此时,调用者调用方法时不能使用括号,否则会报错
3. 讨论
在调用访问方法时不适用括号并没有任何副作用,并且可以强制调用者不适用括号进行调用
2.7 创建接受可变参数的方法
1. 问题描述
为了使方法更为灵活,你想要定义一个接受可变参数的方法
2. 解决方案
在参数字段类型后面添加*即可表示方法接受可变个参数
def printAll(strings: String*) { strings.foreach(println) }
针对以上方法,可以有如下调用
printAll() printAll("foo") printAll("foo", "bar") printAll("foo", "bar", "baz")
可以使用_*操作符来适应序列(Array、List、Seq、Vector等),所以其也可被用作实参调用方法
// a sequence of strings val fruits = List("apple", "banana", "cherry") // pass the sequence to the varargs field printAll(fruits: _*)
3. 讨论
当定义一个包含可变参数的方法时,其必须要放在方法签名的最后,在可变参数后面定义一个参数是非法的
并且一个方法中只能有一个可变参数,当一个参数为可变参数,调用时你不需要提供任何参数,如下
当定义一个接受可变个整形的参数的方法时,当使用(a)参数调用(b)无参数调用,其结果不相同
当使用一个或多个参数调用时,其是第一个种情况,当不使用参数调用时,其是第二种情况,是空列表,这样可以防止抛出异常
2.8 定义可抛出异常的方法
1. 问题描述
你想要定义一个可以抛出异常的方法,这样可以警告调用者,或者是你的代码将会被Java代码调用
2. 解决方案
使用@throws注释来声明可能抛出的异常,将注释放在方法之前
@throws(classOf[Exception]) override def play { // exception throwing code here ... }
当一个方法可能抛出多个异常时,将其一一列出
@throws(classOf[IOException]) @throws(classOf[LineUnavailableException]) @throws(classOf[UnsupportedAudioFileException]) def playSoundFileWithJavaAudio { // exception throwing code here ... }
3. 讨论
Scala使用注释声明异常与Java的以下处理方式相同
public void play() throws FooException { // code here ... }
Scala的受检查异常与Java的不相同,Scala不需要方法声明会抛出的异常,并且不需要调用者捕捉异常
即便Scala不需要异常时受检查的,如果不进行测试,也会出现Java中的结果,在下面的代码中,第二个println永远不会被调用
object BoomTest extends App { def boom { throw new Exception } println("Before boom") boom // this line is never reached println("After boom") }
2.9 支持流式编程风格
1. 问题描述
你想要创建一个调用可以使用流式风格编程的API,其也被称为方法链
2. 解决方案
流式编程风格可以让你的方法调用聚合在一起,如下所示
person.setFirstName("LEE") .setLastName("SF") .setAge(25) .setCity("WH") .setState("HB")
为了支持这种风格,做法如下
· 如果类可以被继承,可将方法的返回类型定义为this.type
· 如果类不能被继承,可将方法的返回类型定义为this
下面示例展示了this.type作为set*方法的返回类型
class Person { protected var fname = "" protected var lname = "" def setFirstName(firstName: String): this.type = { fname = firstName this } def setLastName(lastName: String): this.type = { lname = lastName this } } class Employee extends Person { protected var role = "" def setRole(role: String): this.type = { this.role = role this } override def toString = { "%s, %s, %s".format(fname, lname, role) } }
使用如下
object Main extends App { val employee = new Employee // use the fluent methods employee.setFirstName("Al") .setLastName("Alexander") .setRole("Developer") println(employee) }
3. 讨论
如果确定类不会被继承,则将返回类型定义为this.type毫无意义,可以直接返回this即可,如下例所示
final class Pizza { import scala.collection.mutable.ArrayBuffer private val toppings = ArrayBuffer[String]() private var crustSize = 0 private var crustType = "" def addTopping(topping: String) = { toppings += topping this } def setCrustSize(crustSize: Int) = { this.crustSize = crustSize this } def setCrustType(crustType: String) = { this.crustType = crustType this } def print() { println(s"crust size: $crustSize") println(s"crust type: $crustType") println(s"toppings: $toppings") } }
使用如下
object FluentPizzaTest extends App { val p = new Pizza p.setCrustSize(14) .setCrustType("thin") .addTopping("cheese") .addTopping("green olives") .print() }
当类能够被继承时,则需要将返回类型定义为this.type,这使得流式风格在子类中也可以使用
三、总结
本篇主要讲解了Scala中方法的一些使用技巧,谢谢各位园友的观看~