第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!!!");
  }
}
Full source at GitHub

运行结果

1,2,3,Scala Rocks!!!
Full source at GitHub

FromJavaToScala/Greet.scala

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

println("Scala Rocks!!!")
Full source at GitHub

运行结果

FromJavaToScala/Greet.scala

1,2,3,Scala Rocks!!!
Full source at GitHub

FromJavaToScala/GreetExclusiveUpper.scala

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

println("Scala Rocks!!!")
Full source at GitHub

运行结果

1,2,Scala Rocks!!!
Full source at GitHub

FromJavaToScala/GreetForEach.scala

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

println("Scala Rocks!!!")
Full source at GitHub

运行结果

1,2,3,Scala Rocks!!!
Full source at GitHub

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)
  }
}
Full source at GitHub

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")
Full source at GitHub

运行结果

First Name: Venkat
Last Name: Subramaniam
Email Address: venkats@agiledeveloper.com
Full source at GitHub

FromJavaToScala/MultipleAssignment2.scala

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

val (firstName, lastName) = getPersonInfo(1)
Full source at GitHub

运行结果

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
Full source at GitHub

3.4 灵活的参数和参数值

FromJavaToScala/Parameters.scala

def max(values: Int*) = values.foldLeft(values(0)) { Math.max }
Full source at GitHub

FromJavaToScala/Parameters.scala

max(8, 2, 3)
Full source at GitHub

FromJavaToScala/Parameters.scala

max(2, 5, 3, 7, 1, 6)
Full source at GitHub

FromJavaToScala/ArgType.scala

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

function(1, 2, 3)
Full source at GitHub

运行结果

class scala.collection.mutable.WrappedArray$ofInt
Full source at GitHub

FromJavaToScala/CantSendArray.scala

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

运行结果

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

FromJavaToScala/Parameters.scala

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

FromJavaToScala/DefaultValues.scala

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

FromJavaToScala/DefaultValues.scala

mail("Houston office", "Priority")
mail("Boston office")
mail()
Full source at GitHub

运行结果

sending to Houston office by Priority class
sending to Boston office by first class
sending to head office by first class
Full source at GitHub

FromJavaToScala/Named.scala

mail(mailClass = "Priority", destination = "Bahamas office")
Full source at GitHub

FromJavaToScala/Named.scala

mail(mailClass = "Priority")
Full source at GitHub

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()
Full source at GitHub

运行结果

--- 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
Full source at GitHub

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)
Full source at GitHub

运行结果

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...
Full source at GitHub

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)
Full source at GitHub

运行结果

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...
Full source at GitHub

FromJavaToScala/StringInterpolation.scala

val message = s"A discount of $discount% has been applied"
Full source at GitHub

FromJavaToScala/StringInterpolation.scala

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

FromJavaToScala/StringInterpolation.scala

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

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)
Full source at GitHub

运行结果

The amount after discount is $90.0
The amount after discount is $90.0
Full source at GitHub

FromJavaToScala/StringInterpolation.scala

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

运行结果

On ticket 10% saves $2.512
Full source at GitHub

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")
Full source at GitHub

运行结果

(1+2i) + (2-3i) = 3-1i
Full source at GitHub

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)
Full source at GitHub

运行结果

Calling *
Calling +
11+2i
Full source at GitHub

3.10 Scala 与 Java 的差异

FromJavaToScala/SerialAssignments.scala

var a = 1
var b = 2
a = b = 3 //Error
Full source at GitHub

运行结果

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

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)
Full source at GitHub

运行结果

true
true
true
false
Full source at GitHub

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)
Full source at GitHub

运行结果

Created list1
Created list2
class java.util.ArrayList
class Main$$anon$2$$anon$1
Full source at GitHub

FromJavaToScala/AvoidExplicitReturn.scala

def check1 = true
def check2: Boolean = return true
def check3: Boolean = true
println(check1)
println(check2)
println(check3)
Full source at GitHub

运行结果

true
true
true
Full source at GitHub

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
Full source at GitHub

运行结果

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

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
  }
}
Full source at GitHub

运行结果

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
Full source at GitHub

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
      }
    }
  }
}
Full source at GitHub

运行结果

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
Full source at GitHub