【原文:Style guide】

目录,内容很多需要一点点消化

  • 1. 没有分号
  • 2. 返回关键字可选
  • 3. Def 和 type(定义和类型)
  • 4. 默认公开
  • 5. 省略括号
  • 6. Classes as first-class citizens(作为一等公民的阶级??)
  • 7. Getters 和 Setters 方法
  • 8. 使用命名参数和默认构造函数初始化 bean
  • 9. 使用 with() 和 tap() 对同一个 bean 进行重复操作
  • 10. Equals 和 ==
  • 11. GStrings (interpolation, multiline)
  • 12. 数据结构的原生语法
  • 13. Groovy 开发工具包
  • 14. 超强switch
  • 15. 导入别名
  • 16. Groovy 的真假
  • 17. 安全的图形导航
  • 18. Assert
  • 19. 默认值的 Elvis 运算符
  • 20. 捕捉任何异常
  • 21. 建议

样式指南
开始探索 Groovy 的 Java 开发人员始终摆脱不了 Java 的思维方式,这将逐步影响学习 Groovy,下面一个个特性,指导你提高开发效率并编写更地道的 Groovy 代码。 本文档的目的是指导这样的开发人员,教授一些常见的 Groovy 语法风格、新操作符和新功能(如闭包等)。本指南并不完整,仅作为快速介绍和进一步指南部分的基础 您是否愿意为文档做出贡献并对其进行改进。

1. 没有分号

如果你有 C / C++ / C# / Java 语言开发经验,一定已经习惯了分号,所以我们把它们放在任何地方。 虽然 Groovy 支持 99% 的 Java 语法,有时将一些 Java 代码粘贴到 Groovy 程序中非常容易,结果到处都是大量的分号。 但是… 分号在 Groovy 中是可选的,我们可以省略,删除分号是更地道的。

2. 返回关键字可选

在 Groovy 中,可以返回在方法体中计算的最后一个表达式,而无需 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 = 3m2
}

在这种情况下,在最后一个表达式之前放置一个换行符,或者显式使用 return 可能会产生更好的可读性。

就我自己而言,有时使用 return 关键字,有时不使用,这通常是一个品味问题。 但是,例如,在闭包内部,我们经常省略它。 因此,即使关键字是可选的,如果你认为它阻碍了代码的可读性,也绝不是强制不使用它。

但请注意一点。 当使用使用 def 关键字而不是特定具体类型定义的方法时,您可能会惊讶地看到有时会返回最后一个表达式。 所以通常更喜欢使用特定的返回类型,如 void 或类型。 在上面的示例中,假设我们忘记将 m2 作为要返回的最后一条语句,最后一个表达式将是 m2.c = 3,这将返回…3,而不是您期望的结果。

if/elsetry/catch 这样的语句也可以返回一个值,因为在这些语句中计算了“最后一个表达式”:

def foo(n) {if(n == 1) {"Roshan"} else {"Dawrani"}
}assert foo(1) == "Roshan"
assert foo(2) == "Dawrani"

3. Def 和 type(定义和类型)

当我们谈论 def 和类型时,我经常看到开发人员同时使用 def 和类型。 但是 def 在这里是多余的。 所以做出选择,要么使用 def 要么使用类型。

所以不要写:

def String name = "Guillaume"

要写成这样:

String name = "Guillaume"
// 或者写成这样
def name = "Guillaume"

在 Groovy 中使用 def 时,实际的类型持有者是 Object(因此您可以将任何对象分配给用 def 定义的变量,如果声明方法返回 def,则返回任何类型的对象)。

定义带有无类型参数的方法时,您可以使用 def 但它不是必需的,因此我们倾向于省略它们。 所以而不是:

void doSomething(def param1, def param2) { }

这样写更好:

void doSomething(param1, param2) { }

但正如我们在文档的最后一节中提到的,通常最好输入方法参数,来帮助记录代码,并帮助 IDE 完成代码,或利用静态类型检查或静态编译功能 Groovy 的。

def 多余且应避免的另一个地方是在定义构造函数时:

class MyClass {def MyClass() {}
}

相反,只需删除 def

class MyClass {MyClass() {}
}

4. 默认公开

默认情况下,Groovy 将类和方法视为公共的。 所以你不必在任何公共的地方都使用 public 修饰符。 只有当它不公开时,你才应该放置一个可见性修饰符。

所以不是:

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

喜欢更简洁的:

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

您可能想知道 package-scope 的可见性,Groovy 允许省略 public 的事实意味着默认情况下不支持此范围,但实际上有一个特殊的 Groovy 注释允许您使用该可见性:

class Server {@PackageScope Cluster cluster
}

5. 省略括号

Groovy 允许您省略顶级表达式的括号,例如 println 命令:

println "Hello"
method a, b

对比:

println("Hello")
method(a, b)

当闭包是方法调用的最后一个参数时,例如使用 Groovy 的 each{} 迭代时,您可以将闭包放在右括号外面,甚至可以省略括号:

list.each( { println it } )
list.each(){ println it }
list.each  { println it }

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

在某些情况下需要括号,例如进行嵌套方法调用或调用不带参数的方法时。

def foo(n) { n }
def bar() { 1 }println foo 1 // won't work
def m = bar   // won't work

6. Classes as first-class citizens(作为一等公民的阶级??)

Groovy 中不需要 .class 后缀,有点像 Java 的 instanceof

例如:

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

使用 GStrings 我们将在下面介绍,并使用一等公民(??):

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

7. Getters 和 Setters 方法

在 Groovy 中,getter 和 setter 构成了我们所说的“属性”,并提供了访问和设置这些属性的快捷方式。 因此,您可以使用类似字段的访问表示法,而不是用Java 的方式调用 getter/setter :

resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
resourceGroup.resourcePrototype.name == SERVER_TYPE_NAMEresourcePrototype.setName("something")
resourcePrototype.name = "something"

在 Groovy 中编写 bean 时,通常称为 POGO(Plain Old Groovy Objects),您不必自己创建字段和 getter/setter,而是让 Groovy 编译器为您完成。

所以不是:

class Person {private String nameString getName() { return name }void setName(String name) { this.name = name }
}

你可以简单地写:

class Person {String name
}

如您所见,没有修饰符可见性的独立“field”实际上使 Groovy 编译器为您生成私有字段以及 getter 和 setter。

当使用 Java 中的此类 POGO 时,getter 和 setter 确实存在,当然可以照常使用。

尽管编译器会创建通常的 getter/setter 逻辑,但如果您希望在这些 getter/setter 中执行任何其他或不同的操作,您仍然可以自由提供它们,并且编译器将使用您的逻辑,而不是默认生成的逻辑。

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

像这样的 bean :

class Server {String nameCluster cluster
}

而不是在后续语句中设置每个 setter,如下所示:

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

你可以将命名参数与默认构造函数一起使用(首先调用构造函数,然后按照它们在映射中指定的顺序调用 setter):

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

9. 使用 with() 和 tap() 对同一个 bean 进行重复操作

Named-parameters with the default constructor is interesting when creating new instances, but what if you are updating an instance that was given to you, do you have to repeat the ‘server’ prefix again and again? No, thanks to the with() and tap() methods that Groovy adds on all objects of any kind:
创建新实例时,带有默认构造函数的命名参数很有趣,但是如果你要更新提供给你的实例,你是否必须一次又一次地重复“server”前缀呢? 不,感谢 Groovy 添加在任何类型的所有对象上的 with() 和 tap() 方法:

server.name = application.name
server.status = status
server.sessionCount = 3
server.start()
server.stop()

对比:

server.with {name = application.namestatus = statussessionCount = 3start()stop()
}

与 Groovy 中的任何闭包一样,最后一条语句被视为返回值。 在上面的例子中,这是 stop() 的结果。 要将其用作仅返回传入对象的构建器,还有 tap():

def person = new Person().with {name = "Ada Lovelace"it // Note the explicit mention of it as the return value
}

对比:

def person = new Person().tap {name = "Ada Lovelace"
}

注意:您也可以使用 with(true) 代替 tap() 和 with(false) 代替 with()。

10. Equals 和 ==

Java 的 == 实际上是 Groovy 的 is() 方法,而 Groovy 的 == 是一个更聪明的 equals()

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

但是要进行通常的 equals() 比较,您应该更喜欢 Groovy 的 ==,因为它也可以避免 NullPointerException,而与 left 或 right 是否为 null 无关。

不是:

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

而是:

status == ControlConstants.STATUS_COMPLETED

11. GStrings (interpolation, multiline)

我们经常在 Java 中使用字符串和变量连接,其中有许多双引号、加号和 \n 字符的开/关作为换行符。 使用内插字符串(称为 GStrings),这样的字符串看起来更好,而且输入起来也不那么痛苦:

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

对比:

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

在花括号内,您可以放置任何类型的表达式,而不仅仅是变量。 对于简单的变量,或者 variable.property,你甚至可以去掉花括号:

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

您甚至可以使用带有 ${-> resource } 的闭包符号懒惰地评估这些表达式。 当 GString 将被强制转换为 String 时,它将评估闭包并获得返回值的 toString() 表示。

例子:

int i = 3def 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 中很长时:

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 的三重双引号和纯字符串的三重单引号。

如果你需要编写正则表达式模式,应该使用“斜线”字符串表示法:

assert "foooo/baaaaar" ==~ /fo+\/ba+r/

“斜线”符号的优点是您不需要双重转义反斜线,使使用正则表达式更简单一些。

最后但并非最不重要的一点是,当您需要字符串常量时更喜欢使用单引号字符串,当您明确依赖字符串插值时使用双引号字符串。

12. 数据结构的原生语法

Groovy 为数据结构(如lists, maps, regex, 或ranges范围)提供原生语法构造。 确保在您的 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']// ranges can be inclusive and exclusive
def range = 10..20 // inclusive
assert range.size() == 11
// use brackets if you need to call a method on a range definition
assert (10..<20).size() == 10 // exclusivedef 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

13. Groovy 开发工具包

继续介绍数据结构,当您需要迭代集合时,Groovy 提供了各种额外的方法,修饰 Java 的核心数据结构,例如 each{}、find{}、findAll{}、every{}、collect{}、inject{} ,这些方法为编程语言添加了函数式风格,并有助于更轻松地处理复杂的算法。 由于语言的动态特性,许多新方法通过装饰应用于各种类型。 您可以在String, Files, Streams, Collections等方面找到许多非常有用的方法:

http://groovy-lang.org/gdk.html

14. 超强switch

Groovy 的 switch 比通常只能接受原语和同化的 C 语言强大得多。 Groovy 的 switch 几乎可以接受任何类型。

def x = 1.23
def result = ""
switch (x) {case "foo": result = "found foo"// lets fall throughcase "bar": result += "bar"case [4, 5, 6, 'inList']:result = "list"breakcase 12..30:result = "range"breakcase Integer:result = "integer"breakcase Number:result = "number"breakcase { it > 3 }:result = "number > 3"breakdefault: result = "default"
}
assert result == "number"

通常来讲,带有 isCase() 方法的类型也可以决定一个值是否与一个 case 对应

15. 导入别名

在 Java 中,当使用同名但来自不同包的两个类(如 java.util.Listjava.awt.List)时,您可以导入一个类,但必须对另一个使用完全限定的名称。

有时,在您的代码中,长类名的多次使用会增加代码的冗长性并降低代码的清晰度。

为了改善这种情况,Groovy 提供了导入别名:

import java.util.List as UtilList
import java.awt.List as AwtList
import javax.swing.WindowConstants as WCUtilList list1 = [WC.EXIT_ON_CLOSE]
assert list1.size() instanceof Integer
def list2 = new AwtList()
assert list2.size() instanceof java.awt.Dimension

还可以在静态导入方法时使用别名:

import static java.lang.Math.abs as mabs
assert mabs(-4) == 4

16. Groovy 的真假

所有对象都可以“强制”为布尔值:所有为 null、void、等于 0 或为空的都计算为 false,如果不是,则计算为 true。

所以而不是写:

if (name != null && name.length > 0) {}

可以这样写:

if (name) {}

collections等也是如此。

因此,可以在 while()、if()、三元运算符、Elvis 运算符(见下文)等中使用一些快捷方式。

甚至可以通过向类中添加布尔 asBoolean() 方法来自定义 Groovy Truth!

17. 安全的图形导航

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

在整个调用链中检查空值,如果任何元素为空,则不会抛出 NullPointerException,如果某项为空,则结果值将为空。

18. Assert

要检查参数、返回值等,您可以使用 assert 语句。

与 Java 的 assert 相反,asserts 不需要激活即可工作,因此始终检查 asserts。

def check(String name) {// name non-null and non-empty according to Groovy Truthassert name// safe navigation + Groovy Truth to checkassert name?.size() > 3
}

你还会注意到 Groovy 的“Power Assert”语句提供的不错的输出,以及每个被断言的子表达式的各种值的图形视图。

19. 默认值的 Elvis 运算符

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

我们经常不得不写这样的代码:

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

感谢 Groovy 真假判断,空检查可以简化为“name”。

更进一步,因为无论如何你都会返回 ‘name’,而不是在这个三元表达式中重复 name 两次,我们可以通过使用 Elvis 运算符以某种方式删除问号和冒号之间的内容,这样上面的内容就变成了:

def result = name ?: "Unknown"

20. 捕捉任何异常

如果你真的不关心在你的 try 块中抛出的异常的类型,你可以简单地捕获它们中的任何一个,并简单地忽略捕获的异常的类型。 所以,不是像这样捕捉异常:

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

然后捕捉任何东西(‘any’ 或 ‘all’,或者任何让你认为它是任何东西的东西):

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

请注意,它正在捕获所有异常,而不是 Throwable。 如果你真的需要捕捉“一切”,你必须明确并说你想要捕捉Throwables。

21. 建议

我将完成一些关于何时以及如何使用可选输入的词。 Groovy 让您决定是使用显式强类型,还是何时使用 def

我有一个相当简单的经验法则:每当您编写的代码将被其他人用作公共 API 时,您应该始终支持使用强类型,它有助于使合同更强大,避免可能通过参数类型错误,提供更好的文档,还有助于 IDE 完成代码。 每当代码仅供您使用时,例如私有方法,或者当 IDE 可以轻松推断类型时,您就可以更自由地决定何时键入或不键入。

Groory语言关于省略的知识点相关推荐

  1. c语言基础回顾 —— 其他知识点

    参考:c语言基础回顾 -- 其他知识点 作者:丶PURSUING 发布时间: 2021-03-11 14:48:59 网址:https://blog.csdn.net/weixin_44742824/ ...

  2. c语言各个英文的作用,C语言最重要的知识点复习资料(国外英文资料).doc

    C语言最重要的知识点复习资料(国外英文资料) C语言最重要的知识点复习资料(国外英文资料) The log Share the next list of return logs in the hidd ...

  3. 计算机二级考试c语言公共知识,2016年电大最新计算机二级考试c语言公共基础题知识点.doc...

    2016年电大最新计算机二级考试c语言公共基础题知识点 计算机二级考试c语言公共基础题知识点第一章 数据结构与算法 1.1 算法 算法:是指解题方案的准确而完整的描述. 算法不等于程序,也不等计算机方 ...

  4. c语言0x1234占两个字节,C语言考试必考知识点

    <C语言考试必考知识点>由会员分享,可在线阅读,更多相关<C语言考试必考知识点(11页珍藏版)>请在人人文库网上搜索. 1.C 语言考试知识点第一章 C 语言基本知识[考点1] ...

  5. C语言入门part1—大致知识点梳理(上篇)

    C语言入门part1-大致知识点梳理(上篇) **关键字:**变量常量,全局变量局部变量,字符串+转义字符+注释,sizeof,求数据类型范围(举例char类型),原码反码补码,scanf等等杂七杂八 ...

  6. C语言入门part2—大致知识点梳理(中篇)

    C语言入门part2-大致知识点梳理(中篇) 关键字: 选择语句,循环语句,函数,数组,操作符,if(a >= 15 && a <= 20)和 if( 15 <= a ...

  7. C语言最重要的知识点【入门干货】

    C语言最重要的知识点 总体上必须清楚的: 1)程序结构是三种:  顺序结构 .选择结构(分支结构).循环结构. 2)读程序都要从main()入口, 然后从最上面顺序往下读(碰到循环做循环,碰到选择做选 ...

  8. C语言的这个小知识点,竟然连开发多年的老司机都了解的不完全

    printf()和scanf()是 C语言中最"多才多艺"的 I.O函数 它使用的转换说明和转义字符 能使程序员恰到好处的控制 想要输入和输出的信息 但这也提高了使用它的难度 今天 ...

  9. c语言二维数组作用,C语言二维数组知识点介绍

    C语言二维数组知识点介绍 数组可以看作是一行连续的数据,只有一个下标,称为一维数组.在实际问题中有很多量是二维的或多维的,因此C语言允许构造多维数组.多维数组元素有多个下标,以确定它在数组中的位置.本 ...

  10. c语言学习之基础知识点介绍(十):数组

    本节主要介绍数组. 一.数组 /* 数组:一个变量可以存n个变量. 语法:类型 数组名[长度(正整数)]; 例如:int score[5];//定义了一个int类型的数组,长度为5,可以保存5个数据. ...

最新文章

  1. [转]笑死人的考试填空
  2. eruda/vconsole 手机端调试利器
  3. 从软件到数件,AI生态如何建立自己的“Android”?天云数据CEO直播详解,可预约 | 量子位·视点...
  4. H264码流的两种形式:Annex B和AVCC
  5. 启明云端分享 | sigmastar SSD201开发板网口直连PC升级
  6. 「应用管理与交付」为什么会成为云原生新的价值聚焦点?
  7. python tab和空格混用_我的 Python 编码规范
  8. 22 大端序和小端序
  9. maven添加外部jar,以及springboot打包
  10. SpringBoot项目集成Mybatis Plus(四)SQL映射文件
  11. Julia : 中文字符串的取值 UnicodeError 及解决方案
  12. VMware虚拟机在Windows10下不兼容解决办法
  13. IGRP和EIGRP 详解
  14. Cannot deserialize instance of `com.xxx.project.biz.domain.xxx` out of START_ARRAY token;
  15. vba 添加outlook 签名_如何在Outlook中添加默认签名
  16. js+html+css筋斗云导航栏
  17. Android-模块化-面向接口编程深度解析,值得收藏
  18. 信息安全-期末复习题
  19. 英特尔服务器cpu型号大全,Intel桌面处理器规格表
  20. 医疗器械标准目录 第二部分专业技术领域(2)

热门文章

  1. C# WPF新版开源控件库:Newbeecoder.UI
  2. Android Studio:activity界面跳转时闪退或报错:xxx keeps stopping
  3. 淘宝订单同步及解决方法
  4. 塞班系统微信连接不上服务器,一个时代的结束!塞班手机已无法登陆微信QQ
  5. 301. 删除无效的括号【我亦无他唯手熟尔】
  6. frp穿透你的远程桌面
  7. kubectl 命令详解(三十五):rollout undo
  8. 外星人台式机无盘服务器,外星人电脑Aurora R6/Aurora R7无盘无法正常引导解决方案...
  9. python学什么内容_老男孩Python都需要学什么内容?老男孩教育
  10. jzoj 4638. 第三条跑道