Lists
A list is an ordered collection of objects:
def list = [5, 6, 7, 8] assert list.size == 4 assert list.size() == 4 assert list.class == ArrayList //the specific kind of list being used assert list[2] == 7 //indexing starts at 0 assert list.getAt(2) == 7 //equivalent method to [] assert list.get(2) == 7 //alternative method list[2] = 9 assert list == [5, 6, 9, 8, ] //trailing comma OK list.putAt(2, 10) //equivalent method to [] when value being changed assert list == [5, 6, 10, 8] assert list.set(2, 11) == 10 //alternative method that returns old value assert list == [5, 6, 11, 8] assert [ 'a', 1, 'a', 'a', 2.5, 2.5f, 2.5d, 'hello', 7g, null, 9 as byte ] //objects can be of different types; duplicates allowed assert [1,2,3,4,5][-1] == 5 //use negative indices to count from the end assert [1,2,3,4,5][-2] == 4 assert [1,2,3,4,5].getAt(-2) == 4 //getAt() available with negative index... try{ [1,2,3,4,5].get(-2); assert 0 } //...but not get() catch(e){ assert e instanceof ArrayIndexOutOfBoundsException }
Lists can be evaluated as a boolean value:
assert ! [] //an empty list evaluates as false assert [1] && ['a'] && [0] && [0.0] && [false] && [null] //all other lists, irrespective of contents, evaluate as true
We can use [] to assign a new empty list and << to append items to it:
def list = []; assert list.size() == 0 list << 5; assert list.size() == 1 list << 7 << 'i' << 11; assert list == [5, 7, 'i', 11] list << ['m', 'o']; assert list == [5, 7, 'i', 11, ['m', 'o'] ] assert ( [1,2] << 3 << [4,5] << 6 ) == [1,2,3, [4, 5], 6] //first item in chain of << is target list assert ([1,2,3] << 4) == ([1,2,3].leftShift(4)) //using this method is equivalent to using <<
We can add to a list in many ways:
assert [1,2] + 3 + [4,5] + 6 == [1, 2, 3, 4, 5, 6] assert [1,2].plus(3).plus([4,5]).plus(6) == [1, 2, 3, 4, 5, 6] //equivalent method for + def a= [1,2,3]; a += 4; a += [5,6]; assert a == [1,2,3,4,5,6] assert [1, *[222, 333], 456] == [1, 222, 333, 456] assert [ *[1,2,3] ] == [1,2,3] assert [ 1, [2,3,[4,5],6], 7, [8,9] ].flatten() == [1, 2, 3, 4, 5, 6, 7, 8, 9] def list= [1,2] list.add(3) //alternative method name list.addAll([5,4]) //alternative method name assert list == [1,2,3,5,4] list= [1,2] list.add(1,3) //add 3 just before index 1 assert list == [1,3,2] list.addAll(2,[5,4]) //add [5,4] just before index 2 assert list == [1,3,5,4,2] list = ['a', 'b', 'z', 'e', 'u', 'v', 'g'] list[8] = 'x' assert list == ['a', 'b', 'z', 'e', 'u', 'v', 'g', null, 'x'] //nulls inserted if required
We can use the each and eachWithIndex methods to execute code on each item in a list:
[1, 2, 3].each{ println "Item: $it" }
['a', 'b', 'c'].eachWithIndex{ it, i -> println "$i: $it" }
We can construct a list using another's elements as a template:
def list1= ['a','b','c'] def list2 = new ArrayList( list1 ) //construct a new list, seeded with the same items as in list1 assert list2 == list1 // == checks that each corresponding element is the same def list3 = list1.clone() assert list3 == list1
We can perform a closure on each item of a list and return the result:
assert [1, 2, 3].collect{ it * 2 } == [2, 4, 6] //simple call gives single result assert [1, 2, 3]*.multiply(2) == [1, 2, 3].collect{ it.multiply(2) } //shortcut syntax instead of collect def list= [] assert [1, 2, 3].collect( list ){ it * 2 } == [2, 4, 6] //this style of call gives two identical results assert list == [2, 4, 6]
Other methods on a list return a value:
assert [1, 2, 3].find{ it > 1 } == 2 assert [1, 2, 3].findAll{ it > 1 } == [2, 3] assert ['a','b','c','d','e'].findIndexOf{ it in ['c','e','g'] } == 2 //find first item that satisfies closure assert [1, 2, 3].every{ it < 5 } assert ! [1, 2, 3].every{ it < 3 } assert [1, 2, 3].any{ it > 2 } assert ! [1, 2, 3].any{ it > 3 } // sum anything with a plus() method assert [1,2,3,4,5,6].sum() == 21 assert ['a','b','c','d','e'].sum{ it=='a'?1: it=='b'?2: it=='c'?3: it=='d'?4: it=='e'?5: 0 } == 15 assert ['a','b','c','d','e'].sum{ (char)it - (char)'a' } == 10 assert ['a','b','c','d','e'].sum() == 'abcde' assert [['a','b'], ['c','d']].sum() == ['a','b','c','d'] // an initial value can be provided assert [].sum(1000) == 1000 assert [1, 2, 3].sum(1000) == 1006 assert [1, 2, 3].join('-') == '1-2-3' assert [1, 2, 3].inject('counting: '){ str, item -> str + item } == 'counting: 123' assert [1, 2, 3].inject(0){ count, item -> count + item } == 6
We can find the maximum and minimum in a collection:
def list= [9, 4, 2, 10, 5] assert list.max() == 10 assert list.min() == 2 assert Collections.max( list ) == 10 assert Collections.min( list ) == 2 assert ['x', 'y', 'a', 'z'].min() == 'a' //we can also compare single characters def list2= ['abc', 'z', 'xyzuvw', 'Hello', '321'] assert list2.max{ it.size() } == 'xyzuvw' //we can use a closure to spec the sorting behaviour assert list2.min{ it.size() } == 'z'
We can use a "Comparator" to define the comparing behaviour:
def mc= [compare:{a,b-> a.equals(b)? 0: a<b? -1: 1}] as Comparator
//this syntax to be explained in a later tutorial
def list= [7,4,9,-6,-1,11,2,3,-9,5,-13]
assert list.max( mc ) == 11
assert list.min( mc ) == -13
assert Collections.max( list, mc ) == 11
assert Collections.min( list, mc ) == -13
def mc2= [
compare: {a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 }
] as Comparator
//we should always ensure a.equals(b) returns 0, whatever else we do,
//to avoid inconsistent behaviour in many contexts
assert list.max( mc2 ) == -13
assert list.min( mc2 ) == -1
assert list.max{a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 } == -13
assert list.min{a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 } == -1
We can remove elements from a list by referring to the element/s to be removed:
assert ['a','b','c','b','b'] - 'c' == ['a','b','b','b'] //remove 'c', and return resulting list assert ['a','b','c','b','b'] - 'b' == ['a','c'] //remove all 'b', and return resulting list assert ['a','b','c','b','b'] - ['b','c'] == ['a'] //remove all 'b' and 'c', and return resulting list assert ['a','b','c','b','b'].minus('b') == ['a','c'] //equivalent method name for - assert ['a','b','c','b','b'].minus( ['b','c'] ) == ['a'] def list= [1,2,3,4,3,2,1] list -= 3 assert list == [1,2,4,2,1] //use -= to remove 3, permanently assert ( list -= [2,4] ) == [1,1] //remove 2's and 4's, permanently
We can remove an element by referring to its index:
def list= [1,2,3,4,5,6,2,2,1] assert list.remove(2) == 3 //remove the third element, and return it assert list == [1,2,4,5,6,2,2,1]
We can remove the first occurrence of an element from a list:
def list= ['a','b','c','b','b'] assert list.remove('c') //remove 'c', and return true because element removed assert list.remove('b') //remove first 'b', and return true because element removed assert ! list.remove('z') //return false because no elements removed assert list == ['a','b','b']
We can clear a list of all elements:
def list= ['a',2,'c',4]
list.clear()
assert list == []
We can pop the last item from a list, and use the list as a simple stack:
def stack= [1,2,4,6] stack << 7 assert stack == [1,2,4,6,7] assert stack.pop() == 7 assert stack == [1,2,4,6]
Other useful operators and methods:
assert 'a' in ['a','b','c'] assert ['a','b','c'].contains('a') assert [1,3,4].containsAll([1,4]) assert [].isEmpty() assert [1,2,3,3,3,3,4,5].count(3) == 4 assert [1,2,4,6,8,10,12].intersect([1,3,6,9,12]) == [1,6,12] assert [1,2,3].disjoint( [4,6,9] ) assert ! [1,2,3].disjoint( [2,4,6] ) assert Collections.disjoint( [1,2,3], [4,6,9] ) //alternative method name
There's various ways of sorting:
assert [6,3,9,2,7,1,5].sort() == [1,2,3,5,6,7,9] def list= ['abc', 'z', 'xyzuvw', 'Hello', '321'] assert list.sort{ it.size() } == ['z', 'abc', '321', 'Hello', 'xyzuvw'] def list2= [7,4,-6,-1,11,2,3,-9,5,-13] assert list2.sort{a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 } == [-1, 2, 3, 4, 5, -6, 7, -9, 11, -13] def mc= [ compare: {a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 } ] as Comparator assert list2.sort(mc) == [-1, 2, 3, 4, 5, -6, 7, -9, 11, -13] def list3= [6,-3,9,2,-7,1,5] Collections.sort(list3) assert list3 == [-7,-3,1,2,5,6,9] Collections.sort(list3, mc) assert list3 == [1,2,-3,5,6,-7,9]
We can repeat a list or element:
assert [1,2,3] * 3 == [1,2,3,1,2,3,1,2,3] assert [1,2,3].multiply(2) == [1,2,3,1,2,3] assert Collections.nCopies( 3, 'b' ) == ['b', 'b', 'b'] //nCopies works differently assert Collections.nCopies( 2, [1,2] ) == [ [1,2], [1,2] ] //not [1,2,1,2]
We can find the first or last index of items in a list:
assert ['a','b','c','d','c','d'].indexOf('c') == 2 //index returned assert ['a','b','c','d','c','d'].indexOf('z') == -1 //index -1 means value not in list assert ['a','b','c','d','c','d'].lastIndexOf('c') == 4
Some very common methods are:
def list= [], list2= []
[1,2,3,4,5].each{ list << it*2 }
assert list == [2,4,6,8,10]
[1,2,3,4,5].eachWithIndex{item, index-> list2 << item * index }
//closure supplied must have 2 params
assert list2 == [0,2,6,12,20]
A list may contain itself, but equals() may not always be consistent. Consider this:
def list, list2, list3 list= [1, 2, list, 4] list2= [1, 2, list2, 4] assert list.equals(list2) list3= [1, 2, list, 4] assert ! list.equals(list3)
Ranges and List-Slicing
Ranges are consecutive lists of sequential values like Integers, and can be used just like a List:
assert 5..8 == [5,6,7,8] //includes both values assert 5..<8 == [5, 6, 7] //excludes specified top value
They can also be used with single-character strings:
assert ('a'..'d') == ['a','b','c','d']
Ranges are handy with the each method:
def n=0
(1..10).each{ n += it }
assert n == 55
We can define lists using a range or ranges within a list. This is called slicing:
assert [*3..5] == [3,4,5] assert [ 1, *3..5, 7, *9..<12 ] == [1,3,4,5,7,9,10,11]
Lists can be used as subscripts to other lists:
assert ('a'..'g')[ 3..5 ] == ['d','e','f'] assert ('a'..'g').getAt( 3..5 ) == ['d','e','f'] //equivalent method name assert ('a'..'g')[ 1, 3, 5, 6 ] == ['b','d','f','g'] assert ('a'..'g')[ 1, *3..5 ] == ['b','d','e','f'] assert ('a'..'g')[ 1, 3..5 ] == ['b','d','e','f'] //range in subscript flattened automatically assert ('a'..'g')[-5..-2] == ['c','d','e','f'] assert ('a'..'g').getAt( [ 1, *3..5 ] ) == ['b','d','e','f'] //equivalent method name assert ('a'..'g').getAt( [ 1, 3..5 ] ) == ['b','d','e','f']
We can view a sublist of a list:
def list=[1,2,3,4,5], sl= list.subList(2,4) sl[0]= 9 //if we change the sublist... assert list == [1,2,9,4,5] //...backing list changes... list[3]= 11 assert sl == [9,11] //...and vice versa
We can perform the same methods on the subscripted lists as we can on the lists they're produced from:
assert ['a','b','c','d','e'][1..3].indexOf('c') == 1 //note: index of sublist, not of list
We can update items using subscripting too:
def list = ['a','b','c','d','e','f','g'] list[2..3] = 'z' assert list == ['a', 'b', 'z', 'e', 'f', 'g'] //swap two entries for one list[4..4]= ['u','v'] assert list == ['a', 'b', 'z', 'e', 'u', 'v', 'g'] //swap one entry for two def list= ['a', 'b', 'z', 'e', 'u', 'v', 'g'] list[0..1]= [] assert list == ['z', 'e', 'u', 'v', 'g'] //remove entries from index range list[1..1]= [] assert list == ['z', 'u', 'v', 'g'] //remove entry at index
We can also use a method instead of [] with ranges:
def list = ['a','b','c','d','e','f','g'] list.putAt(2..3, 'z') assert list == ['a', 'b', 'z', 'e', 'f', 'g'] list.putAt(4..4, ['u','v']) assert list == ['a', 'b', 'z', 'e', 'u', 'v', 'g'] list.putAt(1..<3, []) assert list == ['a', 'e', 'u', 'v', 'g'] list.putAt( 0..<0, 'm' ) // assert list == ['m', 'a', 'e', 'u', 'v', 'g'] list.removeRange(1,3) //another method to do similar, means: list[1..<3]= [] list[1..2].clear() assert list == ['m', 'g']
More List Utilities
To reverse a list:
assert [1,2,3].reverse() == [3,2,1] def list= ['a','b','c','d','e'] Collections.reverse( list ) assert list == ['e','d','c','b','a'] use(Collections){ list.reverse() } //alternative syntax for null-returning Collections.reverse(List) assert list == ['a','b','c','d','e'] def list2= [] [1,2,3,4,5].reverseEach{ list2 << it*2 } //same as, but more efficient than: [...].reverse().each{...} assert list2 == [10,8,6,4,2] assert [1,2,3,4,5,6][3..1] == [4,3,2] //use backwards range to reverse returned sublist def list3 = [1, 2, -3, 5, 6, -7, 9] def rmc= Collections.reverseOrder() Collections.sort(list3, rmc) assert list3 == [9, 6, 5, 2, 1, -3, -7] def list4 = [1, 2, -3, 5, 6, -7, 9] def mc= [ compare: {a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1} ] as Comparator def rmc2= Collections.reverseOrder( mc ) Collections.sort(list4, rmc2) assert list4 == [9, -7, 6, 5, -3, 2, 1]
We can perform a binary search on a sorted list:
assert Collections.binarySearch([2,5,6,7,9,11,13,26,31,33], 26) == 7 //list must already be sorted assert Collections.binarySearch([2,5,6,7,9,11,13,31,33], 26) == -8 //if key not there, give negative of one plus the index before which key //would be if it was there def mc= [ compare: {a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 } ] as Comparator assert Collections.binarySearch([2,-5,-6,7,9,-11,13,26,31,-33], 26, mc) == 7 //give comparator list sorted by
We can remove or retain elements in bulk. retainAll() gives the intersection of two lists; removeAll() gives the assymmetric difference.
def list= ['a','b','c','b','b','e','e'] assert list.removeAll( ['b','z'] ) //remove 'b' and 'z', return true because list changed assert list == ['a','c','e','e'] assert ! list.removeAll( ['b','z'] ) //return false because list didn't change assert list == ['a','c','e','e'] assert list.retainAll( ['a','e'] ) //retain only 'a' and 'e', return true because list changed assert list == ['a','e','e'] assert ! list.retainAll( ['a','e'] ) //retain only 'a' and 'e', return true because list didn't change assert list == ['a','e','e']
Some miscellaneous methods:
def list= ['a', 7, 'b', 9, 7, 7, 2.4, 7] Collections.replaceAll( list, 7, 55) assert list == ['a', 55, 'b', 9, 55, 55, 2.4, 55] list= ['a', 7, 'b', 9, 7, 7, 2.4, 7] use(Collections){ list.replaceAll(7, 55) } //alternative syntax assert list == ['a', 55, 'b', 9, 55, 55, 2.4, 55] list= ['a',2,null,4,'zyx',2.5] use(Collections){ list.fill( 'g' ) } //or: Collections.fill( list, 'g' ) assert list == ['g', 'g', 'g', 'g', 'g', 'g'] list= ['a', 'e', 'i', 'o', 'u', 'z'] use(Collections){ list.swap(2, 4) } //or: Collections.swap(list, 2, 4) assert list == ['a', 'e', 'u', 'o', 'i', 'z'] assert Collections.frequency(['a','b','a','c','a','a','d','e'], 'a') == 4 use(Collections){ assert ['a','b','a','c','a','a','d','e'].frequency('a') == 4 } list= ['a','b','c','d','e'] Collections.rotate(list, 3) assert list == ['c','d','e','a','b'] use(Collections){ list.rotate(-2) } assert list == ['e','a','b','c','d'] list= [1,2,3,4,5] Collections.shuffle(list, new Random()) //we can supply our own random number generator... assert list != [1,2,3,4,5] list= [1,2,3,4,5] Collections.shuffle(list) //...or use the default one assert list != [1,2,3,4,5] assert [3,5,5,5,2].unique() == [3,5,2] def mc= [ compare: {a,b-> a.equals(b) || a.equals(-b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 } ] as Comparator assert [3,5,5,-5,2,-7].unique(mc) == [3,5,2,-7] //remove subsequent items comparator considers equal assert [3,5,5,-5,2,-7].unique{a, b-> a == b || a == -b? 0: Math.abs(a)<Math.abs(b)? -1: 1 } == [3,5,2,-7] list= [1,2,3] Collections.copy( list, [9,8,7] ) assert list == [9,8,7] //overwrites original data Collections.copy( list, [11,12] ) //source list shorter... assert list == [11,12,7] //...which leaves remaining entries unchanged try{ Collections.copy( list, [21,22,23,24] ); assert 0 } //source list too long catch(e){ assert e instanceof IndexOutOfBoundsException } list= [1,8,8,2,3,7,6,4,6,6,2,3,7,5] assert Collections.indexOfSubList( list, [2,3,7] ) == 3 assert Collections.lastIndexOfSubList( list, [2,3,7] ) == 10 assert Collections.indexOfSubList( list, [9,9,13] ) == -1 //if sublist doesn't exist
Sets
A set is an unordered collection of objects, with no duplicates. It can be considered as a list with restrictions, and is often constructed from a list:
def s1= [1,2,3,3,3,4] as Set,
s2= [4,3,2,1] as Set,
s3= new HashSet( [1,4,2,4,3,4] )
assert s1.class == HashSet && s2.class == HashSet
//the specific kind of set being used
assert s1 == s2
assert s1 == s3
assert s2 == s3
assert s1.asList() && s1.toList()
//a choice of two methods to convert a set to a list
assert ( ([] as Set) << null << null << null ) == [null] as Set
A set should not contain itself as an element.
Most methods available to lists, besides those that don't make sense for unordered items, are available to sets.
[ { it[1] }, { it.getAt(1) }, { it.putAt(1,4) }, { it.reverse() } ].each{
try{ it([1,2,3] as Set); assert 0 }
catch(e){ assert e instanceof MissingMethodException }
}
The add() and addAll() methods return false if the set wasn't changed as a result of the operation:
def s= [1,2] as Set assert s.add(3) assert ! s.add(2) assert s.addAll( [5,4] ) assert ! s.addAll( [5,4] ) assert s == [1,2,3,5,4] as Set
Examples with Lists and Sets
For small numbers of items, it's common in Groovy to use a list for set processing, and only convert it to a set when necessary, eg, for output.
Though the uniqueness of set items is useful for some processing, for example, if we want to separate the unique and duplicating items in a list:
list=[1,2,7,2,2,4,7,11,5,2,5]
def uniques= [] as Set, dups= [] as Set
list.each{ uniques.add(it) || dups.add(it) }
uniques.removeAll(dups)
assert uniques == [1,4,11] as Set && dups == [2,5,7] as Set
To calculate the symmetric set difference of two sets non-destructively:
def s1=[1,2,3,4,5,6], s2=[4,5,6,7,8,9]
def diff = (s1 as Set) + s2
tmp = s1 as Set
tmp.retainAll(s2)
diff.removeAll(tmp)
assert diff == [1,2,3,7,8,9]
Sorted Sets
A sorted set is one with extra methods that utilize the sorting of the elements. It's often more efficient than doing the same with lists.
def list= [3,2,3,3,1,7,5] assert new TreeSet(list) == new TreeSet([1,1,1,2,5,7,3,1]) assert new TreeSet(list).toList() == list.unique().sort() assert new TreeSet(list).first() == list.unique().min() assert new TreeSet(list).last() == list.unique().max()
We can construct a TreeSet by giving a comparator to order the elements in the set:
def c= [ compare:
{a,b-> a.equals(b)? 0: Math.abs(a)<Math.abs(b)? -1: 1 }
] as Comparator
def ts= new TreeSet( c )
ts<< 3 << -7 << 9 << -2 << -4
assert ts == new TreeSet( [-2, 3, -4, -7, 9] )
assert ts.comparator() == c //retrieve the comparator
The range-views, headSet() tailSet() and subSet(), are useful views of the items in a sorted set. These range-views remain valid even if the backing sorted set is modified directly. The sorted set returned by these methods will throw an IllegalArgumentException if the user attempts to insert an element out of the range.
def ss= new TreeSet(['a','b','c','d','e']) def hs= ss.headSet('c') assert hs == new TreeSet(['a','b']) //return all elements < specified element hs.remove('a') assert ss == new TreeSet(['b','c','d','e']) //headset is simply a view of the data in ss def ts= ss.tailSet('c') assert ts == new TreeSet(['c','d','e']) //return all elements >= specified element ts.remove('d') assert ss == new TreeSet(['b','c','e']) //tailset is also a view of data in ss def bs= ss.subSet('b','e') assert bs == new TreeSet(['b','c']) //return all elements >= but < specified element bs.remove('c') assert ss == new TreeSet(['b','e']) //subset is simply a view of the data in ss ss << 'a' << 'd' assert hs == new TreeSet(['a','b']) //if backing sorted set changes, so do range-views assert ts == new TreeSet(['d','e']) assert bs == new TreeSet(['b','d'])
For a SortedSet of strings, we can append '\0' to a string to calculate the next possible string:
def dic= new TreeSet( ['aardvark', 'banana', 'egghead', 'encephalograph', 'flotsam', 'jamboree'] ) assert dic.subSet('banana', 'flotsam').size() == 3 //incl 'banana' but excl 'flotsam' assert dic.subSet('banana', 'flotsam\0').size() == 4 //incl both assert dic.subSet('banana\0', 'flotsam').size() == 2 //excl both dic.subSet('e', 'f').clear() assert dic == new TreeSet( ['aardvark', 'banana', 'flotsam', 'jamboree'] )//clear all words beginning with 'e'
To go one element backwards from an element elt in a SortedSet:
Object predecessor = ss.headSet( elt ).last()
Immutable Collections
We can convert a list or set into one that can't be modified:
def imList= ['a', 'b', 'c'].asImmutable() try{ imList<< 'd'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } imList= Collections.unmodifiableList( ['a', 'b', 'c'] ) //alternative way try{ imList<< 'd'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } def imSet= (['a', 'b', 'c'] as Set).asImmutable() try{ imSet<< 'd'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } imSet= Collections.unmodifiableSet( ['a', 'b', 'c'] as Set ) //alternative way try{ imSet<< 'd'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } def imSortedSet= ( new TreeSet(['a', 'b', 'c']) ).asImmutable() try{ imSortedSet<< 'd'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } imSortedSet= Collections.unmodifiableSortedSet( new TreeSet(['a', 'b', 'c']) ) //alternative way try{ imSortedSet<< 'd'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException }
We can create an empty list or set that can't be modified:
def list= Collections.emptyList() assert list == [] try{ list<< 'a'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } list= Collections.EMPTY_LIST assert list == [] try{ list<< 'a'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } def set= Collections.emptySet() assert set == [] as Set try{ set<< 'a'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException } set= Collections.EMPTY_SET assert set == [] as Set try{ set<< 'a'; assert 0 } catch(e){ assert e instanceof UnsupportedOperationException }
We can create a single-element list that can't be modified:
def singList= Collections.singletonList('a')
assert singList == ['a']
try{ singList<< 'b'; assert 0 }
catch(e){ assert e instanceof UnsupportedOperationException }
def singSet = Collections.singleton('a')
assert singSet == ['a'] as Set
try{ singSet<< 'b'; assert 0 }
catch(e){ assert e instanceof UnsupportedOperationException }











