Movatterモバイル変換


[0]ホーム

URL:


Operators

version 4.0.27
Table of Contents

This chapter covers the operators of the Groovy programming language.

1. Arithmetic operators

Groovy supports the usual familiar arithmetic operators you find in mathematics and in other programming languages like Java.All the Java arithmetic operators are supported. Let’s go through them in the following examples.

1.1. Normal arithmetic operators

The following binary arithmetic operators are available in Groovy:

OperatorPurposeRemarks

+

addition

-

subtraction

*

multiplication

/

division

Useintdiv() for integer division, and see the section aboutinteger division for more information on the return type of the division.

%

remainder

**

power

See the section aboutthe power operation for more information on the return type of the operation.

Here are a few examples of usage of those operators:

assert  1  + 2 == 3assert  4  - 3 == 1assert  3  * 5 == 15assert  3  / 2 == 1.5assert 10  % 3 == 1assert  2 ** 3 == 8

1.2. Unary operators

The+ and- operators are also available as unary operators:

assert +3 == 3assert -4 == 0 - 4assert -(-1) == 1(1)
1Note the usage of parentheses to surround an expression to apply the unary minus to that surrounded expression.

In terms of unary arithmetics operators, the++ (increment) and-- (decrement) operators are available,both in prefix and postfix notation:

def a = 2def b = a++ * 3(1)assert a == 3 && b == 6def c = 3def d = c-- * 2(2)assert c == 2 && d == 6def e = 1def f = ++e + 3(3)assert e == 2 && f == 5def g = 4def h = --g + 1(4)assert g == 3 && h == 4
1The postfix increment will incrementa after the expression has been evaluated and assigned intob
2The postfix decrement will decrementc after the expression has been evaluated and assigned intod
3The prefix increment will incremente before the expression is evaluated and assigned intof
4The prefix decrement will decrementg before the expression is evaluated and assigned intoh

For the unary not operator on Booleans, seeConditional operators.

1.3. Assignment arithmetic operators

The binary arithmetic operators we have seen above are also available in an assignment form:

  • +=

  • -=

  • *=

  • /=

  • %=

  • **=

Let’s see them in action:

def a = 4a += 3assert a == 7def b = 5b -= 3assert b == 2def c = 5c *= 3assert c == 15def d = 10d /= 2assert d == 5def e = 10e %= 3assert e == 1def f = 3f **= 2assert f == 9

2. Relational operators

Relational operators allow comparisons between objects, to know if two objects are the same or different,or if one is greater than, less than, or equal to the other.

The following operators are available:

OperatorPurpose

==

equal

!=

different

<

less than

<=

less than or equal

>

greater than

>=

greater than or equal

===

identical (Since Groovy 3.0.0)

!==

not identical (Since Groovy 3.0.0)

Here are some examples of simple number comparisons using these operators:

assert 1 + 2 == 3assert 3 != 4assert -2 < 3assert 2 <= 2assert 3 <= 4assert 5 > 1assert 5 >= -2

Both=== and!== are supported which are the same as calling theis() method,and negating a call to theis() method respectively.

import groovy.transform.EqualsAndHashCode@EqualsAndHashCodeclass Creature { String type }def cat = new Creature(type: 'cat')def copyCat = catdef lion = new Creature(type: 'cat')assert cat.equals(lion) // Java logical equalityassert cat == lion      // Groovy shorthand operatorassert cat.is(copyCat)  // Groovy identityassert cat === copyCat  // operator shorthandassert cat !== lion     // negated operator shorthand

3. Logical operators

Groovy offers three logical operators for boolean expressions:

  • &&: logical "and"

  • ||: logical "or"

  • !: logical "not"

Let’s illustrate them with the following examples:

assert !false(1)assert true && true(2)assert true || false(3)
1"not" false is true
2true "and" true is true
3true "or" false is true

3.1. Precedence

The logical "not" has a higher priority than the logical "and".

assert (!false && false) == false(1)
1Here, the assertion is true (as the expression in parentheses is false), because "not" has a higher precedence than "and", so it only applies to the first "false" term; otherwise, it would have applied to the result of the "and", turned it into true, and the assertion would have failed

The logical "and" has a higher priority than the logical "or".

assert true || true && false(1)
1Here, the assertion is true, because "and" has a higher precedence than "or", therefore the "or" is executed last and returns true, having one true argument; otherwise, the "and" would have executed last and returned false, having one false argument, and the assertion would have failed

3.2. Short-circuiting

The logical|| operator supports short-circuiting: if the left operand is true, it knows that the result will be true in any case, so it won’t evaluate the right operand.The right operand will be evaluated only if the left operand is false.

Likewise for the logical&& operator: if the left operand is false, it knows that the result will be false in any case, so it won’t evaluate the right operand.The right operand will be evaluated only if the left operand is true.

boolean checkIfCalled() {(1)    called = true}called = falsetrue || checkIfCalled()assert !called(2)called = falsefalse || checkIfCalled()assert called(3)called = falsefalse && checkIfCalled()assert !called(4)called = falsetrue && checkIfCalled()assert called(5)
1We create a function that sets thecalled flag to true whenever it’s called
2In the first case, after resetting the called flag, we confirm that if the left operand to|| is true, the function is not called, as|| short-circuits the evaluation of the right operand
3In the second case, the left operand is false and so the function is called, as indicated by the fact our flag is now true
4Likewise for&&, we confirm that the function is not called with a false left operand
5But the function is called with a true left operand

4. Bitwise and bit shift operators

4.1. Bitwise operators

Groovy offers four bitwise operators:

  • &: bitwise "and"

  • |: bitwise "or"

  • ^: bitwise "xor" (exclusive "or")

  • ~: bitwise negation

Bitwise operators can be applied on arguments which are of typebyte,short,int,long, orBigInteger.If one of the arguments is aBigInteger, the result will be of typeBigInteger;otherwise, if one of the arguments is along, the result will be of typelong;otherwise, the result will be of typeint:

int a = 0b00101010assert a == 42int b = 0b00001000assert b == 8assert (a & a) == a(1)assert (a & b) == b(2)assert (a | a) == a(3)assert (a | b) == a(4)int mask = 0b11111111(5)assert ((a ^ a) & mask) == 0b00000000(6)assert ((a ^ b) & mask) == 0b00100010(7)assert ((~a) & mask)    == 0b11010101(8)
1bitwise and
2bitwise and returns common bits
3bitwise or
4bitwise or returns all '1' bits
5setting a mask to check only the last 8 bits
6bitwise exclusive or on self returns 0
7bitwise exclusive or
8bitwise negation

It’s worth noting that the internal representation of primitive types follow theJava Language Specification. In particular,primitive types are signed, meaning that for a bitwise negation, it is always good to use a mask to retrieve only the necessary bits.

In Groovy, bitwise operators areoverloadable, meaning that you can define the behavior of those operators for any kind of object.

4.2. Bit shift operators

Groovy offers three bit shift operators:

  • <<: left shift

  • >>: right shift

  • >>>: right shift unsigned

All three operators are applicable where the left argument is of typebyte,short,int, orlong.The first two operators can also be applied where the left argument is of typeBigInteger.If the left argument is aBigInteger, the result will be of typeBigInteger;otherwise, if the left argument is along, the result will be of typelong;otherwise, the result will be of typeint:

assert 12.equals(3 << 2)(1)assert 24L.equals(3L << 3)(1)assert 48G.equals(3G << 4)(1)assert 4095 == -200 >>> 20assert -1 == -200 >> 20assert 2G == 5G >> 1assert -3G == -5G >> 1
1equals method used instead of== to confirm result type

In Groovy, bit shift operators areoverloadable, meaning that you can define the behavior of those operators for any kind of object.

5. Conditional operators

5.1. Not operator

The "not" operator is represented with an exclamation mark (!) and inverts the result of the underlying boolean expression. Inparticular, it is possible to combine thenot operator with theGroovy truth:

assert (!true)    == false(1)assert (!'foo')   == false(2)assert (!'')      == true(3)
1the negation oftrue isfalse
2'foo' is a non-empty string, evaluating totrue, so negation returnsfalse
3'' is an empty string, evaluating tofalse, so negation returnstrue

5.2. Ternary operator

The ternary operator is a shortcut expression that is equivalent to an if/else branch assigning some value to a variable.

Instead of:

if (string!=null && string.length()>0) {    result = 'Found'} else {    result = 'Not found'}

You can write:

result = (string!=null && string.length()>0) ? 'Found' : 'Not found'

The ternary operator is also compatible with theGroovy truth, so you can make it even simpler:

result = string ? 'Found' : 'Not found'

5.3. Elvis operator

The "Elvis operator" is a shortening of the ternary operator. One instance of where this is handy is for returninga 'sensible default' value if an expression resolves tofalse-ish (as inGroovy truth). A simple example might look like this:

displayName = user.name ? user.name : 'Anonymous'(1)displayName = user.name ?: 'Anonymous'(2)
1with the ternary operator, you have to repeat the value you want to assign
2with the Elvis operator, the value, which is tested, is used if it is notfalse-ish

Usage of the Elvis operator reduces the verbosity of your code and reduces the risks of errors in case of refactorings,by removing the need to duplicate the expression which is tested in both the condition and the positive return value.

5.4. Elvis assignment operator

Groovy 3.0.0 introduces the Elvis operator, for example:

import groovy.transform.ToString@ToString(includePackage = false)class Element {    String name    int atomicNumber}def he = new Element(name: 'Helium')he.with {    name = name ?: 'Hydrogen'   // existing Elvis operator    atomicNumber ?= 2           // new Elvis assignment shorthand}assert he.toString() == 'Element(Helium, 2)'

6. Object operators

6.1. Safe navigation operator

The Safe Navigation operator is used to avoid aNullPointerException. Typically when you have a reference to an objectyou might need to verify that it is notnull before accessing methods or properties of the object. To avoid this, the safenavigation operator will simply returnnull instead of throwing an exception, like so:

def person = Person.find { it.id == 123 }(1)def name = person?.name(2)assert name == null(3)
1find will return anull instance
2use of the null-safe operator prevents from aNullPointerException
3result isnull

6.2. Direct field access operator

Normally in Groovy, when you write code like this:

class User {    public final String name(1)    User(String name) { this.name = name}    String getName() { "Name: $name" }(2)}def user = new User('Bob')assert user.name == 'Name: Bob'(3)
1public fieldname
2a getter forname that returns a custom string
3calls the getter

Theuser.name call triggers a call to the property of the same name, that is to say, here, to the getter forname. Ifyou want to retrieve the field instead of calling the getter, you can use the direct field access operator:

assert user.@name == 'Bob'(1)
1use of.@ forces usage of the field instead of the getter

6.3. Method pointer operator

The method pointer operator (.&) can be used to store a reference to a method in a variable,in order to call it later:

def str = 'example of method reference'(1)def fun = str.&toUpperCase(2)def upper = fun()(3)assert upper == str.toUpperCase()(4)
1thestr variable contains aString
2we store a reference to thetoUpperCase method on thestr instance inside a variable namedfun
3fun can be called like a regular method
4we can check that the result is the same as if we had called it directly onstr

There are multiple advantages in using method pointers. First of all, the type of such a method pointer isagroovy.lang.Closure, so it can be used in any place a closure would be used. In particular, it is suitable toconvert an existing method for the needs of the strategy pattern:

def transform(List elements, Closure action) {(1)    def result = []    elements.each {        result << action(it)    }    result}String describe(Person p) {(2)    "$p.name is $p.age"}def action = this.&describe(3)def list = [    new Person(name: 'Bob',   age: 42),    new Person(name: 'Julia', age: 35)](4)assert transform(list, action) == ['Bob is 42', 'Julia is 35'](5)
1thetransform method takes each element of the list and calls theaction closure on them, returning a new list
2we define a function that takes aPerson and returns aString
3we create a method pointer on that function
4we create the list of elements we want to collect the descriptors
5the method pointer can be used where aClosure was expected

Method pointers are bound by the receiver and a method name. Arguments are resolved at runtime, meaning that if you havemultiple methods with the same name, the syntax is not different, only resolution of the appropriate method to be calledwill be done at runtime:

def doSomething(String str) { str.toUpperCase() }(1)def doSomething(Integer x) { 2*x }(2)def reference = this.&doSomething(3)assert reference('foo') == 'FOO'(4)assert reference(123)   == 246(5)
1define an overloadeddoSomething method accepting aString as an argument
2define an overloadeddoSomething method accepting anInteger as an argument
3create a single method pointer ondoSomething, without specifying argument types
4using the method pointer with aString calls theString version ofdoSomething
5using the method pointer with anInteger calls theInteger version ofdoSomething

To align with Java 8 method reference expectations, in Groovy 3 and above, you can usenew as themethod name to obtain a method pointer to the constructor:

def foo  = BigInteger.&newdef fortyTwo = foo('42')assert fortyTwo == 42G

Also in Groovy 3 and above, you can obtain a method pointer to an instance method of a class.This method pointer takes an additional parameter being the receiver instance toinvoke the method on:

def instanceMethod = String.&toUpperCaseassert instanceMethod('foo') == 'FOO'

For backwards compatibility, any static methods that happen to have the correctparameters for the call will be given precedence over instance methods for this case.

6.4. Method reference operator

The Parrot parser in Groovy 3+ supports the Java 8+ method reference operator.The method reference operator (::) can be used to reference a method or constructorin contexts expecting a functional interface. This overlaps somewhat with the functionalityprovided by Groovy’s method pointer operator. Indeed, for dynamic Groovy, the methodreference operator is just an alias for the method pointer operator.For static Groovy, the operator results in bytecode similar to the bytecodethat Java would produce for the same context.

Some examples highlighting various supported method reference cases are shown in the following script:

import groovy.transform.CompileStaticimport static java.util.stream.Collectors.toList@CompileStaticvoid methodRefs() {    assert 6G == [1G, 2G, 3G].stream().reduce(0G, BigInteger::add)(1)    assert [4G, 5G, 6G] == [1G, 2G, 3G].stream().map(3G::add).collect(toList())(2)    assert [1G, 2G, 3G] == [1L, 2L, 3L].stream().map(BigInteger::valueOf).collect(toList())(3)    assert [1G, 2G, 3G] == [1L, 2L, 3L].stream().map(3G::valueOf).collect(toList())(4)}methodRefs()
1class instance method reference: add(BigInteger val) is an instance method in BigInteger
2object instance method reference: add(BigInteger val) is an instance method for object 3G
3class static method reference: valueOf(long val) is a static method for class BigInteger
4object static method reference: valueOf(long val) is a static method for object 3G (some consider this bad style in normal circumstances)

Some examples highlighting various supported constructor reference cases are shown in the following script:

@CompileStaticvoid constructorRefs() {    assert [1, 2, 3] == ['1', '2', '3'].stream().map(Integer::valueOf).collect(toList())(1)    def result = [1, 2, 3].stream().toArray(Integer[]::new)(2)    assert result instanceof Integer[]    assert result.toString() == '[1, 2, 3]'}constructorRefs()
1class constructor reference
2array constructor reference

7. Regular expression operators

7.1. Pattern operator

The pattern operator (~) provides a simple way to create ajava.util.regex.Pattern instance:

def p = ~/foo/assert p instanceof Pattern

while in general, you find the pattern operator with an expression in a slashy-string, it can be used with any kind ofString in Groovy:

p = ~'foo'(1)p = ~"foo"(2)p = ~$/dollar/slashy $ string/$(3)p = ~"${pattern}"(4)
1using single quote strings
2using double quotes strings
3the dollar-slashy string lets you use slashes and the dollar sign without having to escape them
4you can also use a GString!
While you can use most String forms with the Pattern, Find and Match operators,we recommend using the slashy string most of the time to save having toremember the otherwise needed escaping requirements.

7.2. Find operator

Alternatively to building a pattern, you can use the find operator=~ to directly create ajava.util.regex.Matcher instance:

def text = "some text to match"def m = text =~ /match/(1)assert m instanceof Matcher(2)if (!m) {(3)    throw new RuntimeException("Oops, text not found!")}
1=~ creates a matcher against thetext variable, using the pattern on the right hand side
2the return type of=~ is aMatcher
3equivalent to callingif (!m.find(0))

Since aMatcher coerces to aboolean by calling itsfind method, the=~ operator is consistent with the simpleuse of Perl’s=~ operator, when it appears as a predicate (inif,?:, etc.). When the intent is to iterate overmatches of the specified pattern (inwhile, etc.) callfind() directly on the matcher or use theiterator DGM.

7.3. Match operator

The match operator (==~) is a slight variation of the find operator, that does not return aMatcher but a booleanand requires a strict match of the input string:

m = text ==~ /match/(1)assert m instanceof Boolean(2)if (m) {(3)    throw new RuntimeException("Should not reach that point!")}
1==~ matches the subject with the regular expression, but match must be strict
2the return type of==~ is therefore aboolean
3equivalent to callingif (text ==~ /match/)

7.4. Comparing Find vs Match operators

Typically, the match operator is used when the pattern involves a single exact match, otherwisethe find operator might be more useful.

assert 'two words' ==~ /\S+\s+\S+/assert 'two words' ==~ /^\S+\s+\S+$/(1)assert !(' leading space' ==~ /\S+\s+\S+/)(2)def m1 = 'two words' =~ /^\S+\s+\S+$/assert m1.size() == 1(3)def m2 = 'now three words' =~ /^\S+\s+\S+$/(4)assert m2.size() == 0(5)def m3 = 'now three words' =~ /\S+\s+\S+/assert m3.size() == 1(6)assert m3[0] == 'now three'def m4 = ' leading space' =~ /\S+\s+\S+/assert m4.size() == 1(7)assert m4[0] == 'leading space'def m5 = 'and with four words' =~ /\S+\s+\S+/assert m5.size() == 2(8)assert m5[0] == 'and with'assert m5[1] == 'four words'
1equivalent, but explicit ^ and $ are discouraged since they aren’t needed
2no match because of leading space
3one match
4^ and $ indicate exact match required
5zero matches
6one match, greedily starting at first word
7one match, ignores leading space
8two matches

8. Other operators

8.1. Spread operator

The Spread-dot Operator (*.), often abbreviated to just Spread Operator, is used to invoke an action on all itemsof an aggregate object. It is equivalent to calling the action on each item and collecting the result into a list:

class Car {    String make    String model}def cars = [       new Car(make: 'Peugeot', model: '508'),       new Car(make: 'Renault', model: 'Clio')](1)def makes = cars*.make(2)assert makes == ['Peugeot', 'Renault'](3)
1build a list ofCar items. The list is an aggregate of objects.
2call the spread operator on the list, accessing themake property of each item
3returns a list of strings corresponding to the collection ofmake items

The expressioncars*.make is equivalent tocars.collect{ it.make }.Groovy’s GPath notation allows a short-cut when the referenced propertyisn’t a property of the containing list, in that case it is automaticallyspread. In the previously mentioned case, the expressioncars.make canbe used, though retaining the explicit spread-dot operator is often recommended.

The spread operator is null-safe, meaning that if an element of the collection is null,it will return null instead of throwing aNullPointerException:

cars = [   new Car(make: 'Peugeot', model: '508'),   null,(1)   new Car(make: 'Renault', model: 'Clio')]assert cars*.make == ['Peugeot', null, 'Renault'](2)assert null*.make == null(3)
1build a list for which one of the elements isnull
2using the spread operator willnot throw aNullPointerException
3the receiver might also be null, in which case the return value isnull

The spread operator can be used on any class which implements theIterable interface:

class Component {    Integer id    String name}class CompositeObject implements Iterable<Component> {    def components = [        new Component(id: 1, name: 'Foo'),        new Component(id: 2, name: 'Bar')]    @Override    Iterator<Component> iterator() {        components.iterator()    }}def composite = new CompositeObject()assert composite*.id == [1,2]assert composite*.name == ['Foo','Bar']

Use multiple invocations of the spread-dot operator (herecars*.models*.name) whenworking with aggregates of data structures which themselves contain aggregates:

class Make {    String name    List<Model> models}@Canonicalclass Model {    String name}def cars = [    new Make(name: 'Peugeot',             models: [new Model('408'), new Model('508')]),    new Make(name: 'Renault',             models: [new Model('Clio'), new Model('Captur')])]def makes = cars*.nameassert makes == ['Peugeot', 'Renault']def models = cars*.models*.nameassert models == [['408', '508'], ['Clio', 'Captur']]assert models.sum() == ['408', '508', 'Clio', 'Captur'] // flatten one levelassert models.flatten() == ['408', '508', 'Clio', 'Captur'] // flatten all levels (one in this case)

Consider using thecollectNested DGM method instead of the spread-dot operator for collections of collections:

class Car {    String make    String model}def cars = [   [       new Car(make: 'Peugeot', model: '408'),       new Car(make: 'Peugeot', model: '508')   ], [       new Car(make: 'Renault', model: 'Clio'),       new Car(make: 'Renault', model: 'Captur')   ]]def models = cars.collectNested{ it.model }assert models == [['408', '508'], ['Clio', 'Captur']]

8.1.1. Spreading method arguments

There may be situations when the arguments of a method call can be found in a list that you need to adapt to the methodarguments. In such situations, you can use the spread operator to call the method. For example, imagine you have thefollowing method signature:

int function(int x, int y, int z) {    x*y+z}

then if you have the following list:

def args = [4,5,6]

you can call the method without having to define intermediate variables:

assert function(*args) == 26

It is even possible to mix normal arguments with spread ones:

args = [4]assert function(*args,5,6) == 26

8.1.2. Spread list elements

When used inside a list literal, the spread operator acts as if the spread element contents were inlined into the list:

def items = [4,5](1)def list = [1,2,3,*items,6](2)assert list == [1,2,3,4,5,6](3)
1items is a list
2we want to insert the contents of theitems list directly intolist without having to calladdAll
3the contents ofitems has been inlined intolist

8.1.3. Spread map elements

The spread map operator works in a similar manner as the spread list operator, but for maps. It allows you to inlinethe contents of a map into another map literal, like in the following example:

def m1 = [c:3, d:4](1)def map = [a:1, b:2, *:m1](2)assert map == [a:1, b:2, c:3, d:4](3)
1m1 is the map that we want to inline
2we use the*:m1 notation to spread the contents ofm1 intomap
3map contains all the elements ofm1

The position of the spread map operator is relevant, like illustrated in the following example:

def m1 = [c:3, d:4](1)def map = [a:1, b:2, *:m1, d: 8](2)assert map == [a:1, b:2, c:3, d:8](3)
1m1 is the map that we want to inline
2we use the*:m1 notation to spread the contents ofm1 intomap, but redefine the keydafter spreading
3map contains all the expected keys, butd was redefined

8.2. Range operator

Groovy supports the concept of ranges and provides a notation (..) to create ranges of objects:

def range = 0..5(1)assert (0..5).collect() == [0, 1, 2, 3, 4, 5](2)assert (0..<5).collect() == [0, 1, 2, 3, 4](3)assert (0<..5).collect() == [1, 2, 3, 4, 5](4)assert (0<..<5).collect() == [1, 2, 3, 4](5)assert (0..5) instanceof List(6)assert (0..5).size() == 6(7)
1a simple range of integers, stored into a local variable
2anIntRange, with inclusive bounds
3anIntRange, with exclusive upper bound
4anIntRange, with exclusive lower bound
5anIntRange, with exclusive lower and upper bounds
6agroovy.lang.Range implements theList interface
7meaning that you can call thesize method on it

Ranges implementation is lightweight, meaning that only the lower and upper bounds are stored. You can create a rangefrom anyComparable object that hasnext() andprevious() methods to determine the next / previous item in the range.For example, you can create a range of characters this way:

assert ('a'..'d').collect() == ['a','b','c','d']

8.3. Spaceship operator

The spaceship operator (<=>) delegates to thecompareTo method:

assert (1 <=> 1) == 0assert (1 <=> 2) == -1assert (2 <=> 1) == 1assert ('a' <=> 'z') == -1

8.4. Subscript operator

The subscript operator is a shorthand notation forgetAt orputAt, depending on whether you find it onthe left hand side or the right hand side of an assignment:

def list = [0,1,2,3,4]assert list[2] == 2(1)list[2] = 4(2)assert list[0..2] == [0,1,4](3)list[0..2] = [6,6,6](4)assert list == [6,6,6,3,4](5)
1[2] can be used instead ofgetAt(2)
2if on left hand side of an assignment, will callputAt
3getAt also supports ranges
4so doesputAt
5the list is mutated

The subscript operator, in combination with a custom implementation ofgetAt/putAt is a convenient way for destructuringobjects:

class User {    Long id    String name    def getAt(int i) {(1)        switch (i) {            case 0: return id            case 1: return name        }        throw new IllegalArgumentException("No such element $i")    }    void putAt(int i, def value) {(2)        switch (i) {            case 0: id = value; return            case 1: name = value; return        }        throw new IllegalArgumentException("No such element $i")    }}def user = new User(id: 1, name: 'Alex')(3)assert user[0] == 1(4)assert user[1] == 'Alex'(5)user[1] = 'Bob'(6)assert user.name == 'Bob'(7)
1theUser class defines a customgetAt implementation
2theUser class defines a customputAt implementation
3create a sample user
4using the subscript operator with index 0 allows retrieving the user id
5using the subscript operator with index 1 allows retrieving the user name
6we can use the subscript operator to write to a property thanks to the delegation toputAt
7and check that it’s really the propertyname which was changed

8.5. Safe index operator

Groovy 3.0.0 introduces safe indexing operator, i.e.?[], which is similar to?.. For example:

String[] array = ['a', 'b']assert 'b' == array?[1]      // get using normal array indexarray?[1] = 'c'              // set using normal array indexassert 'c' == array?[1]array = nullassert null == array?[1]     // return null for all index valuesarray?[1] = 'c'              // quietly ignore attempt to set valueassert null == array?[1]def personInfo = [name: 'Daniel.Sun', location: 'Shanghai']assert 'Daniel.Sun' == personInfo?['name']      // get using normal map indexpersonInfo?['name'] = 'sunlan'                  // set using normal map indexassert 'sunlan' == personInfo?['name']personInfo = nullassert null == personInfo?['name']              // return null for all map valuespersonInfo?['name'] = 'sunlan'                  // quietly ignore attempt to set valueassert null == personInfo?['name']

8.6. Membership operator

The membership operator (in) is equivalent to calling theisCase method. In the context of aList, it is equivalentto callingcontains, like in the following example:

def list = ['Grace','Rob','Emmy']assert ('Emmy' in list)(1)assert ('Alex' !in list)(2)
1equivalent to callinglist.contains('Emmy') orlist.isCase('Emmy')
2membership negation equivalent to calling!list.contains('Emmy') or!list.isCase('Emmy')

8.7. Identity operator

In Groovy, using== to test equality is different from using the same operator in Java. In Groovy, it is callingequals.If you want to compare reference equality, you should useis like in the following example:

def list1 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3'](1)def list2 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3'](2)assert list1 == list2(3)assert !list1.is(list2)(4)assert list1 !== list2(5)
1Create a list of strings
2Create another list of strings containing the same elements
3using==, we test object equality, equivalent tolist1.equals(list2) in Java
4usingis, we can check that references are distinct, equivalent tolist1 == list2 in Java
5using=== or!== (supported and recommended since Groovy 3.0.0), we can also check whether references are distinct or not, equivalent tolist1 == list2 andlist1 != list2 in Java

8.8. Coercion operator

The coercion operator (as) is a variant of casting. Coercion converts object from one type to anotherwithout thembeing compatible for assignment. Let’s take an example:

String input = '42'Integer num = (Integer) input(1)
1String is not assignable to anInteger, so it will produce aClassCastException at runtime

This can be fixed by usingcoercion instead:

String input = '42'Integer num = input as Integer(1)
1String is not assignable to anInteger, but use ofas willcoerce it to anInteger

When an object is coerced into another, unless the target type is the same as the source type, coercion will return anew object. The rules of coercion differ depending on the source and target types, and coercion may fail if no conversionrules are found. Custom conversion rules may be implemented thanks to theasType method:

class Identifiable {    String name}class User {    Long id    String name    def asType(Class target) {(1)        if (target == Identifiable) {            return new Identifiable(name: name)        }        throw new ClassCastException("User cannot be coerced into $target")    }}def u = new User(name: 'Xavier')(2)def p = u as Identifiable(3)assert p instanceof Identifiable(4)assert !(p instanceof User)(5)
1theUser class defines a custom conversion rule fromUser toIdentifiable
2we create an instance ofUser
3we coerce theUser instance into anIdentifiable
4the target is an instance ofIdentifiable
5the target is not an instance ofUser anymore

8.9. Diamond operator

The diamond operator (<>) is a syntactic sugar only operator added to support compatibility with the operator of thesame name in Java 7. It is used to indicate that generic types should be inferred from the declaration:

List<String> strings = new LinkedList<>()

In dynamic Groovy, this is totally unused. In statically type checked Groovy, it is also optional since the Groovytype checker performs type inference whether this operator is present or not.

8.10. Call operator

The call operator() is used to call a method namedcall implicitly. For any object which defines acall method, you can omit the.call part and use the call operator instead:

class MyCallable {    int call(int x) {(1)        2*x    }}def mc = new MyCallable()assert mc.call(2) == 4(2)assert mc(2) == 4(3)
1MyCallable defines a method namedcall. Note that it doesn’t need to implementjava.util.concurrent.Callable
2we can call the method using the classic method call syntax
3or we can omit.call thanks to the call operator

9. Operator precedence

The table below lists all groovy operators in order of precedence.

LevelOperator(s)Name(s)

1

new  ()

object creation, explicit parentheses

()  {}  []

method call, closure, literal list/map

.  .&  .@

member access, method closure, field/attribute access

?.  *  *.  *:

safe dereferencing, spread, spread-dot, spread-map

~  !  (type)

bitwise negate/pattern, not, typecast

[]  ?[]  ++  --

list/map/array (safe) index, post inc/decrement

2

**

power

3

+` {nbsp} `--` {nbsp} `  -

pre inc/decrement, unary plus, unary minus

4

*  /  %

multiply, div, remainder

5

+  -

addition, subtraction

6

<<  >>  >>>  ..  ..<  <..<  <..

left/right (unsigned) shift, inclusive/exclusive ranges

7

<  <=  >  >=  in  !in  instanceof  !instanceof  as

less/greater than/or equal, in, not in, instanceof, not instanceof, type coercion

8

==  !=  <=>  ===  !==

equals, not equals, compare to, identical to, not identical to

=~  ==~

regex find, regex match

9

&

binary/bitwise and

10

^

binary/bitwise xor

11

|

binary/bitwise or

12

&&

logical and

13

||

logical or

14

? :

ternary conditional

?:

elvis operator

15

=  **=  *=  /=  %=  +=  -=  
<<=  >>=  >>>=  &=  ^=  |=    ?=

various assignments

10. Operator overloading

Groovy allows you to overload the various operators so that they can be used with your own classes. Consider this simpleclass:

class Bucket {    int size    Bucket(int size) { this.size = size }    Bucket plus(Bucket other) {(1)        return new Bucket(this.size + other.size)    }}
1Bucket implements a special method calledplus()

Just by implementing theplus() method, theBucket class can now be used with the+ operator like so:

def b1 = new Bucket(4)def b2 = new Bucket(11)assert (b1 + b2).size == 15(1)
1The twoBucket objects can be added together with the+ operator

All (non-comparator) Groovy operators have a corresponding method that you can implement in your own classes. The onlyrequirements are that your method is public, has the correct name, and has the correct number of arguments. The argumenttypes depend on what types you want to support on the right hand side of the operator. For example, you could supportthe statement

assert (b1 + 11).size == 15

by implementing theplus() method with this signature:

Bucket plus(int capacity) {    return new Bucket(this.size + capacity)}

Here is a complete list of the operators and their corresponding methods:

OperatorMethodOperatorMethod

+

a.plus(b)

a[b]

a.getAt(b)

-

a.minus(b)

a[b] = c

a.putAt(b, c)

*

a.multiply(b)

a in b

b.isCase(a)

/

a.div(b)

<<

a.leftShift(b)

%

a.mod(b)

>>

a.rightShift(b)

**

a.power(b)

>>>

a.rightShiftUnsigned(b)

|

a.or(b)

++

a.next()

&

a.and(b)

--

a.previous()

^

a.xor(b)

+a

a.positive()

as

a.asType(b)

-a

a.negative()

a()

a.call()

~a

a.bitwiseNegate()

Version 4.0.27
Last updated 2025-05-24 10:13:10 +1000

[8]ページ先頭

©2009-2025 Movatter.jp