第3章——从Java到Scala

你可以在使用 Scala 的同时运用自己的 Java 技能。在某些方面 Scala 与 Java 类似,但在 许多其他方面又彼此不同。Scala 青睐纯面向对象,但它又尽可能将类型和 Java 的类型对应 起来。Scala 在支持熟悉的命令式编程风格的同时,也支持函数式编程风格。因此,你可以使 用最熟悉的风格立即开始编程,而不用承受陡峭的学习曲线。

3.1 Scala:简洁的 Java

FromJavaToScala/Greetings.java

//Java code
public class Greetings {
  public static void main(String[] args) {
    for(int i = 1; i < 4; i++) {
      System.out.print(i + ",");     
    } 
    System.out.println("Scala Rocks!!!");
  }
}

运行结果

1,2,3,Scala Rocks!!!

FromJavaToScala/Greet.scala

for (i <- 1 to 3) {
  print(s"$i,")
}

println("Scala Rocks!!!")

运行结果

FromJavaToScala/Greet.scala

1,2,3,Scala Rocks!!!

FromJavaToScala/GreetExclusiveUpper.scala

for (i <- 1 until 3) {
  print(s"$i,")
}

println("Scala Rocks!!!")

运行结果

1,2,Scala Rocks!!!

FromJavaToScala/GreetForEach.scala

(1 to 3).foreach(i => print(s"$i,"))

println("Scala Rocks!!!")

运行结果

1,2,3,Scala Rocks!!!

3.2 Java 原始类型对应的 Scala 类

FromJavaToScala/ScalaInt.scala

class ScalaInt {
  def playWithInt(): Unit = {
    val capacity: Int = 10
    val list = new java.util.ArrayList[String]
    list.ensureCapacity(capacity)
  }
}

3.3 元组和多重赋值

FromJavaToScala/MultipleAssignment.scala

def getPersonInfo(primaryKey: Int) = {
  // Assume primaryKey is used to fetch a person's info...
  // Here response is hard-coded
  ("Venkat", "Subramaniam", "venkats@agiledeveloper.com")
}

val (firstName, lastName, emailAddress) = getPersonInfo(1)

println(s"First Name: $firstName")
println(s"Last Name: $lastName")
println(s"Email Address: $emailAddress")

运行结果

First Name: Venkat
Last Name: Subramaniam
Email Address: venkats@agiledeveloper.com

FromJavaToScala/MultipleAssignment2.scala

def getPersonInfo(primaryKey: Int): (String, String, String) = {
  ("Venkat", "Subramaniam", "venkats@agiledeveloper.com")
}

val (firstName, lastName) = getPersonInfo(1)

运行结果

MultipleAssignment2.scala:5: error: constructor cannot be instantiated to
expected type;
 found   : (T1, T2)
 required: (String, String, String)
val (firstName, lastName) = getPersonInfo(1)
    ^
one error found

3.4 灵活的参数和参数值

FromJavaToScala/Parameters.scala

def max(values: Int*) = values.foldLeft(values(0)) { Math.max }

FromJavaToScala/Parameters.scala

max(8, 2, 3)

FromJavaToScala/Parameters.scala

max(2, 5, 3, 7, 1, 6)

FromJavaToScala/ArgType.scala

def function(input: Int*): Unit = println(input.getClass)

function(1, 2, 3)

运行结果

class scala.collection.mutable.WrappedArray$ofInt

FromJavaToScala/CantSendArray.scala

val numbers = Array(2, 5, 3, 7, 1, 6)
max(numbers) // type mismatch error

运行结果

CantSendArray.scala:5: error: type mismatch;
 found   : Array[Int]
 required: Int
max(numbers) // type mismatch error
    ^
one error found

FromJavaToScala/Parameters.scala

val numbers = Array(2, 5, 3, 7, 1, 6)
max(numbers: _*)

FromJavaToScala/DefaultValues.scala

def mail(destination: String = "head office", mailClass: String = "first"): Unit =
  println(s"sending to $destination by $mailClass class")

FromJavaToScala/DefaultValues.scala

mail("Houston office", "Priority")
mail("Boston office")
mail()

运行结果

sending to Houston office by Priority class
sending to Boston office by first class
sending to head office by first class

FromJavaToScala/Named.scala

mail(mailClass = "Priority", destination = "Bahamas office")

FromJavaToScala/Named.scala

mail(mailClass = "Priority")

3.5 隐式参数

FromJavaToScala/ImplicitParameters.scala

class Wifi(name: String) {
  override def toString: String = name
}

def connectToNetwork(user: String)(implicit wifi: Wifi): Unit = {
  println(s"User: $user connected to WIFI $wifi")
}

def atOffice(): Unit = {
  println("--- at the office ---")
  implicit def officeNetwork: Wifi = new Wifi("office-network")
  val cafeteriaNetwork = new Wifi("cafe-connect")

  connectToNetwork("guest")(cafeteriaNetwork)
  connectToNetwork("Jill Coder")
  connectToNetwork("Joe Hacker")
}

def atJoesHome(): Unit = {
  println("--- at Joe's home ---")
  implicit def homeNetwork: Wifi = new Wifi("home-network")

  connectToNetwork("guest")(homeNetwork)
  connectToNetwork("Joe Hacker")
}

atOffice()
atJoesHome()

运行结果

--- at the office ---
User: guest connected to WIFI cafe-connect
User: Jill Coder connected to WIFI office-network
User: Joe Hacker connected to WIFI office-network
--- at Joe's home ---
User: guest connected to WIFI home-network
User: Joe Hacker connected to WIFI home-network

3.6 字符串和多行原始字符串

FromJavaToScala/MultiLine.scala

  val str = """In his famous inaugural speech, John F. Kennedy said
        "And so, my fellow Americans: ask not what your country can do
	for you-ask what you can do for your country." He then proceeded
	to speak to the citizens of the World..."""
  println(str)

运行结果

In his famous inaugural speech, John F. Kennedy said
        "And so, my fellow Americans: ask not what your country can do 
	for you-ask what you can do for your country." He then proceeded 
	to speak to the citizens of the World...

FromJavaToScala/MultiLine2.scala

val str = """In his famous inaugural speech, John F. Kennedy said
            	|"And so, my fellow Americans: ask not what your country can do
            	|for you-ask what you can do for your country." He then proceeded
            	|to speak to the citizens of the World...""".stripMargin
println(str)

运行结果

In his famous inaugural speech, John F. Kennedy said
"And so, my fellow Americans: ask not what your country can do 
for you-ask what you can do for your country." He then proceeded 
to speak to the citizens of the World...

FromJavaToScala/StringInterpolation.scala

val message = s"A discount of $discount% has been applied"

FromJavaToScala/StringInterpolation.scala

var price = 90
val totalPrice = s"The amount of discount is ${price * discount / 100} dollars"

FromJavaToScala/StringInterpolation.scala

val totalPrice = s"The amount of discount is $$${price * discount / 100}"

FromJavaToScala/StringInterpolation.scala

val discount = 10
var price = 100
val totalPrice =
  s"The amount after discount is $$${price * (1 - discount / 100.0)}"
println(totalPrice)

price = 50
println(totalPrice)

运行结果

The amount after discount is $90.0
The amount after discount is $90.0

FromJavaToScala/StringInterpolation.scala

val product = "ticket"
val price = 25.12
val discount = 10
println(s"On $product $discount% saves $$${price * discount / 100.00}")

运行结果

On ticket 10% saves $2.512

3.9 操作符重载

FromJavaToScala/Complex.scala

class Complex(val real: Int, val imaginary: Int) {
  def +(operand: Complex): Complex = {
    new Complex(real + operand.real, imaginary + operand.imaginary)
  }

  override def toString: String = {
    val sign = if (imaginary < 0) "" else "+"
    s"$real$sign${imaginary}i"
  }
}

val c1 = new Complex(1, 2)
val c2 = new Complex(2, -3)
val sum = c1 + c2
println(s"($c1) + ($c2) = $sum")

运行结果

(1+2i) + (2-3i) = 3-1i

FromJavaToScala/Complex2.scala

class Complex(val real: Int, val imaginary: Int) {
  def +(operand: Complex): Complex = {
    println("Calling +")
    new Complex(real + operand.real, imaginary + operand.imaginary)
  }

  def *(operand: Complex): Complex = {
    println("Calling *")
    new Complex(
      real * operand.real - imaginary * operand.imaginary,
      real * operand.imaginary + imaginary * operand.real)
  }
  override def toString: String = {
    val sign = if (imaginary < 0) "" else "+"
    s"$real$sign${imaginary}i"
  }
}

val c1 = new Complex(1, 4)
val c2 = new Complex(2, -3)
val c3 = new Complex(2, 2)
println(c1 + c2 * c3)

运行结果

Calling *
Calling +
11+2i

3.10 Scala 与 Java 的差异

FromJavaToScala/SerialAssignments.scala

var a = 1
var b = 2
a = b = 3 //Error

运行结果

SerialAssignments.scala:4: error: type mismatch;
 found   : Unit
 required: Int
a = b = 3
      ^
one error found

FromJavaToScala/Equality.scala

val str1 = "hello"
val str2 = "hello"
val str3 = new String("hello")

println(str1 == str2) // Equivalent to Java's str1.equals(str2)
println(str1 eq str2) // Equivalent to Java's str1 == str2
println(str1 == str3)
println(str1 eq str3)

运行结果

true
true
true
false

FromJavaToScala/OptionalSemicolon.scala

val list1 = new java.util.ArrayList[Int];
{
  println("Created list1")
}

val list2 = new java.util.ArrayList[Int] {
  println("Created list2")
}

println(list1.getClass)
println(list2.getClass)

运行结果

Created list1
Created list2
class java.util.ArrayList
class Main$$anon$2$$anon$1

FromJavaToScala/AvoidExplicitReturn.scala

def check1 = true
def check2: Boolean = return true
def check3: Boolean = true
println(check1)
println(check2)
println(check3)

运行结果

true
true
true

3.11 默认访问修饰符

FromJavaToScala/Access.scala

class Microwave {
  def start(): Unit = println("started")
  def stop(): Unit = println("stopped")
  private def turnTable(): Unit = println("turning table")
}
val microwave = new Microwave
microwave.start() // OK

运行结果

Access.scala:9: error: method turnTable in class Microwave cannot be
accessed in this.Microwave
microwave.turnTable() //ERROR
          ^
one error found

FromJavaToScala/Protected.scala

class Vehicle {
  protected def checkEngine() {}
}

class Car extends Vehicle {
  def start() { checkEngine() /*OK*/ }
  def tow(car: Car) {
    car.checkEngine() //OK
  }
  def tow(vehicle: Vehicle) {
    vehicle.checkEngine() //ERROR
  }
}

class GasStation {
  def fillGas(vehicle: Vehicle) {
    vehicle.checkEngine() //ERROR
  }
}

运行结果

Protected.scala:12: error: method checkEngine in class Vehicle cannot be
accessed in automobiles.Vehicle
 Access to protected method checkEngine not permitted because
 prefix type automobiles.Vehicle does not conform to
 class Car in package automobiles where the access take place
    vehicle.checkEngine() //ERROR
            ^
Protected.scala:17: error: method checkEngine in class Vehicle cannot be 
accessed in automobiles.Vehicle
 Access to protected method checkEngine not permitted because
 enclosing class GasStation in package automobiles is not a subclass of
 class Vehicle in package automobiles where target is defined
    vehicle.checkEngine() //ERROR
            ^
two errors found

FromJavaToScala/FineGrainedAccessControl.scala

package society {

  package professional {
    class Executive {
      private[professional] var workDetails = null
      private[society] var friends = null
      private[this] var secrets = null

      def help(another: Executive): Unit = {
        println(another.workDetails)
        println(secrets)
        println(another.secrets) //ERROR
      }
    }

    class Assistant {
      def assist(anExec: Executive): Unit = {
        println(anExec.workDetails)
        println(anExec.friends)
      }
    }
  }

  package social {
    class Acquaintance {
      def socialize(person: professional.Executive) {
        println(person.friends)
        println(person.workDetails) // ERROR
      }
    }
  }
}

运行结果

FineGrainedAccessControl.scala:12: error: value secrets is not a member of
society.professional.Executive
        println(another.secrets) //ERROR
                        ^
FineGrainedAccessControl.scala:28: error: variable workDetails in class 
Executive cannot be accessed in society.professional.Executive
        println(person.workDetails) // ERROR
                       ^
two errors found