IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    《Groovy官方文档》1.3 Groovy和Java比较

    JackWang发表于 2015-09-24 14:46:49
    love 0

    原文地址     译文地址  译者:jackWang

    Groovy语言一直在努力亲近Java开发人员。在设计Groovy语言的时候,我们遵循最小标新立异原则,努力让那些Java开发背景的开发者容易上手并学会。下面我们列举Groovy和Java的一些主要区别。

    1 默认导入

    下面的包和类是默认导入的,也就是说不必精确使用 import 语句来导入它们:

    • java.io.*
    • java.lang.*
    • java.math.BigDecimal
    • java.math.BigInteger
    • java.net.*
    • java.util.*
    • groovy.lang.*
    • groovy.util.*

    2 动态方法(Multi-methods)

    在Groovy里,方法的调用是在运行时动态决定。这一特性叫做运行时分发(runtime dispatch)或动态方法(multi-methods)。也就是说方法的最后调用是根据传入参数在运行时的类型所决定。在Java里,这一点是不一样的:在编译时就决定了方法的参数类型。

    下面的代码,我们采用Java风格,在Groovy和Java都可以编译通过,但是运行结果不一样:

    int method(String arg) {
        return 1;
    }
    int method(Object arg) {
        return 2;
    }
    Object o = "Object";
    int result = method(o);

    在Java里,结果是

    assertEquals(2, result);

    但是Groovy里,结果是

    assertEquals(1, result);

    原因是Java使用的是静态声明的类型信息,这里o被声明为Object,但是Groovy是在运行时决定,当方法最终被调用时,因为这里o实际是一个字符串,因此最终String版本的方法被调用。

    译者注:译者之前也没有接触过Groovy语言,空闲时间也是有限的(姑且让我找这个借口吧,虽然这个借口很牵强,对待知识本来应该以一种严谨,求真的态度)因此这里有些专有名字可能翻译不是很准确,比如对Multi-methods的翻译。译者也不确定是否准确,因此附带了原文单词,请读者自行根据示例代码和上下文意思理解。如果找到准确的中文翻译恳请评论留言,以待修正。

    3 数组初始化

    在Groovy,{…}已经被用作闭包,也就是说你不能使用下面的语法创建数组(译者注:Java可以,并且很常用)

    int[] array = { 1, 2, 3}

    你应该这样声明并初始化一个数组

    int[] array = [1,2,3]

    4 包范围可见性(Package scope visibility)

    在Groovy里,省略字段的修饰符不会像Java一样使其成为包私有属性(package-private field)

    class Person {
        String name
    }

    这里,我们创建了一个属性,它是私有的,而且自动关联了getter和setter方法。如果我们要创建一个包私有属性,可以添加@PackageScope注解来实现:

    class Person {
        @PackageScope String name
    }

    5 ARM块

    ARM(Automatic Resource Management 自动资源管理)块从Java7开始支持,但是Groovy不支持。相应地,Groovy依赖于闭包来实现类似的功能。示例:

    Path file = Paths.get("/path/to/file");
    Charset charset = Charset.forName("UTF-8");
    try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    
    } catch (IOException e) {
        e.printStackTrace();
    }

    在Groovy里可以写成:

    new File('/path/to/file').eachLine('UTF-8') {
       println it
    }

    或者也可以写成跟Java类似风格:

    new File('/path/to/file').withReader('UTF-8') { reader ->
       reader.eachLine {
           println it
       }
    }

    6 内部类

    Groovy遵循了Java的匿名内部类以及嵌套内的特点。但是它并没有完全依照Java语言规范,因此在使用前应该记住它们是有区别的。Groovy的实现和groovy.lang.Clouser类的风格有些类似,但也有不同点。比如在访问私有字段和方法以及局部变量没有final等。

    6.1 静态内部类

    这是一个静态内部类的例子:

    class A {
        static class B {}
    }
    
    new A.B()

    使用静态内部类是一个非常好的实践,如果你一定要使用内部类,建议优先考虑静态内部类。

    6.2 匿名内部类

    import java.util.concurrent.CountDownLatch
    import java.util.concurrent.TimeUnit
    
    CountDownLatch called = new CountDownLatch(1)
    
    Timer timer = new Timer()
    timer.schedule(new TimerTask() {
        void run() {
            called.countDown()
        }
    }, 0)
    
    assert called.await(10, TimeUnit.SECONDS)

    6.3 创建非静态内部类实例

    在Java里,你可以这样写:

    public class Y {
        public class X {}
        public X foo() {
            return new X();
        }
        public static X createX(Y y) {
            return y.new X();
        }
    }

    Groovy不支持y.new X()语法,但你可以写成new X(y),像下面的代码:

    public class Y {
        public class X {}
        public X foo() {
            return new X()
        }
        public static X createX(Y y) {
            return new X(y)
        }
    }

    特别注意,Groovy支持调用无参方法传入一个参数。那个参数的值将会是null。这个特性对于调用构造函数同样适用。可能会有人写new X(this)而不是new X(),这是不合法的。虽然我们还没有找到办法避免用户这样写。

    7  拉姆达表达式

    Java 8 支持拉姆达表达式和方法引用

    Runnable run = () -> System.out.println("Run");
    list.forEach(System.out::println);

    Java8的拉姆达表达式或多或少被认为是匿名内部类。Groovy不支持这样的语法,但是可以使用闭包代替:

    Runnable run = { println 'run' }
    list.each { println it } // or list.each(this.&println)

    8  GStrings

    使用双引号修饰的字符串被解释为GString值。如果一个字符串里含有美元符号在Groovy和Java的编译器里将会产生编译错误。

    当然,Groovy会自动在GString和String之间进行类型转换,就像Java可以接受一个Object参数然后检查其实际类型一样。

    9  字符串和字符

    在Groovy里,使用单引号修饰的被当成String类型,使用双引号修饰的可以当成GString类型或String类型。取决于字面常量。

    assert 'c'.getClass()==String
    assert "c".getClass()==String
    assert "c${1}".getClass() in GString

    如果声明是char类型,Groovy会自动将单个字符从String类型转换为char类型。如果被调用的方法声明的参数类型是char,我们需要强制类型转换为char类型。

    char a='a'
    assert Character.digit(a, 16)==10 : 'But Groovy does boxing'
    assert Character.digit((char) 'a', 16)==10
    
    try {
      assert Character.digit('a', 16)==10
      assert false: 'Need explicit cast'
    } catch(MissingMethodException e) {
    }

    Groovy支持两种风格的类型转换,在转换成char类型的时候,当个字符和多个字符转换有些不一样。对于多个字符转换成char类型,Groovy会选择第一个字符,这一点不像C语言,会直接失败。

    // for single char strings, both are the same
    assert ((char) "c").class==Character
    assert ("c" as char).class==Character
    
    // for multi char strings they are not
    try {
      ((char) 'cx') == 'c'
      assert false: 'will fail - not castable'
    } catch(GroovyCastException e) {
    }
    assert ('cx' as char) == 'c'
    assert 'cx'.asType(char) == 'c'

    10 ==的行为

    在Java里,==意味着基本类型相等或对象类型相等。在Groovy里,==会转换成a.compareTo(b)==0,如果他们是Comparable,就是使用a.equals(b),否则检查基本类型,也就是is,比如a.is(b)

    11  不同的关键字

    Groovy比Java有更多的关键字,请不要把它们当变量名使用

    • in
    • trait

     

     

     

    原创文章,转载请注明: 转载自并发编程网 – ifeve.com

    本文链接地址: 《Groovy官方文档》1.3 Groovy和Java比较

    文章的脚注信息由WordPress的wp-posturl插件自动生成



沪ICP备19023445号-2号
友情链接