When checking if my list that is returned from a DB query contains a number with .contains()
it returns false.
Return false:
System.out.println(listaBd); // Output:[1, 2]
listaBd.contains(Long.valueOf(1)) // False
The problem does not seem from the code but from the list, since if I create the list by hand it returns true.
List <Long> listaLong = new ArrayList();
listaLong.add(1L);
listaLong.add(2L);
System.out.println(listaLong); // Output:[1, 2]
listaLong.contains(Long.valueOf(1)) // True
I get the list as follows:
List<Long> results = new ArrayList<Long>();
results = (List<Long>)QueryUtil.list(query, getDialect(), -1, -1); //Liferay
And from what I understand, if it does not give any exception
when casting it, it is because they are Longs
valid
The query
is something like this very simplified (with lots of joins and wheres that I'm going to exclude):
select idIdioma
from mitable;
idIdioma
is one fk
of a kindNUMBER(10,0)
EDIT: After this back and forth of comments, the answer to the main question of why the contains method returns false is definitely, because the list appears to be of Longs but it doesn't contain Longs, but another numeric type which turned out to be BigDecimal .
list
We have seen that the class method returns in its specification aQueryUtil
, and in its implementation it returns aLifeRay
List<?>
ArrayList<Object>
What is happening here is that by doing this:
The list of
Objects
is cast to a list ofLongs
, but it doesn't really containLongs
, butBigDecimals
. Here the OP asks in the comment why the compiler allows this, we see it below.The thing is that we have a list that contains objects that are not
Longs
, butBigDecimal
. When doing:Effectively, it prints
[1, 2]
what would be the result of executingtoString()
each element of the list. It will paint the same for us if the list were ofIntegers
, ofLongs
, evenStrings
if they contain a number with a string. This is where the delusion is where we have stung, that we have assumed that 1 and 2 wereLongs
when it could be something else.Finally, when doing
When comparing an object of type
BigDecimal
, with an object of typeLong
, it returnsfalse
even if they have the same numeric value.Now, to the question of why the compiler allows that cast, it's because a list of
Object
is compatible with a list ofLongs
when casting . In this case the compiler knows that there is a list of objects and we "tell" it in this case we "lie" saying that it is a list ofLongs
. This itself is not illegal in Java, we are casting from one classList
to anotherList
. Now, when we do a cast, we lose the right to have the compiler give us a compile-time error if the types don't match, and if this happens, we end up with a runtime error.In this case, you didn't even get an error at runtime, because the method
contains
accepts aObject
. If the interfaceList
were defined like this:Yes, it would fail at runtime, because
contains
your list methodLongs
would expect an object of typeLong
as a parameter, and would be receiving aBigDecimal
.Also note that casting of
List<Object>
aList<Long>
is supported, but this code does not compile:Finally, the solution to the initial problem is the following as indicated by @David DPG:
This is the first thing I had written for reference:
I have looked at the doc for QueryUtil.list: https://github.com/liferay/liferay-portal/blob/master/portal-kernel/src/com/liferay/portal/kernel/dao/orm/QueryUtil.java (line 87) and the list it returns is an ArrayList of Objects.
It occurs to me that the list is really a list
Integer
that has 1 and 2 as integers, and thencontains
returns false, since the1
integer does not match the1L
.I paste a code where this happens:
Although you have already found the cause, I think it is convenient to clarify that: At compile time, the compiler allows to cast the List of Object to a List of Long because they are compatible. However, after compiling, due to type erasure Java will work with untyped List ; so when adding the values to the list you are not "forced" to use the Long type. That is why it does not give an execution error when it decides to add the information retrieved from the DB as BigDecimal.