0
点赞
收藏
分享

微信扫一扫

Android的Gradle技巧 7. 深入groovy


7.  深入groovy
本附录回顾了Groovy编程语言的基础知识。 Gradle构建文件主要由Groovy编写的领域特定语言组成,用于构建。除了DSL之外,任何合法的Groovy代码都可以添加到构建中。
Groovy是一种基于Java的通用编程语言,它编译为Java字节代码。虽然它具有功能能力,但它是一种面向对象的语言,可以说是从C ++到Java的路径中的下一代语言。
基本语法
Groovy的“Hello,World!”程序是示例A-1中所示的一个线程。
实例A-1。你好,世界!在Groovy
println'Hello,World!'
注意事项:
•分号是可选的。如果你添加它们,他们工作,但他们不是必需的。
•括号是可选的,直到它们不是。如果编译器正确地猜测他们应该去哪里,一切工作。否则,将它们添加回来。println方法接受一个String参数。这里括号被省略。
•Groovy中有两种类型的字符串:单引号字符串,如Hello,是java.lang.String的实例。双引号字符串是Groovy字符串并允许插值,如示例A-2所示。
Groovy中没有“原始”。所有变量都使用包装器类,如java.lang.Integer,java.lang.Character和java.lang.Double。整数文本的本机数据类型(如3)为整数。浮点文字的本机数据类型,如3.5,是java.math.BigDecimal。
实例A-2: Groovy中的一些基本数据类型

assert 3.class == Integer
assert (3.5).class == BigDecimal
assert 'abc' instanceof String //1
assert "abc" instanceof String //2
String name = 'Dolly'
assert "Hello, ${name}!" == 'Hello, Dolly!'//3
assert "Hello, $name!" == 'Hello, Dolly!' //4
assert "Hello, $name!" instanceof GString


1单引号字符串是Java字符串


2双引号字符串也是Java字符串,除非您插入


3字符串插值,完整形式


4字符串插值,短形式时没有歧义


请注意,您可以调用文字上的方法,因为它们是包装类的实例。


Groovy允许您使用实际类型(如String,Date或Employee)声明变量,也可以使用def。参见实施例A-3。


实例A-3。静态数据类型与动态数据类型



Integer n = 3
Date now = new Date()
def x = 3
assert x.class == Integer
x = 'abc'
assert x.class == String
x = new Date()
assert x.class == Date

Java自动导入java.lang包。在Groovy中,以下包都将自动导入:


•java.lang


•java.util


•java.io


•java.net


•groovy.lang


•groovy.util


类java.math.BigInteger和java.math.BigDecimal也可以没有import语句。


断言方法和Groovy真理


Groovy中的assert方法根据“Groovy真值”来评估其参数。这意味着:


•非零数(正和负)是真的


•非空集合,包括字符串,是真的


•非空引用为真


•布尔true为真


Groovy Truth在示例A-4中示出。


实例A-4。 Groovy真理


assert 3; assert -1; assert!0


assert  'abc'; assert!''; assert!“”


assert  [3,1,4,1,5,9]


assert ![]


传递的声明什么也不返回。失败的断言抛出异常,如例A-5中,包含大量调试信息。


实A-5。失败的断言


int x = 5; int y = 7


assert 12 == x + y //传递


assert 12 == 3 * x + 4.5 * y /(2 / x + y ** 3)//失败


失败断言的结果如例A-6所示。


实例A-6。失败断言输出


Exception thrown
Assertion failed:
assert 12 == 3 * x + 4.5 * y / (2/x + y**3)
| | | | | | | || | ||
false| 5 | | 7 | |5 | |343
15 | 31.5| 0.4| 7
| | 343.4
| 0.0917297612
15.0917297612
at ConsoleScript11.run(ConsoleScript11:4)


操作符重载

在Groovy中,每个运算符对应一个方法调用。例如,+号调用Number上的plus方法。这在Groovy库中广泛使用。一些实例示于实施例A-7中。


实例A-7。操作符重载


assert 3 + 4 == 3.plus(4)
assert 3 * 4 == 3.multiply(4)
assert 2**6 == 64
assert 2**6 == 2.power(6)
assert 'abc' * 3 == 'abcabcabc' // String.multiply(Number)
try {
3 * 'abc'
} catch (MissingMethodException e) {
// no Number.multiply(String) method
}
String s = 'this is a string'
assert s + ' and more' == 'this is a string and more'
assert s - 'is' == 'th is a string'
assert s - 'is' - 'is' == 'th a string'
Date now = new Date()
Date tomorrow = now + 1 // Date.plus(Integer)
assert tomorrow - 1 == now // Date.minus(Integer)

Groovy有一个求幂运算符**,如图所示。


在Java中,==运算符检查两个引用是否分配给同一个对象。在Groovy中,==调用equals方法,因此它检查等价而不是等同性。如果要检查引用,请使用is方法。

集合
Groovy有集合的本地语法。使用方括号和逗号分隔值以创建ArrayList。您可以使用as运算符将一种集合类型转换为另一种集合类型。集合还具有运算符重载,实现类似加号,减号和乘法的方法(示例A-8)。
实例A-8。集合示例和方法

def nums = [3, 1, 4, 1, 5, 9, 2, 6, 5]
assert nums instanceof ArrayList
Set uniques = nums as Set
assert uniques == [3, 1, 4, 5, 9, 2, 6] as Set
def sorted = nums as SortedSet
assert sorted == [1, 2, 3, 4, 5, 6, 9] as SortedSet
assert sorted instanceof TreeSet
assert nums[0] == 3
assert nums[1] == 1
assert nums[-1] == 5 // end of list
assert nums[-2] == 6
assert nums[0..3] == [3, 1, 4, 1] // two dots is a Range
assert nums[-3..-1] == [2, 6, 5]
assert nums[-1..-3] == [5, 6, 2]
String hello = 'hello'
assert 'olleh' == hello[-1..0] // Strings are collections too



Groovy中的范围由两个值组成,两个值由一对点分隔,如from..to。


范围从起始位置开始扩展,调用每个元素的下一个,直到到达到位置(包括)。


地图使用冒号表示法将键与值分隔开。映射上的方括号运算符是getAt或putAt方法,具体取决于您是访问还是添加值。点运算符类似地重载。详见实施例A-9。


实例A-9。映射实例和方法


def map = [a:1, b:2, c:2]
assert map.getClass() == LinkedHashMap
assert map.a == 1 //1
assert map['b'] == 2 //2
assert map.get('c') == 2 //3


1过载点放在这里


2使用putAt方法


3Java仍然工作

关闭 Closures
Groovy有一个叫Closure的类,它代表一个可以像对象一样使用的代码块。把它看作一个匿名方法的主体,这是一个过分简化,但不是一个坏的开始。
闭包就像一个Java 8 lambda,因为它接受参数并计算一个代码块。 Groovy闭包可以修改在它们之外定义的变量,但是Java 8没有一个名为Lambda的类。
Groovy中的许多方法将闭包作为参数。例如,集合上的每个方法将每个元素提供给一个闭包,并使用它来计算。一个例子在例A-10中。
实例A-10。使用Groovy的每个方法和闭包参数

def nums = [3, 1, 4, 1, 5, 9]
def doubles = [] //1
nums.each { n -> //2
doubles << n * 2 //3
}
assert doubles == [6, 2, 8, 2, 10, 18]


1空列表


2每个都接受一个参数的闭包,在箭头之前,这里称为n


3左移位运算符附加到集合


修改定义在闭包外部的变量被认为是副作用,而不是好的做法。优选收集方法,稍后讨论。


这是将列表中的值加倍的自然方式,但是有一个更好的替代方法,称为collect。 collect方法通过对每个元素应用闭包将集合转换为新的集合。它类似于Java 8中的映射方法,或者只是将其视为map-filter-reduce过程中的映射操作(示例A-11)。


实例A-11。使用Groovy的collect方法来转换集合


def nums = [3, 1, 4, 1, 5, 9]
def doubles == nums.collect { it * 2 }
assert doubles == [6, 2, 8, 2, 10, 18]

当闭包有单个参数(这是默认值),并且不使用arrow运算符给该参数命名时,虚拟名称默认为单词it。在这种情况下,collect方法通过在每个元素的闭包中应用* 2创建双精度集合。



POGOs
只有属性和getter和setter的Java类通常称为普通Java对象或POJO。 Groovy有类似的类叫POGOs。实例A-12。
实例A-12。一个简单的POGO

import groovy.transform.Canonical
@Canonical
class Event {
String name
Date when
int priority
}

这个小类实际上有很多功能。对于POGO:
•默认情况下,类是public
•默认情况下,属性是私有的
•默认情况下,方法是公用的
•为未标记为公共或私有的每个属性生成Getter和setter方法
•提供了默认构造函数和“基于映射”的构造函数(使用“attribute:value”形式的参数)
此外,此POGO包括@Canonical注释,触发抽象语法树(AST)转换。 AST转换以特定方式修改编译器在编译过程中创建的语法树。
@Canonical注释实际上是另外三个AST转换的快捷方式:@ToString,@EqualsAndHashCode和@TupleConstructor。每个都做他们的声音,所以在这种情况下,@Canonical注释添加到这个类:
•toString重写,显示类的完全限定名称,后面是属性的值,按从上到下的顺序
•等价重写,对每个属性的等价性进行零安全检查
•hashCode覆盖,以类似于Joshua Bloch在他的Effective Java(Addison-Wesley)书中很久以前的方式基于属性的值生成整数
•一个附加的构造函数,它将属性作为参数,按顺序
这是七行代码的生产力。例A-13显示了如何使用它。
实例A-13。使用事件POGO

Event e1 = new Event(name: 'Android Studio 1.0',
when: Date.parse('MMM dd, yyyy', 'Dec 8, 2014'),
priority: 1)
Event e2 = new Event(name: 'Android Studio 1.0',
when: Date.parse('MMM dd, yyyy', 'Dec 8, 2014'),
priority: 1)
assert e1.toString() ==
'Event(Android Studio 1.0, Mon Dec 08 00:00:00 EST 2014, 1)'
assert e1 == e2
Set events = [e1, e2]
assert events.size() == 1

Gradle使用所有这些功能,更多,但这个摘要应该让你开始。


Gradov中的Groovy构建文件


Gradle构建文件支持所有Groovy语法。这里有一些具体的例子,但是,说明Groovy在Gradle。


在示例A-14中,单词apply是Project实例上的一个方法。方法上的括号是可选的,在此省略。参数是在Project实例上设置一个名为plugin的属性到提供的字符串值。


实例A-14。为Gradle应用Android插件


apply plugin: 'com.android.application'


在示例A-15中,术语android是插件的DSL的一部分,它将闭包作为参数。闭包内的属性,如compileSdkVersion,是带有可选括号的方法调用。在一些Gradle构建文件中,使用=分配属性,这将调用相应的setter方法。 Android插件的开发人员经常添加一个常规方法,如compileSdkVersion(23),除了setter,setCompileSdkVersion(23)。


实例A-15。在android块中设置属性


android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
}


此外,可以使用点表示法来设置“嵌套”属性(如compileSdkVersion此处):


android.compileSdkVersion = 23


两者都是等价的。


最新版本的插件为Gradle构建文件添加了一个干净的任务。此任务名称为clean,是Delete类的一个实例(作为任务的子类),并接受一个


闭包作为参数。与标准Groovy实践保持一致,闭包显示在括号之后(示例A-16)。


实例A-16。默认清洁任务


task clean(type: Delete) {
delete rootProject.buildDir
}

如果Groovy方法使用Closure作为其最后一个参数,则通常在括号后添加闭包。


这里的实现在rootProject.buildDir上调用delete方法(再次使用可选的括号)。 rootProject属性的值是顶级项目,buildDir的默认值是“build”,因此此任务将删除顶级项目中的“build”目录。


注意,在顶层项目中调用clean也会在app子项目上调用它,这将删除那里的构建目录。


在示例A-17中,编译期是DSL的一部分,这意味着它的参数在编译阶段应用。 fileTree方法用括号显示,尽管它们可以省略。 dir参数接受一个表示本地目录的字符串。 include参数接受文件模式的Groovy列表(方括号)。


实例A-17。文件树依赖关系


dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}



举报

相关推荐

0 条评论