Java程序员的Scala教程 - 1

首先说明一下,这篇文章基本来自scala官网,说是翻译吧,也没有原本的把每句话翻下来,有些地方自己也多提了两句。顺便提一下自己工作也主要和Java打交道,废话不说了,正文如下:

官网教程: http://docs.scala-lang.org/tutorials/scala-for-java-programmers.html

习惯英文的直接上面传送。

1Introduce

scala语言和编译进行一个简单的介绍。

2A First Example

第一个程序还用标准的 Hello World 来做例子。

 

objectHelloWorld{
    def main(args:Array[String]){
        println("Hello, world!")
    }
}    

 

 

Java程序比较类似,他包含了一个main方法来接收命令行参数;方法调用预定义的方法printlnmain方法没有返回值(procedure method 过程方法),所以也不需要对这个方法声明返回类型。

对于java程序员,有以下几点要说明:

  • object

object声明了这是一个单例对象(singleton object)。它同时声明了一个名为HelloWorld的类,和一个叫做HolloWorld的实例,这个实例在第一次调用的时候创建。

  • static

scala里面没有static这个概念,无论是字段还是方法。所以上面的main方法没有static关键字。所有需要声明为static的东西,都在单例对象中声明,就是上面说的object

  • public

例子中main函数也没有public关键字,因为在scala中所有没有指定范围的东西(方法、成员)都默认为public的。

2.1Compiling the example

scalac这个scala的编译器来编译上面程序。和大部分的编译器一样,运行它需要一个文件名,也可以加上其他的选项,然后产生一个或多个对象文件。Scalac生成的对象文件是标准的Java class文件。

比如编译上面的例子:

> scalac HelloWorld.scala

会在当前目录产生几个class文件,其中一个是HelloWorld.class,还包含一个可以直接被scala命令执行的class,如下节所示。

2.2Running the example

编译好,就可以用scala命令运行了,类似java命令:

> scala -classpath .HelloWorld

> Hello, world!

3Interaction with Java

Scala可以很简单的和Java代码交互。Java.lang包中的所有类都会被scala默认导入,而其他的java类就需要自己明确的导入了。

看一个简单的实例:我们希望获取当前时间并用法国风格的格式来格式输出。因为java定义了强大的类库,比如DateDateFormat,我们不需要再引入scala中这些等价的类:

 

import java.util.{Date, Locale}
import java.text.DateFormat
import java.text.DateFormat._

object FrenchDate {
    def main(args: Array[String]) {
        val now = new Date
        val df = getDateInstance(LONG, Locale.FRANCE)
        println(df format now)
    }
}

 

 

scalaimportjava的差不多,但是更强大。以下需要注意:

  1. 同一个包中的不同类可在同一行引入,用大括号包起来就行了

  2. 导入包中的全部类,用_来代替java中的*,因为*scala中是一个有效的标识符(下面会介绍)

  3. 不仅能导入类,而且能导入类中的静态方法和静态字段(都是对象啦),程序中的 getDateInstanceLONG

分析代码第一句,创建一个 Date 实例,val是不可变对象的声明(valvar以后会讲)。然后创建一个日期格式对象,getDateInstance 是之前import的静态方法。然后打印出来,打印时用到了sacal一个有意思的语法,

表达式:

df format now

相当于:

df.format(now)

java交互,不仅能使用它的类,还可以直接继承一个java类、实现某个java接口。

4Everything is an Object

Scala是纯面向对象的语言,everything is an object,包括数字、方法。和java不同,java有原始类型(intbooleanshort)和引用类型,并且不能像操作值一样操作方法。

4.1数字是对象

数字是对象,那么当然应该有方法了,其实常用的操作符就是啦:

1 + 2 * 3 / x

根据上面提到的,等价于:

(1).+(((2).*(3))./(x))

也就是说在scala里,+*,等都是有效的标识符。

第二种写法数字两遍的小括号是必须的,因为scala对标记使用了最长匹配规则,如下:

1.+(2)

会被解释为:

  • 1.

  • +

  • 2

三部分,因为点更接近1,而1.会背认为是1.0,那样就不是一个Int了,而是当作用一个Double来计算。

(1).+(2)

上面这样写才对。

4.2方法是对象

这可能让Java程序员感到更加惊奇,在scala中方法也是对象。可以把方法当作参数来传递,存储在一个变量里,作为返回值。这种操作函数的能力称为函数式编程。(函数式编程有很多探讨,可以google functional programming

一个简单的例子来说明如何想操作值一样使用方法。考虑一个计数函数,没秒来执行一些操作。我们要如何包计数操作传递给这个计数函数呢?当然是作为一个函数了。这种简单的函数传递对很多程序员都不陌生,经常用在用户接口程序,来注册一个回调函数(当某些事件发生时触发)。

下面程序中,计数函数名为oncePerSecond,拥有一个回调函数作为参数,回调函数的类型写为() => Unit,这是对所有没有参数、没有返回值的函数的一种写法。

  • Scala中类型声明和java不一样,区别如下

    • Java: String name;

    • scala: val name: String

    • java: Integer getSumInteger();

    • scala: def getSumInteger: Integer

Unit类似与voidmain函数调用计数函数,传递一个回调函数作为参数。这个程序会每个一秒println一次,一直到你电脑关机(如果不结束程序)。

object Timer {
    def oncePerSecond(callback: () => Unit) {
        while (true) { callback(); Thread sleep 1000 }
    }

    def timeFlies() {
        println("time flies like an arrow...")
    }

    def main(args: Array[String]) {
        oncePerSecond(timeFlies)
    }
}

 

4.3匿名函数 Anonymous functions

上面例子定义的timeFiles函数,只被用到了一次,定义出来有点浪费,在scala中完全可以用匿名函数代替。改写后如下:

object TimerAnonymous {
    def oncePerSecond(callback: () => Unit) {
        while (true) { callback(); Thread sleep 1000 }
    }
    def main(args: Array[String]) {
        oncePerSecond(() =>
            println("time flies like an arrow..."))
    }
}

 

匿名函数用=>来区分函数的参数列表和函数体。当然这个匿名函数的没有参数,也就是一个(),在=>的左边,右边就是函数体,只有一句话。

5Classes

scala中的class定义和java差不多,而且增加了类参数:

class Complex(real: Double, imaginary: Double) {

  def re() = real

  def im() = imaginary

}



这个类包含了两个参数,两个方法。生成实例时必须要包含这两个参数:

new Complex(1.5, 2.3)

注意上面两个方法都没有标明返回值,scala编译器会根据函数体自动推断(例子中为Double)。默认会在函数体的最后一句话前加上一个return,这点以后开单张讲解。

5.1无参方法 Methods without arguments

一个小问题:当调用方法时必须加上一个小括号(方法没有参数时):


object ComplexNumbers {

  def main(args: Array[String]) {

    val c = new Complex(1.2, 3.4)

    println("imaginary part: " + c.im())

  }

}



scala中,对于0参数的方法,无论定义或者调用都可以把小括号省略,如下:


class Complex(real: Double, imaginary: Double) {

  def re = real

  def im = imaginary

}



5.2继承和重写 Inheritance and overriding

Scala中的任何类都集成自父类,如果没有声明父类(上面例子),会隐含集成scala.AnyRef类。

重写父类方法必许使用override关键字修饰:


class Complex(real: Double, imaginary: Double) {

  def re = real

  def im = imaginary

  overridedef toString() =

    "" + re + (if (im < 0) ""else"+") + im + "i"

}


今天到这里,明天明天继续。

posted @ 2012-06-20 21:17  alanland  Views(1079)  Comments(0)    收藏  举报