Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>We can restrict the types of values a variable may hold by specifying some restricting class instead of 'def':</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> import org.codehaus.groovy.runtime.typehandling.GroovyCastException def v= 3 //variable v can hold any value v= 'helicopter' v= false v= new StringBuffer() v= null int i= 15 //variable i can only hold integer values i= 'A' assert i == 65 //'A' casted to its integer value //unable to cast boolean value to integer try{ i= false; assert 0 }catch(e){ assert e in GroovyCastException } Closure c= {it * 3} //variable c can only hold Closures try{ c= false; assert 0 }catch(e){ assert e in GroovyCastException } //unable to cast boolean value to Closure StringBuffer s= new StringBuffer('morning') //variable s can only hold StringBuffers try{ s= { it * 5 }; assert 0 }catch(e){ assert e in GroovyCastException } //unable to cast Closure value to StringBuffer </pre></td></tr></table> <p>When we assign values not of a variable's type to the variable, sometimes it may be 'cast' to the type, other times an exception is thrown:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> import org.codehaus.groovy.runtime.typehandling.GroovyCastException int i i= 45L; assert i == 45i i= 45.1f; assert i == 45i try{ i= '42'; assert 0 }catch(e){assert e in GroovyCastException} try{ i= false; assert 0 }catch(e){assert e in GroovyCastException} //long similar to int byte by by= 200i; assert by == -56 //short similar to byte float f f= 123i; assert f == 123.0f try{ f= '42.1'; assert 0 }catch(e){assert e in GroovyCastException} //double similar to float BigInteger bi bi= 42L; assert bi == 42g try{ bi= '421'; assert 0 }catch(e){assert e in GroovyCastException} BigDecimal bd bd= 42.1f; assert bd == 42.1g try{ bd= '4.21'; assert 0 }catch(e){assert e in GroovyCastException} boolean b b= 0; assert ! b b= 1i; assert b b= 1g; assert b b= 1.1g; assert b b= 1.1f; assert b b= ''; assert ! b b= 'a'; assert b b= 'abc'; assert b b= null; assert ! b char c c= 'a'; assert c == ('a' as char) try{ c= 'abc'; assert 0 }catch(e){assert e in GroovyCastException} String s s= 42i; assert s == '42' s= 42L; assert s == '42' s= 42g; assert s == '42' s= 42.1g; assert s == '42.1' s= 42.100g; assert s == '42.100' s= 42.1f; assert s == '42.1' StringBuffer sb try{ sb= 'abc'; assert 0 }catch(e){ assert e in GroovyCastException } </pre></td></tr></table> <p>We can statically type Closure parameters. The casting is more restrictive than for assigning to variables:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> import org.codehaus.groovy.runtime.typehandling.GroovyCastException int i def toTriple= {int n -> n * 3} i= 5 assert toTriple(5) == 15 //a float is cast to an integer when assigning to a variable, but not when //passing as a parameter... i= 5.0f try{ toTriple(5.0f); assert 0 } catch(e){assert e.class in MissingMethodException} //a String can't cast to an integer, either when assigning to a variable or //passing as a parameter... try{ i= 'abc'; assert 0 } catch(e){assert e.class in GroovyCastException} try{ toTriple('abc'); assert 0 } catch(e){assert e.class in MissingMethodException} </pre></td></tr></table> <p>We can also statically type the variable-numbered parameters in a closure:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def c = { int[] args -> args.toList().inject(0){ flo, it-> flo + it } } assert c( 5 ) == 5 assert c( 4, 2, 3 ) == 9 try{ c( 2, 'abc' ); assert 0 }catch(e){ assert e in MissingMethodException } </pre></td></tr></table> <p>We can statically type function parameters:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def f(String s, int i){ ([s]*i).join(',') } assert f('abc', 3) == 'abc,abc,abc' def f(int n, int i){ "$n * $i" } //another function f defined with same //number of but different types of parameters assert f(4, 5) == '4 * 5' assert f('a', 5) == 'a,a,a,a,a' //correct function selected based on parameter types... try{ f(4, 'x'); assert 0 }catch(e){ assert e in MissingMethodException } //...or no method selected </pre></td></tr></table> <p>We can statically type the return type from a function. Casting a returned value of a different type follows the same rules as for assigning to variables:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> String f(){ 'abc' } assert f() == 'abc' int g(){ 2.4f } assert g() == 2i </pre></td></tr></table> <p>We can statically type method parameters just like we do with function parameters, including selecting a method based on its parameter types, for both static methods and instance methods:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> //static methods... class A{ static f(String s, int i){ ([s]*i).join(',') } static f(int n, int i){ "$n * $i" } //another method f defined with same //number of but different types of parameters } assert A.f('abc', 3) == 'abc,abc,abc' assert A.f(4, 5) == '4 * 5' assert A.f('a', 5) == 'a,a,a,a,a' //correct method selected based on parameter types... try{ A.f(4, 'x'); assert 0 }catch(e){ assert e in MissingMethodException } //...or no method selected //instance methods... class Counter{ def count = 0 def incr( String n ){ count += new Integer(n) } def incr( int n ){ count += n } } def c= new Counter(count: 5) c.incr(3) c.incr('4') try{ c.incr(2.5); assert 0 }catch(e){ assert e in MissingMethodException } assert c.count == 12 </pre></td></tr></table> <p>We can statically type the return type from a method, just as we can from a function, both static and instance methods:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class A{ static String f(){ 'abc' } static int g(){ 2.4f } byte h(){ 200i } } assert A.f() == 'abc' assert A.g() == 2i assert new A().h() == -56 </pre></td></tr></table> <p>Property getters and setters can accept and return any statically-typed value:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class Counter{ def count= 0 void setCount(int n){ count= n*2 } //set the value to twice what's supplied String getCount(){ 'count: '+ count } //return the value as a String with 'count: ' prepended } def c= new Counter() c.count= 23 assert c.count == 'count: 46' </pre></td></tr></table> <p>A list can be cast to a class using that class's constructor:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class A{ int x,y A(x,y){ this.x=x; this.y=y } //2-arg constructor String toString(){ "x: $x; y: $y" } } A a a= [1,2] //2-element list causes 2-arg constructor of A to be called assert a.class == A && a.toString() == 'x: 1; y: 2' </pre></td></tr></table> <h3>Statically-Typed Arrays</h3> <p>We can statically type an Object array variable:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> Object[] oa= new Object[2] assert oa.class in Object[] && oa.size() == 2 && oa[0,1] == [null, null] oa= 7 //if we assign another scalar value, it's wrapped into an array assert oa.class in Object[] && oa.size() == 1 && oa[0] == 7 oa= [3, 5] //if we assign another collection value, it's cast to an array assert oa.class in Object[] && oa.size() == 2 && oa[0,1] == [3, 5] def map= ['a':4, 'b':8, 'c':12] oa= map assert oa.class in Object[] && oa.size() == 3 //it's cast to an array of MapEntrys oa.each{ assert it.key in map.keySet() && it.value == map[it.key] } </pre></td></tr></table> <p>We can statically type a variable not only as an array, but as a certain type of array:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> int[] ia ia= 7.5 assert ia.class in int[] && ia.size() == 1 && ia[0] == 7i //assigned value above cast to an integer array try{ ia= ['abc', 'def']; assert 0 }catch(e){ assert e in ClassCastException } //can't cast Strings to Integers </pre></td></tr></table> <p>We can instead statically type each array element:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def a= new int[3] assert a[0] == 0 && a[1] == 0 && a[2] == 0 //default value is 0 a[0]= 7.5 assert a[0] == 7i //assigned value in above line was cast to an integer try{ a[1]= 'abc'; assert 0 }catch(e){ assert e in ClassCastException } //can't cast String to an Integer </pre></td></tr></table> <p>Statically typing both the variable and each element allows both array assignments and element assignments to be cast or disallowed:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> int[] ia= new int[3] ia[0]= 7.5 assert ia[0] == 7i ia= 7.5 assert ia.class in int[] && ia.size() == 1 && ia[0] == 7i </pre></td></tr></table> <p>A multidimensional array type casts its assigned value in various ways:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> //a scalar value is cascadingly wrapped by arrays... Object[][] ia ia= 7.5 assert ia in Object[][] && ia.size() == 1 && ia[0] in Object[] && ia[0].size() == 1 && ia[0][0] == 7.5 //a one-dimensional vector value is array-wrapped at the innermost level... ia= ['a', 'b', 'c'] assert ia in Object[][] && ia.size() == 3 && ia[0] in Object[] && ia[0].size() == 1 && ia[0][0] == 'a' && ia[1][0] == 'b' && ia[2][0] == 'c' </pre></td></tr></table> <h3>Interfaces</h3> <p>Groovy enables a construct known as an interface, which classes can implement. We can test for implemented interfaces with the 'in' operator:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class A{} //a standard class definition, though without any fields, //properties, or methods def a= new A() assert a in A interface X{} class B implements X{} //a class can implement an interface def b= new B() assert b in B && b in X //'in' tests for the class and for interfaces implemented assert ! (a in X) interface Y{} interface Z{} class C implements X, Y, Z{} //a class can implement more than one interface def c= new C() assert c in C && c in X && c in Y && c in Z </pre></td></tr></table> <p>Interfaces can contain method declarations. Each declared method must be defined in implementing classes:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> interface X{ String sayPies(int i) } class A implements X{ String sayPies(int n){ "There are $n pies!" } //sayPies(int) in X defined String sayBirds(int n){ "There are $n birds!" } } def a= new A() assert a.sayPies(24) == 'There are 24 pies!' //class B implements X{} //a compile error when uncommented: sayPies(int) must be implemented //these each give a compile error when uncommented... //class C implements X{ String sayPies(float n){ "$n" } } //wrong parameter type //class D implements X{ Object sayPies(int n){ "$n" } } //wrong return type </pre></td></tr></table> <p>An interface can also be composed of other interfaces, using the 'extends' keyword:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> interface X{ def x1(int i) def x2() } interface Y{ def x1(int i) def y() } interface Z extends X, Y{ } //it's OK if a method, here x1(int), is in more than one interface class A implements Z{ def x1(int i){ i } def x2(){ 2 } def y(){ 3 } } assert new A().x1( 1 ) == 1 </pre></td></tr></table> <p>We can implement an interface with map syntax:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> interface X{ int echo(int i) def sayTarts(int i) String sayPies(int i) } def a= [ echo: {n-> n}, sayTarts: {n-> "There are $n tarts!"}, sayPies: {n-> "There are $n pies!" as String}, //explicit cast from GString to String required here ] as X assert a.echo(12) == 12 assert a.sayTarts(18) == 'There are 18 tarts!' assert a.sayPies(24) == 'There are 24 pies!' //when interface has only one method, we don't need a map, but can assign and //cast the closure directly... interface Y{ def sayCakes(int i) } def b= {n-> "There are $n cakes!"} as Y assert b.sayCakes(36) == 'There are 36 cakes!' </pre></td></tr></table> <p>Interfaces can also have fields, but their values can't be changed:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> interface X{ int status= 1 //constant field on interface int changeCounter() } class A implements X{ int counter= 1 //updateable field on class itself int changeCounter(){ counter++ } int changeStatus(){ status++ } } def a= new A() a.changeCounter() //field 'counter' can be changed... try{ a.changeStatus(); assert 0 }catch(e){ assert e in IllegalAccessException } //...but field 'status' can't </pre></td></tr></table> <h3>Static Typing with Interfaces</h3> <p>We can use an interface, instead of a class, to statically type a variable, field, parameter, etc:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> import org.codehaus.groovy.runtime.typehandling.GroovyCastException interface X{} class A implements X{} class B{} X a a= new A() try{ a= new B(); assert 0 }catch(e){ assert e in GroovyCastException } </pre></td></tr></table> <p>Groovy supplies many interfaces we can use to statically type variables. Some have no methods, eg, Serializable, while others have one or more:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class A implements Serializable{} //Serializable interface marks class A via the 'in' operator assert A in Serializable //class B implements Closeable{} //compile error when uncommented: method close() must be defined class C implements Closeable{ void close(){} //Closeable interface signifies that this close() method is present } def c= new C() if( c in Closeable ) c.close() </pre></td></tr></table> <p>We've met the Comparator interface in the tutorial on Collections, and the Iterator interface in the tutorial on Control Structures.</p> <p>Many Groovy classes we've met implement interfaces, which we can use to statically type variables:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> import org.codehaus.groovy.runtime.typehandling.GroovyCastException List list1= new ArrayList(), list2= [], list3= new LinkedList() assert list1 in ArrayList && list2 in ArrayList && list3 in LinkedList Set set1= new HashSet(), set2= list1, set3= list3, set4= new TreeSet() assert [set1, set2, set3].every{ it in HashSet } && set4 in TreeSet SortedSet ss1= new TreeSet(), ss2 try{ ss2= new HashSet(); assert 0 }catch(e){ assert e in GroovyCastException } Map map1= new HashMap(), map2= new TreeMap(), map3= [:], map4= new LinkedHashMap() assert map1 in HashMap && map2 in TreeMap && [map3, map4].every{ it in LinkedHashMap } SortedMap sm1= new TreeMap(), sm2 try{ sm2= new HashMap(); assert 0 }catch(e){ assert e in GroovyCastException } </pre></td></tr></table>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced