groovy比起java-有哪些地方写起来更舒服

java发展缓慢,语法落后冗余

说起java,其实java挺好的,java现在的性能也不错,但是,java的语法显然比较落后,而且冗余,getter/setter之类的,5的泛型 for each,autobox,7的钻石语法,try catch 多个exception,8的lambda,总之发展缓慢,9也跳票了.

groovy 是什么,有哪些特性

groovy是一个可选的动态类型语言,有静态编译的能力.在我看来,groovy写起来很舒服,有一些动态语言的优势,而且,它和java是100%兼容的,如果你使用静态编译,那么几乎所有的特性也能和java互掉

先来几个耳目一新的特性

int a=1//不需要分号
String multiLine='''
1//适应osc的markdwon
2//适应osc的markdwon
3'''//多行字符串
def map=[a:1,b:2]//这是个map
def list=[1,2,3,4,5]//这是个list
def range=1..5//这是个range
// null 空集合(包含map) 0 空字符串 空数组 在boolean环境中是false
def aMap=[:]
if (aMap){//groovy的false值,上面也提过
println('这段代码不会被执行')//aMap意味着false
}
String interpolationString="$map or ${map}"//这是插值字符串,基本现代的语言都有吧
map << ['c':3]//这是重载运算符,实现起来其实很简单

好了,先从这几个小特性说起,两个语言的对比范畴很大,但本文主要从语法的便利性角度入手,告诉你为什么groovy写着舒服

1 可选分号;

大部分人可能觉得就是少写个分号而已,我列到第一,大惊小怪.但是实际上我告诉你,你写了那么多年的分号白写了,实在没啥用,kotlin已经列为可选了,我觉得这也算是现代语言的标志之一,去掉旧时代的冗余语法

分号没用,因为大家写java,基本都一行一句,没必要加分号,编译器自己加就完了(一行多句还是要自己加),不加分号也不影响代码的可读性,实际上完全不影响.我见到的现代语言中,rust需要分号来结尾,但是rust的分号是用来区别句子和表达式的,加分号是语句,不加分号是表达式(有返回值),是有真正的需求来区分语义的,但是java显然不需要.

你java打了那么多年的分号,实际不需要,是浪费时间,我写js的时候也不打分号,当然js的不打分号是有潜在的坑的,你需要知道,不过我这里不多说了

2 多行字符串和插值字符串

实际上,这是一种很迫切的需求,可惜java就没有

比如我用spring jdbc,写sql的时候,我需要很长的sql,而且这个sql我就用一次,很特殊,(没必要用mybatis的方式抽出去),这个时候,我想怎么换行,就怎么换行,很随意的.至于插值,这个明显节约代码量,省工.

'string'单引号闭合是String,"string${aaa}"双引号闭合是GString,支持插值,目前知道这些就好了

我想,这也是java的mybatis之类的流行的一个原因吧,java不支持多行字符串,所以代码里面写sql有些虐

3 友好的map和list操作,自己看代码就清楚了

def numList = [1, 2, 3, 4, 5]//很方便,等价List numList=new ArrayList();numList.add(1) ... 其实这个实现很简单,但是java也许就是不愿意做吧
def numMap = [a: 1, b: 2, c: 3]//很方便,等价也很方便
def list = [] //默认是ArrayList
assert list.class == ArrayList//可以省略.class
def map = [:] //默认是LinkedHashMap,为什么不是{},而是[:],官方的解释就是{}和闭包还有语句的大括号冲突了,不过这也没什么
assert map.class == LinkedHashMap
map.'a' = 1
map.b = 2
map << [c: 3]
assert map == [a: 1, b: 2, c: 3]
assert map.a == 1
assert map.'a' == 1//map 包含空白字符之类的可以用这种方式
assert map['a'] == 1//map 包含空白字符之类的可以用这种方式
list.add(1)
list << 2
assert list == [1, 2]
assert list[0] == 1
LinkedList list1 = []//因为默认是ArrayList,这种方式可以改变
assert list1.class == LinkedList
def list2 = [:] as LinkedList//另外一种方式改变
assert list2.class == LinkedList

def 我以后会讲,你暂时需要知道的就是,你虽然用的是def,但是其实编译器知道numList 是List,是的,包含泛型,在@CompileStatic或@TypeChecked的模式下,意味着numList .add('3')会出错

4 友好的操作符重载

现在先给你一个java的惊喜

Integer a = 1;
System.out.println(a == 1);//true无疑
BigDecimal b1 = new BigDecimal(1);
BigDecimal b2 = new BigDecimal(1);
b2.setScale(1);
System.out.println(b1 == b2);//竟然是false,好吧,这是对象引用的比较
System.out.println(b1.equals(b2));//是true
System.out.println(b1.compareTo(b2));//或许你需要用这个

换成groovy

BigDecimal a = 1
BigDecimal b = a + 1 - 1
b = b + 2 //还可以这样写
assert a == b//==被映射为equals
//用原来的== 可以用 .is
assert !(a.is(b))
int i = 1
if (i) {//其实(i)也是运算符重载,此时会调用i的asBoolean()方法,因为groovy会autobox基本类型
println('我会被执行,因为i==1,数字除了0都是true')
}

更多的重载运算符 重载运算符

5 去掉冗余的老旧的getter setter

groovy提出了新的概念properties,不是java的filed

class Pro {
Integer property1 //1 没用private public protected(gorrvy里面是 @PackageScope)
def property2 //2 可选的statoc final(有final就会没有set) 之类的
final String property3 //3 def 或者 确定的类型
static String property4 //4 property名字
//满足以上四个条件就是一个property //实际上等于java以下内容,一个private+getter+setter(final修饰的没有setter)
private String property5 String getProperty5() {
return property5
} void setProperty5(String property5) {
this.property5 = property5
}
}

groovy提出了property的概念,而且其实现也好java兼容,但是码量明显减少,其'.'的语法是GPath,会自动调用get

static void main(String[] args) {
def pro = new Pro()
Pro pro1 = [:]//也可以这样声明,前提是必须指定类型,并且有默认的构造器,以下等价
Pro pro2 = []//等价以上
Pro pro3 = [property1: 123]//等价以上
def pro4 = [property1: 123] as Pro//等价以上
pro.property1 = 123 //类似pro.setProperty1(123)
println(pro.property1)//类似pro.getProperty1()
}

6 动态语言的舒适,静态语言的性能

groovy 1的是时候,有人诟病性能不佳,但是groovy 2开始,提供了@TypeChecked注解,静态检查,有时需要其他的注解来支持,@CompileStatic,静态检查+静态编译,此时会失去groovy的动态特性,而且此时的grrovy几乎能实现和java 100%的互掉(不只是groovy 调用java,java 调用groovy 也一样)

作为静态语言的喜爱者,明显是不用def,虽然groovy是可选的类型.官方的文档也说到,现在动态也很快了,甚至有些时候比静态都快,但是我不太信,我没看到数据的对比.使用groovy,你可以用现代的语法,和类似动态语言的便利,写出和静态语言几乎一样的性能

@CompileStatic//开启静态编译
class CompileStaticDemo {
static void main(String[] args) {
String s = '123'//虽然你用def,编译器也知道s是String,但是这不利于代码的阅读,所以还是老老实实的用明确的类型
assert s.length() == 3
Closure square = {
int x ->
return x * x
}
assert 9 == square(3)
Pro pro = []
assert pro.property1 == null
//这点就是完全有静态语言的写法,而且编译成静态的代码
}
}

7 丰富的内置支持,例如json

实际上groovy还是造了很多轮子的,比如groovy的模板,groovy版的jsp,交gsp,groovy内置的xml支持等等,这些轮子无疑会增加成本,但是很多我们可以不用,忽略即可

不过这个内置json,还是要提一下,这个内置json是整合的boon json,很早的一个评测,2013年的,boon json和其它框架的benchmark 那时候boon json的性能竟然大部分情况好于jackson

不管怎么说,java从5支持正则,没有以前,java用正则要用jakarta 的正则包,你用groovy了以后,现在就可以用内置的json支持,还是很便利的

@CompileStatic
class JsonDemo {
static void main(String[] args) {
Pro pro = []
pro.property1 = 123
pro.property2 = 'property2'
pro.property5 = '555'
def json = JsonOutput.toJson(pro)
println(json)//{
"property5":"555","property2":"property2","property4":null,"property1":123,"property3":null
}
//null 值没有忽略,groovy 2.5 中会添加支持,不断完善中
}
}

我的实践

groovy是一个动态语言,但是2.0以后,可以作为静态语言来用,我觉得grrovy的动态特性可能主要是用来支持groovy DSL的,对于服务端的程序来说,我认为没必要用它动态的特性.

但是每一个类都加@CompileStatic实在太麻烦,不过groovy提供了一个特性.自定义CompilerConfiguration ,你写一个脚本

package conf
//换行
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}

然后用下面的编译,就好了

groovyc -configscript src/conf/config.groovy src/main/groovy/MyClass.groovy

当然我们的项目没那么简单,你用idea的话,可以配置这个Config script flag,用gradle的话,虽然我没试过,但是我觉得也有类似的配置吧,所以你可以放心的用groovy的CompileStatic

用它代替java没问题

1. 稳定的支持,发展好

groovy比起java,糖多,写起来舒服,但是一个企业用的技术,必须是LTS,5年甚至10年都要有技术支持,这点grrovy能行吗,实际上groovy 2.0以后,越来越好了,现在已经就入了apache,即使加入apache之前,也获得过商业公司Pivotal软件的支持,2015年3月,groovy加入的apache

这是tiobe的走势 tiobe中groovy的走势 也可以说明groovy的流行程度越来越高 tiobe groovy走势

2. 没有什么不可忍受的缺点

语法没什么蹩脚的地方,这点和kotlin比比

val a: Int = 1  // immediate assignment
val b = 2 // `Int` type is inferred
val c: Int // Type required when no initializer is provided
c = 3 // deferred assignment

我只想说,为啥不 int a =1 ,即使你能类型自动推测var a =1 也不利于阅读,而且冒号也没有空格好敲,不过,这个可以忍,

如果写成下面这段代码就更有意思了

好多var

你看到一大堆var的时候有何感想

3. 完全可以静态检查编译

虽然它是动态类型,但是完全当静态用没问题,这点既保障了性能,也保证了代码质量,上面已经提过了.当然用不用groovy,这个取决与你是否喜欢它,认为他比java好,写起来更舒服

4. groovy即java,不缺轮子

java的生态groovy完全可以无缝继承,而且静态编译的groovy几乎也可以被java 100%互掉,所以轮子都是现成的,完全不缺

5. "0成本"的学习曲线

比起scala之流,groovy和java的相似度还是很大的,学习起来比较easy的,基本上基础学几下,用起来就没什么问题了,不过你还是需要一段时间来适应

Groovy系列-groovy比起Java--有哪些地方写起来更舒服?的更多相关文章

  1. java1234教程系列笔记 S1 Java SE chapter 02 写乘法口诀表

    一.水仙花数 1.方式一:这是我的思路,取各个位数的方式.我个人习惯于使用取模运算. public static List<Integer> dealNarcissiticNumberMe ...

  2. Groovy系列(2)- Groovy与Java的不同之处

    Groovy与Java的不同之处 默认 imports 所有这些包和类都是默认导入的,不必使用显式import语句来使用它们 java.io.* java.lang.* java.math.BigDe ...

  3. Groovy系列(1)- Groovy简述

    Groovy简述 前言 由于性能测试的JSR223 Sampler取样器需要用到 Groovy 语言,这两天对其进行了粗略的学习,本文是对学习做的一个简单总结,主要内容参考于官方文档(Groovy 的 ...

  4. Java系列笔记(3) - Java 内存区域和GC机制

    目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection, ...

  5. 【JAVA编码专题】 JAVA字符编码系列三:Java应用中的编码问题

    这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...

  6. 【转载】Java系列笔记(3) - Java 内存区域和GC机制

    Java系列笔记(3) - Java 内存区域和GC机制 转载:原文地址http://www.cnblogs.com/zhguang/p/3257367.html 目录 Java垃圾回收概况 Java ...

  7. 使用Groovy+Spock轻松写出更简洁的单测

    当无法避免做一件事时,那就让它变得更简单. 概述 单测是规范的软件开发流程中的必不可少的环节之一.再伟大的程序员也难以避免自己不犯错,不写出有BUG的程序.单测就是用来检测BUG的.Java阵营中,J ...

  8. Java系列笔记(2) - Java RTTI和反射机制

    目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...

  9. JAVA反射系列之Field,java.lang.reflect.Field使用获取方法

    JAVA反射系列之Field,java.lang.reflect.Field使用获取方法.   转载https://my.oschina.net/u/1407116/blog/209383 摘要 ja ...

随机推荐

  1. java-SimpleDateFormatDemo & BirthDemo

    java日期格式设置,以及案例BirthDemo package com.example; import java.text.ParseException; import java.text.Simp ...

  2. Spring Boot全日志设置

    说在前面 这里日志分两种.一种是tomcat的输出(系统)日志,一种是自己定义的日志. 系统日志设置 目标 当springboot接收到请求时记录日志到文件中 实现 你只需要在你的绿叶applicat ...

  3. DataUml Design 教程7 - 数据库生成模型

    DataUml Design支持数据库生成模型,并支持外键关系,能够根据外键自动生成类与类之间的关系. 目前DataUML Design支持MS Server.MY SQL.Oracle和Access ...

  4. mysql命令 SHOW TABLE STATUS LIKE '%city%'; 查看表的状态可以查看表的创建时间

    show status like '%handler_read_key%'; #走索引的命令的数量. #查看存储引擎 mysql> show variables like '%engine%'; ...

  5. 四个 jQuery 方法:

    append() - 在被选元素的结尾插入内容 prepend() - 在被选元素的开头插入内容 after() - 在被选元素之后插入内容 before() - 在被选元素之前插入内容

  6. css3的线性渐变效果

    1.代码: <!doctype html> <html lang="en"> <head> <meta charset="UTF ...

  7. poj 3683(2-sat+输出一组可行解)

    题目链接:http://poj.org/problem?id=3683 思路:对于每个结婚仪式,只有在开始或结束时进行这两种选择,我们可以定义xi为真当且仅当在开始时进行.于是我们可以通过时间先后确定 ...

  8. Java 基础巩固,根深而叶茂

    #J2SE ##基础 八种基本数据类型的大小,以及他们的封装类. 八种基本数据类型,int ,double ,long ,float, short,byte,character,boolean 对应的 ...

  9. ubuntu环境初始化

    0. 在Ubuntu系统中永久修改主机名也比较简单.主机名存放在/etc/hostname文件中,修改主机名时,编辑hostname文件,在文件中输入新的主机名并保存该文件即可 1.打开termini ...

  10. mysql编译参数详解(./configure)

    1.--prefix=PREFIX:指定程序安装路径: 2.--enable-assembler:使用汇编模式:(文档说明:compiling in x86 (and sparc) versions  ...