Using 'contains' method in a class array - java

I have a class like this:
public static class TiposDeHistorial
{
String CODIGO, TIPO;
public TiposDeHistorial()
{
}
public String getCODIGO()
{
return CODIGO;
}
public void setCODIGO(String CODIGO)
{
this.CODIGO = CODIGO;
}
public String getTIPO()
{
return TIPO;
}
public void setTIPO(String TIPO)
{
this.TIPO = TIPO;
}
}
and a list of it:
ArrayList<TiposDeHistorial> tiposHistorial;
So my question is: can I use tiposHistorial.contains(...) to search in a specific array field, CODIGO or TIPO, for example?

First of, you do not have an array but an ArrayList.
The contains method on a List operates with the equals method of it's stored elements (TiposDeHistorial in your case). Therefore the answer to your question is no.
Trying something like tiposHistorial.contains("a") will not work as there is a type mismatch: your list is of type TiposDeHistorial while you try to check for an element of String.

If you are using Java 8 you can use following code:
tiposHistorial.stream()
.filter(x -> "specific value for CODIGO".equals(x.getCODIGO()))
.findFirst()
.orElse(null);
It will return TiposDeHistorial object in the list containing specific CODIGO value or null otherwise.
As for your question: "contains" method just returns "true" or "false", not an object. Moreover it uses "equals" method of your object, so it will not help if you want to search using fields.

Contains method will return true only if your object equals with ur list elements objects.
You can try extending equals method and have your own criteria which can work for either CODIGO or TIPO.
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
test other = (test) obj;
if (CODIGO == null) {
if (other.CODIGO != null)
return false;
} else if (!CODIGO.equals(other.CODIGO))
return false;
return true;
}

The answers already given here are all correct, just if You don't know java streams, and would like to check if the list contains both some CODIGO and TIPO fields, for me the simplest solution would be:
ArrayList<TiposDeHistorial> tiposHistorial = new ArrayList<>();
//add elements to the list
String tipo = "TIPO"; // the TIPO value You are looking for in the list
String codigo = "CODIGO"; // the CODIGO value You are looking for in the list
boolean containsTipo = false;
boolean containsCodigo = false;
for (TiposDeHistorial element: tiposHistorial) {
if (!containsTipo && element.getTIPO().equals(tipo)) {
containsTipo = true;
}
if (!containsCodigo && element.getCODIGO().equals(codigo) ){
containsCodigo = true;
}
if (containsTipo && containsCodigo)
break;
}
By editing it just a bit, You may also find which elements of the array contain the values You are looking for, if that will be Your intention

Related

Java class object not equal even they are equal [duplicate]

This question already has answers here:
Why does this .equals() code example return "false"? [duplicate]
(3 answers)
Closed 2 years ago.
Hey i have two java class object, whose key and values are same but when I check ob1.equals(obj2) its return false.
here is the code :
Category expected = new Category("01","lorem","custom");
ResponseEntity<List<LinkedHashMap>> response = restTemplate.exchange("/api/categories", HttpMethod.GET,
null, new ParameterizedTypeReference<List<LinkedHashMap>>() {});
LinkedHashMap result = response.getBody().get(0); // which is same as expected object
//check if equals
private boolean areEqual(LinkedHashMap result, Category expected) {
String catId = (String) obj.get("category_id"); //is 01
String name = (String) obj.get("category_name"); // is lorem
String sec = (String) obj.get("section_name"); // is custom
DefaultCategory temp = new Category(catId, name, sec);
return temp.equals(expected); //<--------- returning false, even they are equal
}
The api return this category
#GetMapping("categories")
public ResponseEntity<List<Category>> getDefaultCategories() {
List<Category> categories = new ArrayList();
categories.add(new Category("01","lorem","custom"));
return new ResponseEntity<>(categories, HttpStatus.OK);
}
Standard .equals(...) checks two objects are same instance or not. If you want to compare two objects with their fields. You can override equals method like below.
public class DefaultCategory {
private String catId;
private String name;
private String sec;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultCategory)) return false;
DefaultCategory other = (DefaultCategory) o;
if(!Objects.equals(other.catId, catId)) return false;
if(!Objects.equals(other.name, name)) return false;
if(!Objects.equals(other.sec, sec)) return false;
return true;
}
}
Because expected is a child class and temp is a super class or vice versa. You are comparing two different objects(types). Cast you temp to Category and you will be fine. Or override your equals to allow mixed type comparison.

indexOf() in Android when using Helper

I know that the below code gives the index of that particular element in java.
List<String> list = new ArrayList<>();
list .add("100");
Log.d("TAG",String.valueOf(list.indexOf("300")));
But how to get the index of an element while using a helper Class?
List<HelperClass> Arraylist= new ArrayList<>();
Arraylist.add(new HelperClass(name, email, phoneno));
Log.d("TAG", String.valueOf(new HelperClass(Arraylist.indexOf(name,email,phoneno))));
I searched everywhere for this but couldn't find. Can someone tell me how to find index of a particular item in arraylist while using modal to add data?
Obviously what I have tried is wrong and it shows red line under the whole line but I just typed that code for your understanding of what I want to achieve. Can someone give me a way please?
Helper
#Override
public int hashCode() {
int result = getName() != null ? getName().hashCode() : 0;
result = 31 * result + (Email != null ? Emaail.hashCode() : 0);
result = 31 * result + (PhoneNo!= null ? PhoneNo.hashCode() : 0);
return result;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Helper)) return false;
Helperthat = (Helper) o;
if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null)
return false;
if (Email != null ? !Email.equals(that.Email) : that.Email != null)
return false;
if (PhoneNo != null ? !PhoneNo.equals(that.PhoneNo) : that.PhoneNo != null)
return false;
}
ArrayList#indexOf uses the Object#equals comparison method.
If you want to be able to lookup a HelperClass instance inside a Collection, you need to provide your own, overridden, equals method, and possibly also the hashCode one, for use with other, specific, Collection implementations (Map, Set, etc.).
class HelperClass {
...
#Override
public boolean equals(final Object object) {
if (object == this) {
return true;
}
if (!(object instance of HelperClass)) {
return false;
}
final HelperClass other = (HelperClass) object;
return name.equals(other.name) &&
email.equals(other.email) &&
phone.equals(other.phone);
}
}
You obviously need to have an appropriate HelperClass instance to find a match.
final String name = "Name";
final String email = "Email";
final String phone = "Phone";
final HelperClass first = new HelperClass(name, email, phone);
final HelperClass second = new HelperClass(name, email, phone);
final List<HelperClass> helpers = new ArrayList<>(8);
helpers.add(first);
final int index = helpers.indexOf(second); // index = 0
indexOf requires the object as input. If it does not find the object you are passing in, it will return -1. You need to pass the object whose location in the arraylist you are looking for as the input into the indexOf function.
Solution :
create a HelperClass to pass into the indexOf method:
.indexOf(new HelperClass(name, email, phoneno));
However that change by itself will still return -1. See the api doc for indexOf:
public int indexOf(Object o)
Returns the index of the first occurrence of the specified element in
this list, or -1 if this list does not contain the element. More
formally, returns the lowest index i such that (o==null ? get(i)==null
: o.equals(get(i))), or -1 if there is no such index.
It's using equals to decide whether it's found a match. You should have overridden the equals method on your HelperClass class, so it's using the default implementation in java.lang.Object, which compares the references, and only returns true if the two references HelperClass to the same object.
Override equals and hashcode on your HelperClass class, like:
#Override public boolean equals(Object other) {
if (!(other instanceof HelperClass)) {
return false;
}
HelperClass otherHelperClass = (HelperClass)other;
return otherHelperClass.x == this.x && otherHelperClass.y == this.y;
}
#Override public int hashCode() {
return x + y; // same values should hash to the same number
}

Collection.contains yields wrong result

I've got an object which has got a couple of fields -- as you can see the hashcode and equals method is implemented just taking the id in account:
public class SpotResponse{
String id;
// bla bla other fields
public SpotResponse() {
}
public SpotResponse(#NonNull String id) {
this.id = id;
}
public String getId() {
return id;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SpotResponse that = (SpotResponse) o;
return id == that.id;
}
#Override
public int hashCode() {
return id.hashCode();
}
}
I've got a method which checks if a Collection<SpotResponse> newSpots
contains some oldSpots from a HashMap<String, SpotResponse> spots = new HashMap<>();
If I do this:
List<String> newKeys = new ArrayList<>();
for (SpotResponse response : newSpots) {
newKeys.add(response.getId());
}
for (SpotResponse oldSpot : spots.values()) {
if (newKeys.contains(oldSpot.getId())) {
continue;
}
/* blabla */
}
newKeys.contains() returns true properly, but if instead I do
newSpots.contains(oldSpot)
It always returns false. In this case, the Collection is an ArrayList (if this is of any help)
Your bug is in your equals implementation, on this line:
return id == that.id;
You're comparing two Strings (namely id and that.id) with ==, when you should use id.equals(that.id).
You have to be careful when using Contains with Primitives.
String is technically an object class wrapping a primitive of chars, but when you are comparing it, it is not comparing the literal object memory pointer, it is comparing the value at the memory pointer.
Contains is using .equals under the hood, so when overriding equals in your class you can't default back to the == comparison as that compares address and not necessarily value.
Hope that helps.

Comparing An Entry In A Map With An Object

I have a Map in Java like so,
private HashMap<String, Object[][]> theMap;
Where the key is a String and the entry is going to be something along the line of,
theMap = new HashMap<>();
Object[][] theData = {
{Boolean.FALSE, "Text"}
};
theMap.put("Key1", theData);
Somewhere along the line I would like to check if an entry in the map is equivalent to another object. Currently I am doing it like this,
Object[][] tempData = {
{Boolean.FALSE, "Text"}
};
for(Object key: entries.keySet()) {
if(entries.get(key).equals(tempData)) {
entries.remove(key);
}
}
And it is not working.
I would prefer the comparison to be done with an object rather than with another map. I'm wondering what I'm doing wrong with this comparison here?
The reason you are not getting equality is that arrays inherit Object#equals() which is based on identity, not equality of contents. You could consider using java.util.Arrays.deepEquals(Object[], Object[]) to compare.
That is the answer to the immediate question. However, using a 2-dimensional array of Object to hold a boolean and a String is really bad code smell and indicates you need to encapsulate what you are putting in the array.
Identity vs Equivalence
Please make sure that you understand that by default the equals() method of Object checks on whether two object references are referring to the same object (identity), which is not what your code is checking.
Instead, your code is checking whether the two objects (the values you put on the map) are having the same value (equivalence).
Here are two articles about this topic:
What is the difference between identity and equality in OOP?
Overriding equals method in Java
In this particular problem of yours, I think the solution involves two steps:
Your tempData and theData does not seems to be an array
of elements of the same type (it does not appear to be a 2-dimensional
array either). Instead, it contains a Boolean value and then a
String value. In this case, I think you really should think
through what this thingy is and design a class for it (I am showing
an example below)
The class should override the equals() (and hashCode()) methods
so that you can use its equals() for equivalence checking.
Note also that your IDE (e.g. Eclipse) probably can generate a template for equals() and hashCode() for you.
Example: (here I assume your Boolean represents a condition, and your String represents a message)
class MyRecord {
private Boolean condition;
private String message;
public Boolean getCondition() {
return condition;
}
public void setCondition(Boolean condition) {
this.condition = condition;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((condition == null) ? 0 : condition.hashCode());
result = prime * result
+ ((message == null) ? 0 : message.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyRecord other = (MyRecord) obj;
if (condition == null) {
if (other.condition != null)
return false;
} else if (!condition.equals(other.condition))
return false;
if (message == null) {
if (other.message != null)
return false;
} else if (!message.equals(other.message))
return false;
return true;
}
}

Comparing two collections using hamcrest contains() method

I have two collections which I am trying to compare for equality in my unit tests, but I am struggling with the contains method. Here is what I have:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(expectedItems, contains(actualItems));
}
items contains the same objects as expectedItems so I would expect the assertion to be true but this is the output I get:
[Item{name=iPhone}, Item{name=Skateboard}] --> Expected
[Item{name=iPhone}, Item{name=Skateboard}] --> Actual
java.lang.AssertionError:
Expected: iterable containing [<[Item{name=iPhone}, Item{name=Skateboard}]>]
but: item 0: was <Item{name=iPhone}>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
Please can you help me where I am going wrong with using the contains method?
public class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return Objects.toStringHelper(this).add("name", name).toString();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Item other = (Item) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
A Collection's .contains(...) uses the equals and hashCode methods of the Objects. In order to use equals (or in this case contains) on your own Objects, you need to override the equals and hashCode methods of your class. This is because Java uses references behind the scenes, so even though the field may be equal, the Object-references are not.
In Eclipse you can generate them using right-mouse click -> Source -> Generate hashCode() and equals().... But, since you never stated you use Eclipse, here is an example of the methods that are generated:
// Overriding this class' equals and hashCode methods for Object comparing purposes
// using the Collection's contains
// contains does the following behind the scenes: Check if both inputs aren't null,
// check if the HashCodes match, check if the Objects are equal.
// Therefore to use the Collection's contains for Objects with the same fields, we
// need to override the Object's equals and hashCode methods
// These methods below are generated by Eclipse itself using "Source -> Generate
// hashCode() and equals()..."
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
Item other = (Item) obj;
if(name == null){
if(other.name != null)
return false;
}
else if(!name.equals(other.name))
return false;
return true;
}
If you add both of these to your Item-class, the contains will work.
EDIT:
I'm not sure, but when I look at your code I think the following might be wrong:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
// You first print both lists
System.out.println(expectedItems);
System.out.println(items);
// And then add the two items to the expectedItems
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(expectedItems, contains(actualItems));
}
If you try the following instead:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
// First add both items
expectedItems.add(iPhone);
expectedItems.add(skateboard);
// Then print both lists
System.out.println(expectedItems);
System.out.println(items);
assertThat(expectedItems, contains(actualItems));
}
Does the expectedList now contain 4 items?
[Item{name=iPhone}, Item{name=Skateboard}, Item{name=iPhone}, Item{name=Skateboard}] --> Expected
[Item{name=iPhone}, Item{name=Skateboard}] --> Actual
In that case you shouldn't add the two items, since they are already present in the list.
Also, you're trying to use the contains on the entire list. Normally the contains is used to see if a single item is present in the list. So you could either use something like this:
for(Item i : expectedList){
assertTrue(actualList.contains(i));
}
or perhaps something like this, in case you use these libraries:
assertThat(actualList, is(expectedList));
I'm not sure if this is the cause and if this will fix it, since you use a different JUnit library then I usually do and I'm not sure if these syntax with the Asserts are possible.
I really don't think you actually need hamcrest for this. Wouldn't it be easier to make the asserts in one of the following ways:
A list is still an object at the end of the day:
org.junit.Assert.assertEquals(expected, actual)
An old fashion functionality for lists by using containsAll(..):
org.junit.Assert.assertTrue(expectedItems.containsAll(actualItems))
Using asserts for arrays' equality:
org.junit.Assert.assertArrayEquals(expectedItems.toArray(), actualItems.toArray())
Of course you can use hamcrest as well:
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.containsInAnyOrder(actual.toArray()));
OR
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.contains(actual.toArray()));
You basically asserting that expectedItems is a list with one element and this element is expected to be a list itself with the two items iPhone and skateboard.
To assert that expectedItems and actualItems have the same elements in the same order try this:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
assertThat(actualItems, contains(iPhone, skateboard));
}
And beware that assertThat expects the "actual" object as first parameter and not the "expected".
Alternatively you can do something like that:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(actualItems, contains(expectedItems.toArray(new Item[expectedItems.size()])));
}

Categories

Resources