`
jboy
  • 浏览: 8497 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Groovy编程风格和语言特性指南(针对Java开发人员)

阅读更多

原文 http://groovy.codehaus.org/Groovy+style+and+language+feature+guidelines+for+Java+developers

Groovy编程风格和语言特性指南(针对Java开发人员

作为一个Java开发人员,当/开始学习Groovy,总是会用Java方式循序渐进地学习Groovy以使/的工作效率提高和写更地道的Groovy代码。本文的目的是引导这类开发人员学习一些常用的的Groovy语法风格,学习新的运算符,新的特性闭包,等等。不是详细描述,只能作为一个快速的介绍,和进一步学习的基础部分,欢迎添加,丰富该文档

没有分号

对于一个C / C + + / C/ Java背景的开发人员,我们是如此习惯使用分号,它们无处不在。更糟的是,Groovy支持99Java的语法,并且某些时候复制一些Java代码到你的Groovy程序里是如此容易,这样你的世界就会充斥着无数的分号。但是......Groovy中,分号是可选的,你可以忽略它们,将其删除更地道Groovy风格

可选关键字return

Groovy中,方法体内的最后一个表达式会被返回,而不需要return关键字。尤其是针对简短的方法和闭包省略return显得更简洁

String toString() {return "a server" 

String toString() {"a server" }

但有时候,这并不易于理解当你使用一个变量,并且这个变量出现在多行:

def props() {

def m1 = [a:1, b:2

m2 = m1.findAll { k, v -> v %2 ==0 

m2.c =3 

m2

}

在这种情况下,无论是最后一个表达式之前加上一个换行还是显式地使用return,可能会产生更好的可读性。

我自己,有时使用return关键字,有时没有,它往往是一个品味的问题。例如在使用闭包时,我们通常会省略return所以,即使关键字是可选的,但是不意味着强制性的,如果你认为它妨碍你代码的可读性就别使用

注意如果使用def关键字而不是某个具体类型定义的方法时,有时返回的最后一个表达式可能会让你吃惊。所以通常更喜欢使用一个特定的返回类型,如void某个类型。在我们上面的例子中,假设我们忘了把m2最为最后一条语句返回,最后的表达m2.c == 3,这将返回... 3,而不是期望map

有一些语句,如if / else语句,try / catch语句,也可以返回一个值,因为他们也可以有一个最后表达式

def foo(n) {i

f(n ==1) {

"Roshan" 

}else {

"Dawrani" 

}

assert foo(1) =="Roshan"

assert foo(2) =="Dawrani"

Def具体类型

我们正在谈论def类型,我经常看到开发人员'def'具体类型一起使用。但是,def在这里是多余的。需要做出一个选择,要么使用def,要么使用一个具体类型。

所以,不要这样写:

def String name ="Guillaume"

较好的是这样

String name ="Guillaume"

Groovy中,def表明的实际类型是Object(这样你就可以def定义的变量分配任何对象,和在用def定义的方法里返回任何类型的对象)。

默认public修饰符

默认情况下,Groovy中认为,类和方法是具有public访问权限的。所以,你没有必要使用public修饰符。只有当它不是public的,你应该使用可见性修饰符。

因此,对于以下写法

public class Server { public String toString() {return "a server" } }

更简洁的写法是

class Server { String toString() {"a server" } }

你可能想知道包范围的可见性修饰符,事实上,Groovy允许省略public即表示默认情况下不支持包范围的可见性,但实际上一个特殊的Groovy注解,使用的包可见性

class Server { @PackageScope Cluster cluster }

省略括号

Groovy允许你省略顶级层次表达式的圆括号,如用println的命令:

println "Hello

method a, b

VS

println("Hello") 

method(a, b)

当一个闭包是一个方法调用的最后一个参数,如在使用Groovyeach函数,你可以把闭包放在括号外,甚至可以省略括号:

list.each( { println it } ) 

list.each(){ println it } 

list.each { println it }

总是喜欢第三种形式,这更自然,一对空括号只是无用的语法噪音!

有一些情况,Groovy并不是允许你删除括号。正如我所说的,顶级的表达式可以省略,但嵌套的方法调用,或者赋值语句的右边(?可以省略?),你不能忽略括号

def foo(n) { n }

println foo1 // won't work

def m = foo1

类,一等公民

后缀.class有点像Java的的instanceof,但在Groovy已不再需要

例如:

connection.doPost(BASE_URI +"/modify.hqu", params, ResourcesResponse.class)

使用的GString和一等公民,写法如下

connection.doPost("${BASE_URI}/modify.hqu", params, ResourcesResponse)

GetterSetter

Groovy中,一个gettersetter方法形成了我们所谓的属性,并提供了一个捷径来访问和设置这些属性Java的调用方式不同,你可以使用一个类似字段访问的方式

resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME 

resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME 

resourcePrototype.setName("something")

resourcePrototype.name = "something"

Groovy编写bean,通常被称为POGOsPlain and Old GroovyObjects),你不必创建字段getter / setter,编译器会替你做。

因此,不要这样写

class Person { 

private String name 

String getName() {

return name 

}

void setName(String name) {

this.name = name 

}

可以简单的写

class Person { String name }

正如你看到,一个独立的没有修饰符字段实际上使得Groovy编译器生成一个私有字段相应gettersetter

当然,在Java使用POGOsgettersetter确实存在,并可以照常使用。

尽管编译器创建通用的getter / setter方法的逻辑,然而如果你愿意在这些getter / setter方法做任何附加的或不同的逻辑,你必须可以提供它们,编译器将使用你的逻辑,而不是默认生成。

使用命名参数和默认构造函数初始化bean

一个bean,如:

class Server { String name; Cluster cluster }

可以使用命名参数的默认构造函数(首先构造函数被调用,然后依次调用setter):

def server =new Server(name:"Obelix", cluster: aCluster)

而不是声明后调用各个setter

def server =new Server() 

server.name ="Obelix"

server.cluster = aCluster

使用with()重复操作同一个bean

使用命名参数的默认构造函数创建新的实例有趣,但如果你正在更新的一个得到的实例,你一定要重复一遍又一遍的'server'前缀?不,多亏了Groovy给所有对象添加的with()方法:

server.name = application.name 

server.status = status 

server.sessionCount = 3 

server.start() 

server.stop()

VS

server.with { 

name = application.name 

status = status 

sessionCount = 3 

start() 

stop() 

}

Equals ==

Java==其实是Groovyis()方法,Groovy==是一个聪明的equals()方法!

要比较的对象引用,你应该使用a.is(B)而不是==

对于通常的equals()比较,你应该更喜欢Groovy==,因为它也可以避免NullPointerException异常,无论左边或者右边的变量是不是null

不要这样写:

status !=null && status.equals(ControlConstants.STATUS_COMPLETED)

这样做:

status == ControlConstants.STATUS_COMPLETED

GString内插变量,多行)

Java中我们经常使用双引号,加好和\n换行符来使用字符串和变量串联。利用内插字符串(称为GString),这样的字符串看起来更好并且减少打字的痛苦:

throw new Exception("Unable to convert resource: " + resource)

VS

throw new Exception("Unable to convert resource: ${resource}")

在大括号中,你可以把任何一种表达方式放入其中,而不仅仅是变量。对于简单变量或变量的属性,你甚至可以丢弃的大括号:

throw new Exception("Unable to convert resource: $resource")

你甚至可以延迟评估这些表达式,使用闭包的符号$ { -> resource}。当GString的将被强制转换为String,它会评估闭包,并获得toString()的返回值的。示例:

int i =3 

def s1 ="i's value is: ${i}"

def s2 ="i's value is: ${-> i}" 

i++

assert s1 =="i's value is: 3" // eagerly evaluated, takes the value on creation

assert s2 =="i's value is: 4" // lazily evaluated, takes the new value into account

Java字符串和其连接的表达Java是很冗长的

throw new PluginException("Failed to execute command list-applications:" +

" The group with name " 

parameterMap.groupname[0] +

" is not compatible group of type " 

SERVER_TYPE_NAME)

您可以使用\延续字符(这是一个多行字符串):

throw new PluginException("Failed to execute command list-applications: \ 

The group with name ${parameterMap.groupname[0]} \ 

is not compatible group of type ${SERVER_TYPE_NAME}")

或者使用多行三重引号的字符串:

throw new PluginException("""Failed to execute command list-applications: 

The group with name ${parameterMap.groupname[0]} 

is not compatible group of type ${SERVER_TYPE_NAME)}""")

也可以在该字符串上调用stripIndent()方法剥离出现在多行的字符串的左侧的缩进

另请注意Groovy中的单引号和双引号的区别:单引号总是创建Java字符串,没有内插变量,而双引号可以创建Java字符串,也可以创建GString当有内插变量

对于多行字符串,你可以使用三个引号,也就是说:GString三双引号单纯的字符串三个单引号。

原生语法的数据结构

Groovy提供原生的语法来构造如listmap,正则表达式,范围值等数据结构。确保在你的Groovy程序利用它们。

下面是一些例子:

def list = [1,4,6,9]

// by default, keys are Strings, no need to quote them

// you can wrap keys with () like [(variableStateAcronym): stateName] to insert a variable or object as a key.

def map = [CA:'California', MI:'Michigan']

def range =10..20

def pattern = ~/fo*/

// equivalent to add()

list <<5

// call contains()

assert 4 in list

assert 5 in list

assert 15 in range

// subscript notation

assert list[1] ==4 

// add a new key value pair

map << [WA:'Washington']

// subscript notation

assert map['CA'] =='California'

// property notation

assert map.WA =='Washington' 

// matches() strings against patterns

assert 'foo' =~ pattern

Groovy的开发工具包

当你需要对集合进行迭代并关注在数据结构上时Groovy中提供各种额外的方法,包装了Java的核心数据结构,就像each{}find{}findAll{}every{}collect{}inject{}。这些方法添加了函数编程的风格,并编写复杂的算法更容易。由于语言的动态性质,经过包装,许多新的方法应用到不同类型。你可以找到很多关于字符串,文件,流,集合的非常有用的方法,更多请看

http://groovy.codehaus.org/groovy-jdk/

switch的威力

GroovyswitchC-风格的语言--通常只接受基本类型功能更强大。Groovyswitch语句接受几乎任何一种类型。

def x =1.23

def result =""

switch (x) {

case "foo": result ="found foo" 

// lets fall through 

case "bar": result +="bar" 

case [4,5,6,'inList']: 

result ="list" 

break 

case 12..30

result ="range" 

break 

case Integer: 

result ="integer" 

break 

case Number: 

result ="number" 

break 

default: result ="default"

}

assert result =="number"

更普遍的是,具有isCase()方法的类型,也可以出现在case子句中。

Import使用别名

Java中,当使用不同包里的具有相同的名称的两个类时,如java.util.Listjava.awt.List,你可以导入一个类,但另一个必须使用全名

还有有时候在你的代码中,当频繁使用一个很长的类名,代码变得冗长。

为了改善这种情况下,Groovy允许import使用别名:

import java.util.List as juList

import java.awt.List as aList

import java.awt.WindowConstants as WC

还可以导入静态的方法:

import static pkg.SomeClass.foo

foo()

GroovyTrue

所有对象都可以被转成一个布尔值:一切nullvoidempty都是false,如果不是,则计算结果为true

因此,if (name) {}写法完全可以替代if (name != null && name.length > 0) {}集合类也是如此。

于是可以在类似while()if(),三元运算符,Elvis操作符(见下文)等中运用此技巧

甚至可以自定义的Groovytrue,通过添加一个的布尔asBoolean()方法到你的

安全引用导航

Groovy支持.运算符的一个变体,可以安全导航一个对象图。

Java中,当你对对象路径图中的一个节点兴趣,需要检查是否为NULL往往导致写出来的复杂的if语句或嵌套的if语句:

if (order !=null) {

if (order.getCustomer() !=null) {

if (order.getCustomer().getAddress() !=null) { 

System.out.println(order.getCustomer().getAddress()); 

}

}

}

利用?.安全引用操作符,可以简化代码:

println order?.customer?.address

整个调用链中检查空值,任何元素为null都不会抛出NullPointerException异常,如果有一个为null返回值也是null

断言

要检查参数,返回值,以及更多的东西,你可以使用“assert”语句。

Java的断言相反,断言并不需要被激活才能工作,Groovy中它总是打开的

def check(String name) {

// name non-null and non-empty according to Groovy Truth 

assert name

// safe navigation + Groovy Truth to check 

assert name?.size() >3

}

您还可以看到Groovy强大的断言语句提供的漂亮的输出被断言的每个子表达式的值图形视图。

Elvis操作符提供默认值

Elvis操作符是一种特殊的三元运算符的快捷方式,用于方便的使用默认值。

我们经常要这样写代码:

def result = name !=null ? name :"Unknown"

由于Groovy特性,空检查name!=null可以简化name

再进一步,因为你总是返回name与其在这个三元表达式重复name两次,不如我们以某种方式删除问号和冒号之间的部分,通过使用Elvis操作符,上述代码变成:

def result = name ?:"Unknown"

捕获任何异常

如果你真的不关心try代码块内抛出的异常,你可以简单地捕捉所有的异常并忽略其类型。但是不是像下面一样捕捉throwables

try {// ...}catch (Throwable t) {// something bad happens}

而是捕捉所有东西('任何''所有',或任何让你觉得这是一切的东西):

try {// ...}catch (any) {// something bad happens}

关于强弱类型的建议

最后我会以如何使用可选的类型结束本文Groovy中你可以自己决定是否使用显式的强类型,或者使用def

我有一个相当简单的经验法则:每当你写的代码会被其他人当作一个公共API使用,你应该总是使用强类型,它有助于增强规约,避免可能的传递错误类型参数,提供更好的文档,也有利于IDE的代码完成;如果代码仅是供自己使用,如私有方法,或当IDE可以很容易地推断出的类型,那么你可以自由决定

0
8
分享到:
评论

相关推荐

    精通 Groovy--下一代开发语言

    许多 Java 开发人员非常喜欢 Groovy 代码和 Java 代码的相似性。从学习的角度看,如果知道如何编写 Java 代码,那就已经了解 Groovy 了。Groovy 和 Java 语言的主要区别是:完成同样的任务所需的 Groovy 代码比 Java...

    Groovy in Action 中文版

    《Groovy in Action》是Groovy编程的综合指南,它向Java开发者介绍了Groovy提供的新的动态特性。为了呈现《Groovy in Action》,Manning再次从源头工作,与包括Groovy项目团队成员和经理在内的专家作者团队合作。其结果...

    java 动态脚本语言 精通 Groovy

    java 动态脚本语言 精通 Groovy

    groovy和Java相互调用1

    Groovy 调用 Java 类groovy 调用 Java class 十分方便,只需要在类前导入该 Java 类,在 Groovy 代码中就可以无缝使用该

    Groovy 快速开发指南

    Groovy作可以运行为在JVM上的动态语言,为java开发者带来另一片天地

    Java脚本编程:语言框架与模式

    资源名称:Java脚本编程:语言框架与模式内容简介:《Sun公司核心技术丛书·Java脚本编程语言、框架与模式》讲解了脚本语言的基本概念和使用方法,概括了Java开发人员可以使用的解决方案,并探讨了在Java应用程序中...

    JAVA经典教程-Groovy入门

    如果你已经具备一定的Java基础,想快速学习一门脚本语言,Groovy是个自然的过渡选择。无论编码习惯还是风格,Groovy是最接近Java的。通过Groovy1.1的annotation支持,你能够在Groovy里很自然地使用Seam,Hibernate,...

    [Groovy] Making Java Groovy 英文版

    Making Java Groovy is a practical handbook for developers who want to blend Groovy into their day to day work with Java It starts by introducing the key differences between Java and Groovy and how you...

    Groovy入门经典.pdf

     本书是有关Groovy的第一本正式出版物,作者KennethBarclay和JohnSavage介绍了Groovy开发的所有主要领域,并解释了这种创新性的编程语言给Java平台赋予的动态特性。阅读本书只要求具备Java编程的一般性知识。不管你...

    JGSK, Java,Groovy,Scala,Kotlin 四种语言的特点对比.zip

    JGSK, Java,Groovy,Scala,Kotlin 四种语言的特点对比

    Groovy+Java混合使用例子

    Groovy环境搭建教程中的例子工程,纯Java、纯Groovy以及Java+Groovy混合 教程参考:http://blog.csdn.net/rcom10002/archive/2011/06/26/6568557.aspx

    AndroidDemoIn4Languages, 在Android开发中,比较 Java Groovy Scala Kotlin.zip

    AndroidDemoIn4Languages, 在Android开发中,比较 Java Groovy Scala Kotlin 中文版 日本語 AndroidDemoIn4Languages为了了解Android开发的更好语言,用 Java 。Groovy 。Scala 和Kotlin编写了一个简单的Android应用...

    Groovy入门经典

    , 本书是有关Groovy的第一本正式出版物,作者Kenneth Barclay和John Savage介绍了Groovy开发的所有主要领域,并解释了这种创新性的编程语言给Java平台赋予的动态特性。阅读本书只要求具备Java编程的一般性知识。不管...

    Java 开发 2_0 通过 CouchDB 和 Groovy 的 RESTClient 实现 REST

    Java 开发 2_0 通过 CouchDB 和 Groovy 的 RESTClient 实现 REST

    Groovy v2.4.13官方版

    Groovy 是用于Java虚拟机的一种敏捷的动态语言,它结合了Python、Ruby和Smalltalk的许多强大的特性。它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多...

    Java Groovy

    Making Java Groovy

    [Groovy] Groovy 编程 (英文版)

    [Pragmatic Bookshelf] Groovy 编程 (英文版) [Pragmatic Bookshelf] Programming Groovy Dynamic Productivity for the Java Developer (E-Book) ☆ 出版信息:☆ [作者信息] Venkat Subramaniam [出版机构] ...

    Java调用Groovy,实时动态加载数据库groovy脚本

    Java调用Groovy,实时动态加载数据库groovy脚本,java读取mongoDB的groovy脚本,加载实时运行,热部署

    Java Groovy结合使用

    概述主要介绍Java、spring与groovy结合使用,高清英文版本

    Java中使用Groovy的三种方式

    Java中使用Groovy的三种方式,详细见我的博客。

Global site tag (gtag.js) - Google Analytics