然而,你和JAVA的蜜月期过去了,你在编程语言的选择上更加务实了.只要有足够的理由,你就可以毫不犹豫去尝试一种新的语言,但JAVA还没有足够的缺陷让你下定决心离开她.此时,你听说了一个叫做Ruby的东东,它的简洁优雅以及巨大的威力给你留下深刻的印象.但你并不是那么确定去使用一个脚步语言来构建你的企业应用.动态类型以及TextMate确实都不错,但对于现实世界,你需要一个更坚实的支柱.作为一个实用主义者,你仍然坚持使用JAVA.
这时,好消息传来了.一门新的编程语言登上了舞台并在开发者的世界引起了一场风暴.Scala貌似具有你对一门编程语言所期待一切: 静态类型,编译为字节码,简洁且富有表现力的语法.你可能已经被它的一些例子给深深吸引了.它看起来和JAVA非常相似,但是剔除了JAVA中冗余的语法结构.Scala没有分号,没有public static void的方法修饰词,并且具有静态类型推断机制.
现在剩下的唯一问题就是你应该从何开始.你也许尝试过去Scala的网站查看相关知识,但是..这一切看起来是那么的函数化:Lamdas,high-order functions,immutable state,recursion out the wazoo.突然让人感到前途未卜.
但是,JavaEE的难民们,不必担心.Scala确实是一门函数式的编程语言,但它同样也是命令式的和面向对象的.也就是说,除了书写那种晦涩难懂的函数式代码(原文: It means that you don’t have to write code with the sole purpose of pleasing Haskell Curry. ),你还有其它的选择.你可以书写可读性很强的代码,以便你一个星期之后还能看懂它.将你的代码给你那些只使用JAVA的同事看,他们甚至也能看懂它.只需要一个正确的引导,你就可以使用Scala来构建你的的JAVA应用.
导读:
如果符合上面所说的,那么这个Scala系列就是为你而准备的.我已经阅读过大量有关Scala的文章以及入门材料(如果你更喜欢函数式的编程,我强烈推荐你去看Alex Blewitt写的系列文章),但很少有文章是为了使JAVA开发比较轻松的转变到Scala来的.我个人缺乏FP(函数式编程)的经验,因此我肯定不会在文章中介绍如何将Scheme代码移植到Scala.该系列文章着重于类比Scala与JAVA,并说明为什么Scala比JAVA更好.
起步:
Java代码
| object HelloWorld extends Application{ println("Hello, World!") } object HelloWorld extends Application{ println("Hello, World!") } |
引用
scalac hello.scala
scala HelloWorld
注意到"hello.scala"文件名没有?Scala并不像Java一样强制你在定义public class时,必须保存在文件名与类名相同的文件中.事实上Scala允许你像C++或Ruby一样,在同一个文件中你想定义多少class都可以.但我们最好还是遵循Java的命名规则,因此作为一个具有良好习惯的程序员,我们应该将上面的代码保存为"HelloWorld.scala".
编辑器:
在刚开始接触Scala,选择一个正确的编辑器是个关键.就像你在使用Java中所了解的那样,IDE非常有用.但作为一门新生的编程语言,Scala目前还没有很好的IDE支持,不过这只是时间问题.在目前,你只有非常有限的选择:
引用
Eclipse(有几个不太成熟的Scala插件)
Emacs
IntelliJ(只支持基本的语法高亮)
TextMate
VIM
jEdit
(译者注:我使用的是UltraEdit,自己配置一下,能够自动缩进与语法高亮以及编译运行,凑合着用了)
上面列的是几个主要的选项,更完整的列表可以去Scala安装目录下的misc/scala-tool-support/文件夹下查看.我个人推荐使用jEidt或者TextMate;如果你有冒险精神,可以去尝试Eclipse上的几个插件.Eclipse上的插件具有通常IDE所具有的一些功能(至少Beta版是这样),譬如语义高亮,代码自动完成,etc.但根据我的经验,这些插件都不够稳定以至于难以使用.Scala是一门比Java简洁多的语言,它对IDE的依赖性比Java小得多,因此这些都不是本质问题,你可以照样做的很好.
再来一个例子
Java代码
| object HelloWorld2{ def main(args:Array[String]) = { var greeting ="" for(i <- 0 until args.length){ greeting += (args(i) + " ") } if(args.length > 0) greeting =greeting.substring(0, greeting.length -1 ) println(greeting) } } object HelloWorld2{ def main(args:Array[String]) = { var greeting ="" for(i <- 0 until args.length){ greeting += (args(i) + " ") } if(args.length > 0) greeting =greeting.substring(0, greeting.length -1 ) println(greeting) } } |
将它保存到HelloWorld2.scala,并使用如下命令编译运行:
引用
scalac HelloWorld2.scala
scala HelloWorld2 Hello, World!
这次我们使用了不同的方式,通过命令行向程序传递参数,其运行的结果同样是在控制台输出"Hello, World".这个程序比上一个复杂一些,首先定义了一个String类型的变量greeting,然后遍历一个数组,最后对String进行适当的处理(Scala专家肯定会建议使用Array#deepMkString(String)(类似于Ruby中的Array::join方法),这样确实没错.但我这里主要是为了介绍一些语言上的知识,而不是API的使用).
首先应该注意的是,这里我们定义了一个main方法.在第一个例子中,我们仅仅继承了Application类,然后把其它的都交给默认构造函数来做.这样很好很简洁,但有两个问题:第一,我们没有办法向程序传递命令行参数;第二,对Scala新手来说,这样看起来有点魔幻.我将在后面的文章中揭开第一个例子中背后的把戏,现在你记住它就是了.
这个例子中的main方法是不是已经让你联想到了JAVA中的 public static void main?没错,Scala中的main就对应Java中的 public static void main.根据这个信息,有经验的程序员就可以通过思考知道更多关于Scala的知识.
一开始,你可能有这样的结论:Scala中的方法隐含就是public的.这基本正确,Scala中的方法默认为public,这意味着Scala中没有public方法修饰词(private与protected都有定义).更进一步的,你会猜测:Scala中的方法默认为static的.然而,这次你的猜想不完全正确.
Scala并没有真正意义上的static属性.你越早认识到这一点,你就越容易理解这门语言.作为替代,Scala有专门的语法让你实现与使用sigleton模式(这正是object的含义).我们实际上声明了一个具有实例方法main(译者注:注意,这个main方法并不是static的)的单实例类(singleton class).我将会在以后详细说明这一点,目前你可以认为object就是一个只具有静态方法的类.(译者注:这个描述不甚准确).
仔细的观察这个例子,我们还可以得到Scala中数组的语法,以及如何显式的指明一个变量的类型.让我们仔细研究一下声明main方法的这行代码:
Java代码
| def main(args:Array[String]) = { def main(args:Array[String]) = { |
Java代码
| public static void main(Array args) public static void main(Array args) |
Java代码
| var myInteger:Int var myInteger:Int |
Java代码
| var greeting ="" var greeting:String ="" var greeting ="" var greeting:String ="" |
细心的读者可能还注意到了,例子中的main方法并没有指明返回类型.这是因为Scala同样可以推断出来.如果我们想显式的指明这点,可以像下面这样:
Java代码
| def main(args:Array[String]):Unit = { def main(args:Array[String]):Unit = { |
数组的遍历:
Java代码
| var greeting ="" for(i <- 0 until args.length) { greeting += (args(i) + " ") } var greeting ="" for(i <- 0 until args.length) { greeting += (args(i) + " ") } |
这段代码比刚才那段稍微复杂点.我们一开始声明了一个String类型的变量greeting,然后使用了一个在Scala中不常用的for循环,这里有一些隐含的类型推断.有Ruby经验的知道在Ruby中的等价形式:
Ruby代码
| for i in 0..(args.size - 1) greeting += args[i] + " " end for i in 0..(args.size - 1) greeting += args[i] + " " end |
Java代码
| val range =0.until(args.length) for(i <- range) { val range =0.until(args.length) for(i <- range) { |
在Scala中,我们可以通过多种不同的形式调用方法.在这个例子中,我们看到了"value methodName param"与"value.methodName(param)"这两种形式的语法是等价的.另外一个很重要的事情是,until方法是RichInt具有的,Int并没有该方法.这里存在一个隐式类型转换,将Int类型的0转换为scala.runtime.RichInt的一个实例.这里不去深究这个类型转换是怎样进行的,我们关心的是RichInt类确实有一个返回Rangle对象的until方法.
因此,事实上这段代码与JAVA中的下列代码在逻辑上是等价的:
Java代码
| for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) { |
可能你还注意到了,循环体中访问数组args元素使用的是圆括号"()",而不是我们习惯的方括号"[]".
更好的遍历方式:
在JAVA 5中引入了一个foreach的语法,像下面这样:
Java代码
| for(String arg: args) { greeting += arg + " "; } for(String arg: args) { greeting += arg + " "; } |
Ruby代码
| args.foreach {arg => greeting += (arg + " ") } args.foreach {arg => greeting += (arg + " ") } |
Ruby代码
| args.foreach(arg => { greeting += (arg + " ") }) args.foreach(arg => { greeting += (arg + " ") }) |
Ruby代码
| args.foreach(arg => greeting +=(arg + " ")) args.foreach(arg => greeting +=(arg + " ")) |
Ruby代码
| object HelloWorld2 { def main(args:Array[String]) = { var greeting = "" args.foreach(arg => greeting += (arg + " ")) if (args.length > 0) greeting = greeting.substring(0, greeting.length - 1) println(greeting) } } object HelloWorld2 { def main(args:Array[String]) = { var greeting = "" args.foreach(arg => greeting += (arg + " ")) if (args.length > 0) greeting = greeting.substring(0, greeting.length - 1) println(greeting) } } |
因为Scala是基于JVM的,因此它从JAVA那儿继承了大量的API.这意味这你能够与JAVA交互使用.并且,你所写的Scala代码事实上使用的就是Java API.比如上面的HelloWorld2中我们使用了一个字符串变量greeting,这个变量事实上就是Java中的String类型.再比如,当你在Scala中声明一个整数类型(Int),编译器会自动将它转换为Java的基本类型int.
Scala还内置了一些隐式类型转换,当需要的时候编译器会自动进行(就像例子中的Int到RichInt类型的转换).比如在Scala中将Array[String]类型传递给需要String[]类型参数的函数时,隐式类型转换就会发生.甚至Scala中的类型参数可以和Java中的泛型相互转化.简单的说,Scala就是一个披着不同语法外衣的Java.
结束
Scala不需要复杂高深的理论或学术知识.一个普通的开发者就可以在下一个企业WEB应用里面使用它.它具有JAVA所缺乏的简洁明了的语法,并且保留了JAVA的高效与可靠性.
译者注:本文中的HelloWorld2还有一下一些版本
Java代码
| object HelloWorld{ def main(args: Array[String]) { println(args.mkString(" ")) } } object HelloWorld{ def main(args: Array[String]) { println(args.mkString(" ")) } } |
| object HelloWorld{ def main(args: Array[String]) { println(args.reduceLeft((a:String,b:String)=>a+" "+b)) } } object HelloWorld{ def main(args: Array[String]) { println(args.reduceLeft((a:String,b:String)=>a+" "+b)) } } Java代码 object HelloWorld{ def main(args: Array[String]) { println(args.reduceLeft[String](_+" "+_)) } } |
首先是用Scala语言写的Java风格的快速排序的代码
Java代码
| def sort(xs: Array[Int]) { def swap(i: Int, j: Int) { val t = xs(i); xs(i) = xs(j); xs(j) = t } def sort1(l: Int, r: Int) { val pivot = xs((l + r) / 2) var i = l; var j = r while (i <= j) { while (xs(i) < pivot) i += 1 while (xs(j) > pivot) j -=1 if (i <= j) { swap(i, j) i += 1 j -= 1 } } if (l < j) sort1(l, j) if (j < r) sort1(i, r) } sort1(0, xs.length 1) } def sort(xs: Array[Int]) { def swap(i: Int, j: Int) { val t = xs(i); xs(i) = xs(j); xs(j) = t } def sort1(l: Int, r: Int) { val pivot = xs((l + r) / 2) var i = l; var j = r while (i <= j) { while (xs(i) < pivot) i += 1 while (xs(j) > pivot) j -=1 if (i <= j) { swap(i, j) i += 1 j -= 1 } } if (l < j) sort1(l, j) if (j < r) sort1(i, r) } sort1(0, xs.length 1) } |
Java代码
| def sort(xs: Array[Int]): Array[Int] = if (xs.length <= 1) xs else { val pivot = xs(xs.length / 2) Array.concat( sort(xs filter (pivot >)), xs filter (pivot ==), sort(xs filter (pivot <))) } |
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/13270562/viewspace-277835/ ,如需转载,请注明出处,否则将追究法律责任。