
正文
java和scala代码 scala和java混编
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
scala和java的区别
可以说scala来源于java,但又高于java,我的理解是scala就是在java语言的基础上增加了一层编码的 “壳” 让程序人员可以通过函数式编程的方式来开发程序。由于scala最终被编译为.class文件运行在JVM虚拟机中,其实本质上还是java, 所以在scala和java可以互调双方的api;
区别:
1,变量的声明
变量var 常量val scala支持自动类型推测
scala更多的是采用常量,而不是变量来解决问题,这样带来的好处是可以减少多线程并发安全问题,特别适合用于多并发分布式的场景
2,函数的声明
关键字def, Scala函数没有返回值用Unit,相当于java的void
Scala支持函数式编程,可以使用高阶函数 函数是一等公民
3,基本类型
其实可以认为scala中并没有真正意义上的基本类型,他的类型都是类
4,静态
java中静态static是违背java面向对象的编程思想和封装特性的,scala取消了静态的概念,使用了单例对象Object来实现
5,对字符串的支持
Scala支持使用字符串插值的方式对字符串进行格式化,使用$开头进行取值
另外支持使用三引号将其中的内容直接包起来,其中可以包括任何字符而不需要转义
6,类
Scala类中的字段自动带有getter和setter方法,另外可以使用@BeanProperty注解来生成java中的Get/Set方法
Scala中的每个类都有一个主构造器,这个构造器和类定义”交织在一起”,类的参数直接成为类的字段,主构造器执行类体中所有的语句
7,Scala中不支持Break
使用return替代
在循环中用if和布尔类型变量进行守卫
导入java中支持break的包
8,访问范围问题
java中外部看不到内部,内部能看到外部
scala中外部看不到内部,内部看不到外部
9,通配符
Java使用*进行通配,Scala使用 _ 进行通配
10,默认导入的类
scala默认导入java.lang包、scala包、scala.Predef类。
java默认导入java.lang包
11,特质 trait -- 可以类比java中的接口,但是又和接口非常不一样
java中称为类实现了接口 scala中称为混入了特质
和java中的接口不同 scala中的特质可以包含 带有方法体的方法。
相关问答
Q1: 简述 Scala与Java的区别 :以及优劣势,不要复制百科里面的。。
都是编程语言啊。
Scala运行于Java平台(Java虚拟机)java和scala代码,并兼容现有java和scala代码的Java程序。它也能运行于Java ME, CLDC(Java Platform, Micro Edition Connected Limited Device Configuration)上。目前还有另一.NET平台java和scala代码的实现java和scala代码,不过该版本更新有些滞后。 Scala的编译模型(独立编译java和scala代码,动态类加载)与Java和C#一样,所以Scala代码可以调用Java类库(对于.NET实现则可调用.NET类库) 。 Scala包中包含了编译器和类库,以BSD许可证发布。
面向对象,函数式编程
Q2: 用Java在各种框架下编译Scala项目
在IDE上的设置
首先 下载的IntelliJ IDEA的 x(社区版) 因为目前它是最好的Scala的IDE 然后选择File |设置|插件 选择可用的选项卡来安装Scala插件
创建Maven项目
在IntelliJ IDEA中 选择文件|新建项目 然后选择Maven的模块创建一个Maven项目 然后修改如下所示的pom xml 添加所有你需要的设置 建立Scala的汇编语言
project xmlnsxmlns= xmlns:xsi= instance
xsi:schemaLocation= v _ _ xsd
modelVersion /modelVersion
groupId foo/groupId
artifactIdmyapp/artifactId
packagingwar/packaging
version SNAPSHOT/version
namemyapp Java EE Webapp/name
url;/url
properties
spring version RELEASE/spring version
/properties
repositories
repository
id /id
nameRepository hosting the jee artifacts/name
url;/url
/repository
repository
id/id
nameScala tools Maven Repository/name
url;/url
/repository
repository
idwpt release/id
url repo/releases/url
/repository
repository
idwpt snapshot/id
url repo/snapshots/url
/repository
/repositories
pluginRepositories
pluginRepository
id/id
nameScala tools Maven Repository/name
url;/url
/pluginRepository
/pluginRepositories
dependencyManagement
dependencies
dependency
groupId springframework/groupId
artifactIdspring context/artifactId
version${spring version}/version
/dependency
dependency
groupId springframework/groupId
artifactIdspring core/artifactId
version${spring version}/version
/dependency
dependency
groupId springframework/groupId
artifactIdspring web/artifactId
version${spring version}/version
/dependency
dependency
groupId springframework/groupId
artifactIdspring orm/artifactId
version${spring version}/version
/dependency
/dependencies
/dependencyManagement
dependencies
dependency
groupId h database/groupId
artifactIdh /artifactId
version /version
/dependency
dependency
groupId hibernate/groupId
artifactIdhibernate entitymanager/artifactId
version GA/version
/dependency
dependency
groupId springframework/groupId
artifactIdspring orm/artifactId
/dependency
dependency
groupIddev/groupId
artifactIdwpt core/artifactId
version SNAPSHOT/version
scopetest/scope
/dependency
dependency
groupIddev/groupId
artifactIdwpt runtime spring/artifactId
version SNAPSHOT/version
/dependency
dependency
groupIdjavax/groupId
artifactIdjavaee web api/artifactId
version /version
scopeprovided/scope
/dependency
dependency
groupIdjunit/groupId
artifactIdjunit/artifactId
version /version
scopetest/scope
/dependency
dependency
groupId scala lang/groupId
artifactIdscala library/artifactId
version RC /version
/dependency
dependency
groupId apache wicket/groupId
artifactIdwicket/artifactId
version /version
/dependency
dependency
groupId slf j/groupId
artifactIdslf j log j /artifactId
version /version
/dependency
/dependencies
build
pluginManagement
plugins
plugin
groupId apache maven plugins/groupId
artifactIdmaven piler plugin/artifactId
version /version
/plugin
plugin
groupId scala tools/groupId
artifactIdmaven scala plugin/artifactId
version /version
/plugin
/plugins
/pluginManagement
plugins
plugin
groupId apache maven plugins/groupId
artifactIdmaven piler plugin/artifactId
executions
execution
phasepile/phase
goals
goalpile/goal
/goals
/execution
/executions
configuration
source /source
target /target
/configuration
/plugin
plugin
groupId apache maven plugins/groupId
artifactIdmaven war plugin/artifactId
version beta /version
configuration
failOnMissingWebXmlfalse/failOnMissingWebXml
/configuration
/plugin
plugin
groupId scala tools/groupId
artifactIdmaven scala plugin/artifactId
executions
execution
idscala pile first/id
phaseprocess resources/phase
goals
goaladd source/goal
goalpile/goal
/goals
/execution
execution
idscala test pile/id
phaseprocess test resources/phase
goals
goaltestCompile/goal
/goals
/execution
/executions
/plugin
/plugins
finalNamemyapp/finalName
/build
/project
web xml中设置
接下来 修改main/webapp/WEB INF/web xml 从而确立了Wicket的过滤器 打开Spring的JPA实体管理器和Spring监听器 进行Spring的初始化
?xml version= encoding= UTF ?
web app version= xmlns= xmlns:xsi= instance
xsi:schemaLocation= app_ _ xsd
filter
filter namef /filter name
filter class springframework orm jpa support OpenEntityManagerInViewFilter/filter class
/filter
filter
filter namef /filter name
filter class apache wicket protocol WicketFilter/filter class
init param
param nameapplicationClassName/param name
param value foo myapp MyApp/param value
/init param
/filter
filter mapping
filter namef /filter name
url pattern/app/*/url pattern
/filter mapping
filter mapping
filter namef /filter name
url pattern/*/url pattern
/filter mapping
context param
param namecontextConfigLocation/param name
param valueclasspath:/beans xml/param value
/context param
listener
listener class sprntext ContextLoaderListener/listener class
/listener
/web app
设置Spring bean访问和调用的数据库
要定义这些Spring bean 创建main/resources的beans xml以及一下的内容
?xml version= encoding= UTF ?
beansxmln *** eansxmlns=
xmlns:xsi= instance
xmlns:context=
xmlns:tx=
xsi:schemaLocation=
beans xsd
context xsd
tx xsd
context:ponent scan base package= foo myapp /
bean id= emf class= springframework orm jpa LocalContainerEntityManagerFactoryBean
property name= persistenceXmlLocation value= classpath:/META INF/my persistence xml /
/bean
bean id= transactionManager class= springframework orm jpa JpaTransactionManager
property name= entityManagerFactory ref= emf /
/bean
tx:annotation driven /
/beans
读取数据库配置中persistence xml文件 在这里 您将获得一个主目录中名为MyApp的H 数据库 因此 创建main/resources/META INF文件的内容如下
persistencexmlnspersistencexmlns=
xmlns:xsi= instance
xsi:schemaLocation= _ _ xsd
version=
persistence unit name= myapp transaction type= RESOURCE_LOCAL
provider hibernate ejb HibernatePersistence/provider
properties
propertynamepropertyname= nnection driver_class value= h Driver /
property name= nnection url value= jdbc:h :tcp://localhost/~/myapp /
propertynamepropertyname= nnection username value= sa /
propertynamepropertyname= nnection password value= /
property name= hibernate dialect value= hibernate dialect H Dialect /
property name= hibernate hbm ddl auto value= create /
/properties
/persistence unit
/persistence
创建Wicket的页面
在这里 您将创建一个Wicket页面显示从数据库加载一些内容 因此 创建主/Scala文件夹 右键单击它并选择新建|Scala类 命名为我的页面类和投入 foo myapp包中 如下所示
package foo myapp
import apacl _
import basic Label
import list {ListItem ListView}
import apache wicket spring injection annot SpringBean
import apache wicket model CompoundPropertyModel
class MyPage extends WebPage {
@SpringBean
var ps: ProductService = _
val productListView = newListView[Product]( productListView ps getAll) {
def populateItem(item: ListItem[Product]) = {
item setModel(newCompoundPropertyModel[Product](item getDefaultModelObject))
item add(new Label( name ))
item add(new Label( price ))
}
}
add(productListView)
}
请注意 在创建ProductService对象加载的文件之后使用 此外 请注意该字段被分配到一个下划线(_) Scala编译为不可初始化的 而是留在默认状态 在你将覆盖作为编译之前 执行Spring bean的页面构造 现在 创建在src/main/resources//foo/myapp的的l文件
!DOCTYPE HTML PUBLIC //W C//DTD HTML Transitional//EN
table border=
tr wicket:id= productListView
td wicket:id= name /td
td wicket:id= price /td
/tr
/table
/
创建ProductService
右键单击在in the src/main/scala文件夹中的 foo myapp包并选择New | Scala的类 然后选择创建ProductService
package foo myapp
import java util List
trait ProductService {
def getAll: List[Product]
}
这是接口 对创造一个DefaultProductService的Scala在同一个包内进行执行操作
package foo myapp
import javax persistence {PersistenceContext EntityManager}
import springframework stereotype {Service}
import springframework transaction annotation Transactional
import springframework beans factory annotation Autowired
@Service
@Transactional
class DefaultProductService extends ProductService {
@Autowired
var products: Products = _
def getAll = products getAll
}
请注意 把它使用类型文件命名为DAO
创建文件的DAO
要创建的DAO 创建一个名为在同一文件夹
package foo myapp
import java util List
trait Products {
def getAll: List[Product]
}
然后创建在同一文件夹中的执行Scala的DefaultProducts文件
package foo myapp
import javax persistence {PersistenceContext EntityManager}
import springframework stereotype Repository
import java util List
@Repository
class DefaultProducts extends Products {
@PersistenceContext
var em: EntityManager = _
def getAll = {
em createQuery( select p from Product p ) getResultList asInstanceOf[List[Product]]
}
}
创建entity程序
创建entity程序并将其映射到数据库
package foo myapp
import javax persistence {GeneratedValue Id Entity}
@Entity
class Product {
@Id
@GeneratedValue
var id: Long = _
var name: String = _
var price: Double = _
}
创建Wicket的应用程序
最后 创建在同一个MyApp的Scala程序
package foo myapp
import apache wicket protocol WebApplication
dev wicketpagetest MockableSpringBeanInjector
class MyApp extends WebApplication {
def getHomePage = classOf[MyPage]
override def init = {
MockableSpringBeanInjector installInjector(this)
}
}
在这里 您指定为首页我的目录 植入Spring Bean中
运行应用程序
随着IntelliJ IDEA的版本不断改进 您将嵌入到应用服务器运行您的应用程序 这非常容易 在刚刚创建的测试 foo myapp的ManualTest在刚刚创建的测试 foo myapp包一类ManualTest/scala文件(不是main/scala文件) 以下内容是
package foo myapp
dev wicketpagetest {WebAppJettyConfiguration WicketAppJettyLauncher}
object ManualTest {
def main(args: Array[String]) {
val l = new WicketAppJettyLauncher
l startAppInJetty(new WebAppJettyConfiguration)
}
}
要运行的应用程序 首先需要运行数据库服务器上的H 程序 所以 在下载和解压 然后变成h /bin和运行h bat(或在Linux上h sh) ManualTest是在IDEA的编辑器上 在IDEA选择运行DEA 它将运行ManualTest Jetty的运行您的应用程序
为了测试它 请尝试通过在浏览//localhost: /app
不知道各位感觉如何 感谢各位支持!谢谢!
lishixinzhi/Article/program/Java/hx/201311/26175
Q3: Scala和java比较
1、 scala可以编写脚本,编写一个.scala的脚本代码,直接用同scala x.scala进行执行。
但同时scala也可以类似java,通过scalac编译为.class等形式,基于编译执行。
2、 scala可以在交互式的命令中直接编码运行。
3、 支持隐式变量定义,通过var关键词定义一个变量,具体变量类型在赋值后,scala自行进行类型推断。例如var a = List(1,2,3)
4、 常量定义用val 关键词定义
5、 没有静态类型,通过object 定义单例类,main方法就是放在object类型中。
Q4: 面向Java开发人员的Scala指南: 构建计算器,第1 部分
摘要 特定于领域的语言已经成为一个热门话题 很多函数性语言之所以受欢迎 主要是因为它们可以用于构建特定于领域的语言 鉴于此 在 面向 Java? 开发人员的 Scala 指南 系列的第 篇文章中 Ted Neward 着手构建一个简单的计算器 DSL 以此来展示函数性语言的构建 外部 DSL 的强大功能 他研究了 Scala 的一个新的特性 case 类 并重新审视一个功能强大的特性 模式匹配
上个月的文章发表后 我又收到了一些抱怨/评论 说我迄今为止在本系列中所用的示例都没涉及到什么实质性的问题 当然在学习一个新语言的初期使用一些小例子是很合理的 而读者想要看到一些更 现实的 示例 从而了解语言的深层领域和强大功能以及其优势 这也是理所当然的 因此 在这个月的文章中 我们来分两部分练习构建特定于领域的语言(DSL)— 本文以一个小的计算器语言为例
关于本系列
Ted Neward 将和您一起深入探讨 Scala 编程语言 在这个新的 developerWorks 系列 中 您将深入了解 Sacla 并在实践中看到 Scala 的语言功能 进行比较时 Scala 代码和 Java 代码将放在一起展示 但(您将发现)Scala 中的许多内容与您在 Java 编程中发现的任何内容都没有直接关联 而这正是 Scala 的魅力所在!如果用 Java 代码就能够实现的话 又何必再学习 Scala 呢?
特定于领域的语言
可能您无法(或没有时间)承受来自于您的项目经理给您的压力 那么让我直接了当地说吧 特定于领域的语言无非就是尝试(再一次)将一个应用程序的功能放在它该属于的地方 — 用户的手中
通过定义一个新的用户可以理解并直接使用的文本语言 程序员成功摆脱了不停地处理 UI 请求和功能增强的麻烦 而且这样还可以使用户能够自己创建脚本以及其他的工具 用来给他们所构建的应用程序创建新的行为 虽然这个例子可能有点冒险(或许会惹来几封抱怨的电子邮件) 但我还是要说 DSL 的最成功的例子就是 Microsoft® Office Excel 语言 用于表达电子表格单元格的各种计算和内容 甚至有些人认为 SQL 本身就是 DSL 但这次是一个旨在与关系数据库相交互的语言(想象一下如果程序员要通过传统 API read() / write() 调用来从 Oracle 中获取数据的话 那将会是什么样子)
这里构建的 DSL 是一个简单的计算器语言 用于获取并计算数学表达式 其实 这里的目标是要创建一个小型语言 这个语言能够允许用户来输入相对简单的代数表达式 然后这个代码来为它求值并产生结果 为了尽量简单明了 该语言不会支持很多功能完善的计算器所支持的特性 但我不也不想把它的用途限定在教学上 — 该语言一定要具备足够的可扩展性 以使读者无需彻底改变该语言就能够将它用作一个功能更强大的语言的核心 这意味着该语言一定要可以被轻易地扩展 并要尽量保持封装性 用起来不会有任何的阻碍
关于 DSL 的更多信息
DSL 这个主题的涉及面很广 它的丰富性和广泛性不是本文的一个段落可以描述得了的 想要了解更多 DSL 信息的读者可以查阅本文末尾列出的 Martin Fowler 的 正在进展中的图书 特别要注意关于 内部 和 外部 DSL 之间的讨论 Scala 以其灵活的语法和强大的功能而成为最强有力的构建内部和外部 DSL 的语言
换句话说 (最终的)目标是要允许客户机编写代码 以达到如下的目的
清单 计算器 DSL 目标
// This is Java using the Calculator String s = (( * ) + ) ; double result = tedneward calcdsl Calculator evaluate(s); System out println( We got + result); // Should be
我们不会在一篇文章完成所有的论述 但是我们在本篇文章中可以学习到一部分内容 在下一篇文章完成全部内容
从实现和设计的角度看 可以从构建一个基于字符串的解析器来着手构建某种可以 挑选每个字符并动态计算 的解析器 这的确极具诱惑力 但是这只适用于较简单的语言 而且其扩展性不是很好 如果语言的目标是实现简单的扩展性 那么在深入研究实现之前 让我们先花点时间想一想如何设计语言
根据那些基本的编译理论中最精华的部分 您可以得知一个语言处理器(包括解释器和编译器)的基本运算至少由两个阶段组成
● 解析器 用于获取输入的文本并将其转换成 Abstract Syntax Tree(AST) ● 代码生成器(在编译器的情况下) 用于获取 AST 并从中生成所需字节码 或是求值器(在解释器的情况下) 用于获取 AST 并计算它在 AST 里面所发现的内容
拥有 AST 就能够在某种程度上优化结果树 如果意识到这一点的话 那么上述区别的原因就变得更加显而易见了 对于计算器 我们可能要仔细检查表达式 找出可以截去表达式的整个片段的位置 诸如在乘法表达式中运算数为 的位置(它表明无论其他运算数是多少 运算结果都会是 )
您要做的第一件事是为计算器语言定义该 AST 幸运的是 Scala 有 case 类 一种提供了丰富数据 使用了非常薄的封装的类 它们所具有的一些特性使它们很适合构建 AST
case 类
在深入到 AST 定义之前 让我先简要概述一下什么是 case 类 case 类是使 scala 程序员得以使用某些假设的默认值来创建一个类的一种便捷机制 例如 当编写如下内容时
清单 对 person 使用 case 类
case class Person(first:String last:String age:Int){}
Scala 编译器不仅仅可以按照我们对它的期望生成预期的构造函数 — Scala 编译器还可以生成常规意义上的 equals() toString() 和 hashCode() 实现 事实上 这种 case 类很普通(即它没有其他的成员) 因此 case 类声明后面的大括号的内容是可选的
清单 世界上最短的类清单
case class Person(first:String last:String age:Int)
这一点通过我们的老朋友 javap 很容易得以验证
清单 神圣的代码生成器 Batman!
C:\Projects\Exploration\Scalajavap PersonCompiled from case scala public class Person extends java lang Object implements scala ScalaObject scala Product java io Serializable{ public Person(java lang String java lang String int); public java lang Object productElement(int); public int productArity(); public java lang String productPrefix(); public boolean equals(java lang Object); public java lang String toString(); public int hashCode(); public int $tag(); public int age(); public java lang String last(); public java lang String first();}
如您所见 伴随 case 类发生了很多传统类通常不会引发的事情 这是因为 case 类是要与 Scala 的模式匹配(在 集合类型 中曾简短分析过)结合使用的
使用 case 类与使用传统类有些不同 这是因为通常它们都不是通过传统的 new 语法构造而成的 事实上 它们通常是通过一种名称与类相同的工厂方法来创建的
清单 没有使用 new 语法?
object App{ def main(args : Array[String]) : Unit = { val ted = Person( Ted Neward ) }}
case 类本身可能并不比传统类有趣 或者有多么的与众不同 但是在使用它们时会有一个很重要的差别 与引用等式相比 case 类生成的代码更喜欢按位(biise)等式 因此下面的代码对 Java 程序员来说有些有趣的惊喜
清单 这不是以前的类
object App{ def main(args : Array[String]) : Unit = { val ted = Person( Ted Neward ) val ted = Person( Ted Neward ) val amanda = Person( Amanda Laucher ) System out println( ted == amanda: + (if (ted == amanda) Yes else No )) System out println( ted == ted: + (if (ted == ted) Yes else No )) System out println( ted == ted : + (if (ted == ted ) Yes else No )) }}/*C:\Projects\Exploration\Scalascala Appted == amanda: Noted == ted: Yested == ted : Yes*/
case 类的真正价值体现在模式匹配中 本系列的读者可以回顾一下模式匹配(参见 本系列的第二篇文章 关于 Scala 中的各种控制构造) 模式匹配类似 Java 的 switch/case 只不过它的本领和功能更加强大 模式匹配不仅能够检查匹配构造的值 从而执行值匹配 还可以针对局部通配符(类似局部 默认值 的东西)匹配值 case 还可以包括对测试匹配的保护 来自匹配标准的值还可以绑定于局部变量 甚至符合匹配标准的类型本身也可以进行匹配
有了 case 类 模式匹配具备了更强大的功能 如清单 所示
清单 这也不是以前的 switch
case class Person(first:String last:String age:Int);object App{ def main(args : Array[String]) : Unit = { val ted = Person( Ted Neward ) val amanda = Person( Amanda Laucher ) System out println(process(ted)) System out println(process(amanda)) } def process(p : Person) = { Processing + p + reveals that + (p match { case Person(_ _ a) if a = they re certainly old case Person(_ Neward _) = they e from good genes case Person(first last ageInYears) if ageInYears = first + + last + is + ageInYears + years old case _ = I have no idea what to do with this person }) }}/*C:\Projects\Exploration\Scalascala AppProcessing Person(Ted Neward ) reveals that they re certainly old Processing Person(Amanda Laucher ) reveals that Amanda Laucher is years old */
清单 中发生了很多操作 下面就让我们先慢慢了解发生了什么 然后回到计算器 看看如何应用它们
首先 整个 match 表达式被包裹在圆括号中 这并非模式匹配语法的要求 但之所以会这样是因为我把模式匹配表达式的结果根据其前面的前缀串联了起来(切记 函数性语言里面的任何东西都是一个表达式)
其次 第一个 case 表达式里面有两个通配符(带下划线的字符就是通配符) 这意味着该匹配将会为符合匹配的 Person 中那两个字段获取任何值 但是它引入了一个局部变量 a p age 中的值会绑定在这个局部变量上 这个 case 只有在同时提供的起保护作用的表达式(跟在它后边的 if 表达式)成功时才会成功 但只有第一个 Person 会这样 第二个就不会了 第二个 case 表达式在 Person 的 firstName 部分使用了一个通配符 但在 lastName 部分使用常量字符串 Neward 来匹配 在 age 部分使用通配符来匹配
由于第一个 Person 已经通过前面的 case 匹配了 而且第二个 Person 没有姓 Neward 所以该匹配不会为任何一个 Person 而被触发(但是 Person( Michael Neward ) 会由于第一个 case 中的 guard 子句失败而转到第二个 case)
第三个示例展示了模式匹配的一个常见用途 有时称之为提取 在这个提取过程中 匹配对象 p 中的值为了能够在 case 块内使用而被提取到局部变量中(第一个 最后一个和 ageInYears) 最后的 case 表达式是普通 case 的默认值 它只有在其他 case 表达式均未成功的情况下才会被触发
简要了解了 case 类和模式匹配之后 接下来让我们回到创建计算器 AST 的任务上
计算器 AST
首先 计算器的 AST 一定要有一个公用基类型 因为数学表达式通常都由子表达式组成 通过 + ( * ) 就可以很容易地看到这一点 在这个例子中 子表达式 ( * ) 将会是 + 运算的右侧运算数
事实上 这个表达式提供了三种 AST 类型
● 基表达式 ● 承载常量值的 Number 类型 ● 承载运算和两个运算数的 BinaryOperator
想一下 算数中还允许将一元运算符用作求负运算符(减号) 将值从正数转换为负数 因此我们可以引入下列基本 AST
清单 计算器 AST(src/calc scala)
package tedneward calcdsl{ private[calcdsl] abstract class Expr private[calcdsl] case class Number(value : Double) extends Expr private[calcdsl] case class UnaryOp(operator : String arg : Expr) extends Expr private[calcdsl] case class BinaryOp(operator : String left : Expr right : Expr) extends Expr}
注意包声明将所有这些内容放在一个包( tedneward calcdsl)中 以及每一个类前面的访问修饰符声明表明该包可以由该包中的其他成员或子包访问 之所以要注意这个是因为需要拥有一系列可以测试这个代码的 JUnit 测试 计算器的实际客户机并不一定非要看到 AST 因此 要将单元测试编写成 tedneward calcdsl 的一个子包
清单 计算器测试(testsrc/calctest scala)
package tedneward calcdsl test{ class CalcTest { import junit _ Assert _ @Test def ASTTest = { val n = Number( ) assertEquals( n value) } @Test def equalityTest = { val binop = BinaryOp( + Number( ) Number( )) assertEquals(Number( ) binop left) assertEquals(Number( ) binop right) assertEquals( + binop operator) } }}
到目前为止还不错 我们已经有了 AST
再想一想 我们用了四行 Scala 代码构建了一个类型分层结构 表示一个具有任意深度的数学表达式集合(当然这些数学表达式很简单 但仍然很有用) 与 Scala 能够使对象编程更简单 更具表达力相比 这不算什么(不用担心 真正强大的功能还在后面)
接下来 我们需要一个求值函数 它将会获取 AST 并求出它的数字值 有了模式匹配的强大功能 编写这样的函数简直轻而易举
清单 计算器(src/calc scala)
package tedneward calcdsl{ // object Calc { def evaluate(e : Expr) : Double = { e match { case Number(x) = x case UnaryOp( x) = (evaluate(x)) case BinaryOp( + x x ) = (evaluate(x ) + evaluate(x )) case BinaryOp( x x ) = (evaluate(x ) evaluate(x )) case BinaryOp( * x x ) = (evaluate(x ) * evaluate(x )) case BinaryOp( / x x ) = (evaluate(x ) / evaluate(x )) } } }}
注意 evaluate() 返回了一个 Double 它意味着模式匹配中的每一个 case 都必须被求值成一个 Double 值 这个并不难 数字仅仅返回它们的包含的值 但对于剩余的 case(有两种运算符) 我们还必须在执行必要运算(求负 加法 减法等)前计算运算数 正如常在函数性语言中所看到的 会使用到递归 所以我们只需要在执行整体运算前对每一个运算数调用 evaluate() 就可以了
大多数忠实于面向对象的编程人员会认为在各种运算符本身以外 执行运算的想法根本就是错误的 — 这个想法显然大大违背了封装和多态性的原则 坦白说 这个甚至不值得讨论 这很显然违背 了封装原则 至少在传统意义上是这样的
在这里我们需要考虑的一个更大的问题是 我们到底从哪里封装代码?要记住 AST 类在包外是不可见的 还有就是客户机(最终)只会传入它们想求值的表达式的一个字符串表示 只有单元测试在直接与 AST case 类合作
但这并不是说所有的封装都没有用了或过时了 事实上恰好相反 它试图说服我们在对象领域所熟悉的方法之外 还有很多其他的设计方法也很奏效 不要忘了 Scala 兼具对象和函数性 有时候 Expr 需要在自身及其子类上附加其他行为(例如 实现良好输出的 toString 方法) 在这种情况下可以很轻松地将这些方法添加到 Expr 函数性和面向对象的结合提供了另一种选择 无论是函数性编程人员还是对象编程人员 都不会忽略到另一半的设计方法 并且会考虑如何结合两者来达到一些有趣的效果
从设计的角度看 有些其他的选择是有问题的 例如 使用字符串来承载运算符就有可能出现小的输入错误 最终会导致结果不正确 在生产代码中 可能会使用(也许必须使用)枚举而非字符串 使用字符串的话就意味着我们可能潜在地 开放 了运算符 允许调用出更复杂的函数(诸如 abs sin cos tan 等)乃至用户定义的函数 这些函数是基于枚举的方法很难支持的
对所有设计和实现的来说 都不存在一个适当的决策方法 只能承担后果 后果自负
但是这里可以使用一个有趣的小技巧 某些数学表达式可以简化 因而(潜在地)优化了表达式的求值(因此展示了 AST 的有用性)
● 任何加上 的运算数都可以被简化成非零运算数 ● 任何乘以 的运算数都可以被简化成非零运算数 ● 任何乘以 的运算数都可以被简化成零
不止这些 因此我们引入了一个在求值前执行的步骤 叫做 simplify() 使用它执行这些具体的简化工作
清单 计算器(src/calc scala)
def simplify(e : Expr) : Expr = { e match { // Double negation returns the original value case UnaryOp( UnaryOp( x)) = x // Positive returns the original value case UnaryOp( + x) = x // Multiplying x by returns the original value case BinaryOp( * x Number( )) = x // Multiplying by x returns the original value case BinaryOp( * Number( ) x) = x // Multiplying x by returns zero case BinaryOp( * x Number( )) = Number( ) // Multiplying by x returns zero case BinaryOp( * Number( ) x) = Number( ) // Dividing x by returns the original value case BinaryOp( / x Number( )) = x // Adding x to returns the original value case BinaryOp( + x Number( )) = x // Adding to x returns the original value case BinaryOp( + Number( ) x) = x // Anything else cannot (yet) be simplified case _ = e } }
还是要注意如何使用模式匹配的常量匹配和变量绑定特性 从而使得编写这些表达式可以易如反掌 对 evaluate() 惟一一个更改的地方就是包含了在求值前先简化的调用
清单 计算器(src/calc scala)
def evaluate(e : Expr) : Double = { simplify(e) match { case Number(x) = x case UnaryOp( x) = (evaluate(x)) case BinaryOp( + x x ) = (evaluate(x ) + evaluate(x )) case BinaryOp( x x ) = (evaluate(x ) evaluate(x )) case BinaryOp( * x x ) = (evaluate(x ) * evaluate(x )) case BinaryOp( / x x ) = (evaluate(x ) / evaluate(x )) } }
还可以再进一步简化 注意一下 它是如何实现只简化树的最底层的?如果我们有一个包含 BinaryOp( * Number( ) Number( )) 和 Number( ) 的 BinaryOp 的话 那么内部的 BinaryOp 就可以被简化成 Number( ) 但外部的 BinaryOp 也会如此 这是因为此时外部 BinaryOp 的其中一个运算数是零
我突然犯了作家的职业病了 所以我想将它留予读者来定义 其实是想增加点趣味性罢了 如果读者愿意将他们的实现发给我的话 我将会把它放在下一篇文章的代码分析中 将会有两个测试单元来测试这种情况 并会立刻失败 您的任务(如果您选择接受它的话)是使这些测试 — 以及其他任何测试 只要该测试采取了任意程度的 BinaryOp 和 UnaryOp 嵌套 — 通过
结束语
显然我还没有说完 还有分析的工作要做 但是计算器 AST 已经成形 我们无需作出大的变动就可以添加其他的运算 运行 AST 也无需大量的代码(按照 Gang of Four 的 Visitor 模式) 而且我们已经有了一些执行计算本身的工作代码(如果客户机愿意为我们构建用于求值的代码的话)
lishixinzhi/Article/program/Java/hx/201311/25735
Q5: Spark 中用 Scala 和 java 开发有什么区别
Scala到底是什么?在目前众多java和scala代码的JVM语言当中java和scala代码,Scala无疑是最引人注意的语言之一。Scala是一个静态语言,更适合大型工程项目,Scala直接编译成Java字节码,性能接近Java。Scala是一个多范式的语言,java和scala代码你可以混合使用函数式和面向对象编程,混合使用可变类和不变类,混合使用Actor和传统的Java并发库。
短短一个月的时间,Scala于本月冲进了TIOBE的前五十名。一个 Twitter 的开发人员说过,Scala 将会成为现代 Web2.0 的发起语言。LinkedIn 也用这种语言。同样许多其他大的公司如 Sony Picture, EDF, SAP 也开始使用这种语言。为什么Scala发展这么迅猛,可以获得如此热烈的社区支持。
曾冠东还表示,Scala不是Java的杀手,它无法取代Java的地位,也突破不了JVM的限制、Java实现不了的功能它也实现不了。java和scala代码我们可以将Scala形象的理解成大量语法糖的Java。
Scala 开发团队发布了最新的2.9.2稳定版本,Scala 语言的特性有许多,例如高阶函数和对象、抽象类型绑定,actor 使得函数在 Scala 中能是一个子类成为可能,Scala 中的设计模式使得面向对象和函数编程无缝结合。Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和 Scala 的 Actor 模型应用。它已经成功运用在电信行业。Spark 是一种可扩展的数据分析平台,它整合了内存计算的基元,因此,相对于 Hadoop 的集群存储方法,它在性能方面更具优势。Spark 是在 Scala 语言中实现的,并且利用了该语言,为数据处理提供了独一无二的环境。Scala 编译器可以生成字节码,直接运行在使用JVM上。该语言(它实际上代表了可扩展语言)被定义为可直接集成到语言中的简单扩展。
Scala作为一门静态语言,它的主要特性有哪些?
· Scala是面向对象的
Scala是一个纯面向对象语言,在某种意义上来讲所有数值都是对象。对象的类型和行为是由class和trait来描述的。Class的抽象可由子类化和一种灵活的基于mixin的组合机制(它可作为多重继承的简单替代方案)来扩展。
· Scala是函数式的
Scala还是一个函数式语言,在某种意义上来讲所有函数都是数值。Scala为定义匿名函数提供了一种轻量级的语法,它支持高阶(higher-order)函数、允许函数嵌套、支持局部套用(currying)。Scala的case类及其内置支持的模式匹配模型代数类型在许多函数式编程语言中都被使用。
· Scala是静态类型的
Scala配备了一套富有表现力的类型系统,该抽象概念以一种安全的和一致的方式被使用。
· Scala是可扩展的
Scala的设计承认了实践事实,领域特定应用开发通常需要领域特定语言扩展。Scala提供了一个独特的语言组合机制,这可以更加容易地以类库的形式增加新的语言结构:
任何方式可以被用作中缀(infix)或后缀(postfix)操作符闭包按照所期望的类型(目标类型)自动地被构造
两者结合使用可方便地定义新语句,无需扩展语法,也无需使用类似宏的元编程工具。
· Scala可与Java和.NET进行互操作
Scala设计时就考虑了与流行编程环境良好交互,如Java 2运行时环境(JRE)和 .NET框架(CLR)。特别是与主流面向对象语言,如Java和C#尽量无缝交互。Scala有像Java和C#一样的编译模型(独立编译,动态装载类),允许访问成千上万的高质量类库。
在并发性方面,与 Scala 在 .NET 领域中的姐妹语言 F# 相似,Scala 是针对 “并发性问题” 的解决方案之一,让开发人员能够更加轻松地专注于问题的实质,而不用考虑并发编程的低级细节。Actor 编程模式让高度并行应用程序的开发更加简单。Scala把Erlang风格的基于actor的并发带进了JVM。我们可以利用Scala的actor模型在JVM上设计具伸缩性的并发应用程序,以自动获得多核心处理器带来的优势,而不必依照复杂的Java线程模型来编写程序。Scala 为并发性提供了两种级别的支持,这与其他与 Java 相关的主题极为类似:
首先,对底层库的完全访问(比如说 java.util.concurrent)以及对 “传统” Java 并发性语义的支持(比如说监控程序和wait()/notifyAll())。其次,这些基本机制上面有一个抽象层
Scala 提供了在稳定的高性能平台(Java 虚拟机)上生成的能力同时也是一门敏捷性语言。这一类型的语言也有其他的选择,例如 Jython, JRuby, Groovy 和 Clojure, 但是这些都是运行在 JVM 上的动态类型语言。Open Class 的效果让大家会觉得Scala是动态语言,但它是选择隐式转换来实现的,这也正好证明了Scala是静态语言。隐式转换(Implicit conversion)使 Scala 具有类型安全性,正如扩展方法(extension method)之于 C#,开放类(open class)之于 ruby。即:向未曾定义的类型添加方法(如字符串、列表、整数)。这是使得 Scala 符合 DSL(特定领域语言)模型的特性之一。
Scala结合了面向对象和函数编程的优势,函数编程的一个好处就是java和scala代码你能够像运用一个数据那样运用函数,可以用来定义真正高层级的库,或者去定义新的领域特殊语言(DSL)。
在谈及Java与Scala的对比时,曾冠东表示,Scala能调用绝大部分的Java,而Java调用Scala独有的东西会比较难。Java 拥有非常强的概念规范,因此任何一个 Java 程序之间具有非常多的相似之处,并且这样能够方便的进行程序员交替。但是 Scala 并没有这样的统一性,因为这是一门很有表现力的语言。现场曾冠东为我们演示了实际案例,如下图所示:
正所谓,金无足赤,人无完人。Scala对二进制不兼容,语法也越来越复杂,不能突破Bytecode的限制、编译速度有所缓慢。当它被广泛用于单元测试、开发工具、Socket开发、以及面对多核挑战的并发应用。总而言之,Scala是一种函数式面向对象语言,它融汇了许多前所未有的特性,而同时又运行于JVM之上。正如JRuby 创建者之一Charles Nutter 所宣称的那样Scala就是 Java 王位的合法继承人。随着开发者对Scala的兴趣日增,以及越来越多的工具支持,无疑Scala语言将成为广大软件工程师手上一件必不可少的工具。
关于java和scala代码和scala和java混编的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。






