| ////////////////////////////////////////// |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| |
| ////////////////////////////////////////// |
| |
| = Differences with Java |
| |
| Groovy tries to be as natural as possible for Java developers. We’ve |
| tried to follow the principle of least surprise when designing Groovy, |
| particularly for developers learning Groovy who’ve come from a Java |
| background. |
| |
| Here we list all the major differences between Java and Groovy. |
| |
| == Default imports |
| |
| All these packages and classes are imported by default, i.e. you do not |
| have to use an explicit `import` statement to use them: |
| |
| * java.io.* |
| * java.lang.* |
| * java.math.BigDecimal |
| * java.math.BigInteger |
| * java.net.* |
| * java.util.* |
| * groovy.lang.* |
| * groovy.util.* |
| |
| == Multi-methods |
| |
| In Groovy, the methods which will be invoked are chosen at runtime. This is called runtime dispatch or multi-methods. It |
| means that the method will be chosen based on the types of the arguments at runtime. In Java, this is the opposite: methods |
| are chosen at compile time, based on the declared types. |
| |
| The following code, written as Java code, can be compiled in both Java and Groovy, but it will behave differently: |
| |
| [source,java] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=multimethods,indent=0] |
| ---- |
| |
| In Java, you would have: |
| |
| [source,java] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=multimethods_java,indent=0] |
| ---- |
| |
| Whereas in Groovy: |
| |
| [source,java] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=multimethods_groovy,indent=0] |
| ---- |
| |
| That is because Java will use the static information type, which is that `o` is declared as an `Object`, whereas |
| Groovy will choose at runtime, when the method is actually called. Since it is called with a `String`, then the |
| `String` version is called. |
| |
| == Array initializers |
| |
| In Groovy, the `{ ... }` block is reserved for closures. That means that you cannot create array literals with this |
| syntax: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=arraycreate_fail,indent=0] |
| ---- |
| |
| You actually have to use: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=arraycreate_success,indent=0] |
| ---- |
| |
| == Package scope visibility |
| |
| In Groovy, omitting a modifier on a field doesn't result in a package-private field like in Java: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=packageprivate_property,indent=0] |
| ---- |
| |
| Instead, it is used to create a _property_, that is to say a _private field_, an associated _getter_ and an associated |
| _setter_. |
| |
| It is possible to create a package-private field by annotating it with `@PackageScope`: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=packageprivate_field,indent=0] |
| ---- |
| |
| == ARM blocks |
| |
| ARM (Automatic Resource Management) block from Java 7 are not supported in Groovy. Instead, Groovy provides various |
| methods relying on closures, which have the same effect while being more idiomatic. For example: |
| |
| [source,java] |
| ---- |
| 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(); |
| } |
| ---- |
| |
| can be written like this: |
| |
| [source,groovy] |
| ---- |
| new File('/path/to/file').eachLine('UTF-8') { |
| println it |
| } |
| ---- |
| |
| or, if you want a version closer to Java: |
| |
| [source,groovy] |
| ---- |
| new File('/path/to/file').withReader('UTF-8') { reader -> |
| reader.eachLine { |
| println it |
| } |
| } |
| ---- |
| |
| == Inner classes |
| |
| WARNING: The implementation of anonymous inner classes and nested classes follows the Java lead, but |
| you should not take out the Java Language Spec and keep shaking the head |
| about things that are different. The implementation done looks much like |
| what we do for `groovy.lang.Closure`, with some benefits and some |
| differences. Accessing private fields and methods for example can become |
| a problem, but on the other hand local variables don’t have to be final. |
| |
| === Static inner classes |
| |
| Here’s an example of static inner class: |
| |
| [source,groovy] |
| --------------------- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=innerclass_1,indent=0] |
| --------------------- |
| |
| The usage of static inner classes is the best supported one. If you |
| absolutely need an inner class, you should make it a static one. |
| |
| === Anonymous Inner Classes |
| |
| [source,groovy] |
| --------------------- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=innerclass_2,indent=0] |
| --------------------- |
| |
| === Creating Instances of Non-Static Inner Classes |
| |
| In Java you can do this: |
| |
| [source,java] |
| ---------------------------------- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=innerclass_3_java,indent=0] |
| ---------------------------------- |
| |
| Groovy doesn't support the `y.new X()` syntax. Instead, you have to write `new X(y)`, like in the code below: |
| |
| [source,groovy] |
| ---------------------------------- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=innerclass_3,indent=0] |
| ---------------------------------- |
| |
| [WARNING] |
| Caution though, Groovy supports calling methods with one |
| parameter without giving an argument. The parameter will then have the |
| value null. Basically the same rules apply to calling a constructor. |
| There is a danger that you will write new X() instead of new X(this) for |
| example. Since this might also be the regular way we have not yet found |
| a good way to prevent this problem. |
| |
| == Lambda expressions and the method reference operator |
| |
| Java 8+ supports lambda expressions and the method reference operator (`::`): |
| |
| [source,java] |
| ---- |
| Runnable run = () -> System.out.println("Run"); // Java |
| list.forEach(System.out::println); |
| ---- |
| |
| Groovy 3 and above also support these within the Parrot parser. |
| In earlier versions of Groovy you should use closures instead: |
| |
| [source,groovy] |
| ---- |
| Runnable run = { println 'run' } |
| list.each { println it } // or list.each(this.&println) |
| ---- |
| |
| |
| == GStrings |
| |
| As double-quoted string literals are interpreted as `GString` values, Groovy may fail |
| with compile error or produce subtly different code if a class with `String` literal |
| containing a dollar character is compiled with Groovy and Java compiler. |
| |
| While typically, Groovy will auto-cast between `GString` and `String` if an API declares |
| the type of a parameter, beware of Java APIs that accept an `Object` parameter and then |
| check the actual type. |
| |
| == String and Character literals |
| |
| Singly-quoted literals in Groovy are used for `String`, and double-quoted result in |
| `String` or `GString`, depending whether there is interpolation in the literal. |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=type_depends_on_quoting_AND_whether_we_actually_interpolate,indent=0] |
| ---- |
| |
| Groovy will automatically cast a single-character `String` to `char` only when assigning to |
| a variable of type `char`. When calling methods with arguments of type `char` we need |
| to either cast explicitly or make sure the value has been cast in advance. |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=single_char_strings_are_autocasted,indent=0] |
| ---- |
| |
| Groovy supports two styles of casting and in the case of casting to `char` there |
| are subtle differences when casting a multi-char strings. The Groovy style cast is |
| more lenient and will take the first character, while the C-style cast will fail |
| with exception. |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=chars_c_vs_groovy_cast,indent=0] |
| ---- |
| |
| == Primitives and wrappers |
| |
| Because Groovy uses Objects for everything, it link:core-object-orientation.html#_primitive_types[autowraps] references |
| to primitives. Because of this, it does not follow Java's behavior of widening taking priority over boxing. |
| Here's an example using `int` |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/PrimitiveTest.groovy[tags=widening_vs_boxing,indent=0] |
| ---- |
| <1> This is the method that Java would call, since widening has precedence over unboxing. |
| <2> This is the method Groovy actually calls, since all primitive references use their wrapper class. |
| |
| == Behaviour of `==` |
| |
| In Java `==` means equality of primitive types or identity for objects. In |
| Groovy `==` translates to `a.compareTo(b)==0`, if they are `Comparable`, and |
| `a.equals(b)` otherwise. To check for identity, there is `is`. E.g. |
| `a.is(b)`. |
| |
| == Conversions |
| |
| Java does automatic widening and narrowing |
| https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html[conversions]. |
| |
| [cols=">2s,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a"] |
| .Java Conversions |
| |============================================================================================ |
| | 8+|*Converts to* |
| | Converts from | *boolean* | *byte* | *short* | *char* | *int* | *long* | *float* | *double* |
| | boolean | - | N | N | N | N | N | N | N |
| | byte | N | - | Y | C | Y | Y | Y | Y |
| | short | N | C | - | C | Y | Y | Y | Y |
| | char | N | C | C | - | Y | Y | Y | Y |
| | int | N | C | C | C | - | Y | T | Y |
| | long | N | C | C | C | C | - | T | T |
| | float | N | C | C | C | C | C | - | Y |
| | double | N | C | C | C | C | C | C | - |
| |============================================================================================ |
| ^*^ 'Y' indicates a conversion Java can make, 'C' indicates a conversion Java can make when there is an explicit cast, |
| 'T` indicates a conversion Java can make but data is truncated, 'N' indicates a conversion Java can't make. |
| |
| Groovy expands greatly on this. |
| |
| [cols=">2s,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a,^1a"] |
| .Groovy Conversions |
| |================================================================================================================================================================================================================= |
| | 18+|*Converts to* |
| | Converts from | *boolean* | *Boolean* | *byte* | *Byte* | *short* | *Short* | *char* | *Character* | *int* | *Integer* | *long* | *Long* | *BigInteger* | *float* | *Float* | *double* | *Double* | *BigDecimal* |
| | boolean | - | B | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
| | Boolean | B | - | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
| | byte | T | T | - | B | Y | Y | Y | D | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
| | Byte | T | T | B | - | Y | Y | Y | D | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
| | short | T | T | D | D | - | B | Y | D | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
| | Short | T | T | D | T | B | - | Y | D | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
| | char | T | T | Y | D | Y | D | - | D | Y | D | Y | D | D | Y | D | Y | D | D |
| | Character | T | T | D | D | D | D | D | - | D | D | D | D | D | D | D | D | D | D |
| | int | T | T | D | D | D | D | Y | D | - | B | Y | Y | Y | Y | Y | Y | Y | Y |
| | Integer | T | T | D | D | D | D | Y | D | B | - | Y | Y | Y | Y | Y | Y | Y | Y |
| | long | T | T | D | D | D | D | Y | D | D | D | - | B | Y | T | T | T | T | Y |
| | Long | T | T | D | D | D | T | Y | D | D | T | B | - | Y | T | T | T | T | Y |
| | BigInteger | T | T | D | D | D | D | D | D | D | D | D | D | - | D | D | D | D | T |
| | float | T | T | D | D | D | D | T | D | D | D | D | D | D | - | B | Y | Y | Y |
| | Float | T | T | D | T | D | T | T | D | D | T | D | T | D | B | - | Y | Y | Y |
| | double | T | T | D | D | D | D | T | D | D | D | D | D | D | D | D | - | B | Y |
| | Double | T | T | D | T | D | T | T | D | D | T | D | T | D | D | T | B | - | Y |
| | BigDecimal | T | T | D | D | D | D | D | D | D | D | D | D | D | T | D | T | D | - |
| |================================================================================================================================================================================================================= |
| ^*^ 'Y' indicates a conversion Groovy can make, 'D' indicates a conversion Groovy can make when compiled dynamically or |
| explicitly cast, 'T` indicates a conversion Groovy can make but data is truncated, 'B' indicates a boxing/unboxing |
| operation, 'N' indicates a conversion Groovy can't make. |
| |
| The truncation uses <<core-semantics.adoc#Groovy-Truth,Groovy Truth>> when converting to `boolean`/`Boolean`. Converting |
| from a number to a character casts the `Number.intvalue()` to `char`. Groovy constructs `BigInteger` and `BigDecimal` |
| using `Number.doubleValue()` when converting from a `Float` or `Double`, otherwise it constructs using `toString()`. |
| Other conversions have their behavior defined by `java.lang.Number`. |
| |
| == Extra keywords |
| |
| There are a few more keywords in Groovy than in Java. Don't use them for |
| variable names etc. |
| |
| * `as` |
| * `def` |
| * `in` |
| * `trait` |