Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function .contains() not working in Groovy on expected way

I am trying to check if number is member of list by using Groovy programming language.

I have this piece of code:

List<Long> list = [1, 2, 3]
Long number = 3

println(list.contains(number))​

Expected output is true, but the result I get is false.

Does anybody have an explanation?

like image 957
Jakov Avatar asked Apr 30 '18 14:04

Jakov


People also ask

How do you check if an array contains a value in Groovy?

Groovy - Lists contains() Returns true if this List contains the specified value.

How do you call a function in Groovy?

In Groovy we can add a method named call to a class and then invoke the method without using the name call . We would simply just type the parentheses and optional arguments on an object instance. Groovy calls this the call operator: () . This can be especially useful in for example a DSL written with Groovy.

What does == mean in Groovy?

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.

What does [:] mean in Groovy?

[:] creates an empty Map. The colon is there to distinguish it from [] , which creates an empty List. This groovy code: def foo = [:]


1 Answers

Generic type parameters don't feature at runtime. Check this:

List<Long> list = [1, 2, 3]
list.each{println it.getClass()}

Which prints:

class java.lang.Integer
class java.lang.Integer
class java.lang.Integer

The true confusion is introduced by the bizarre behavior difference between .equals and == implementations:

Long.valueOf(3).equals(Integer.valueOf(3))
===> false
Long.valueOf(3) == Integer.valueOf(3)
===> true

List.contains seems to be using .equals, which checks the class of the parameter, thus explaining why forcing element types to Long resolves the problem.

So, in the midst of this uncertainty, I think the only sure thing is that Groovy's == execution performs the most intuitive and predictable comparison. So I'd change the check to:

boolean contains = list.grep{it == 3L} //sets value to true if matches at least 1

It helps when one doesn't have to be cognizant of data types linked to literals:

def ints = [1, 2, 3]
def longs = [1L, 2L, 3L]

boolean found1 = ints.grep{it == 3L}
boolean found2 = ints.grep{it == 3}
boolean found3 = longs.grep{it == 3L}
boolean found4 = longs.grep{it == 3}

println found1
println found2
println found3
println found4

Which works as anyone would want:

true
true
true
true
like image 186
ernest_k Avatar answered Oct 12 '22 14:10

ernest_k