I want to find a LegalEntity object in an ArrayList. The object can possibly be a different instance. I'm only interested in whether they represent the same value, i.e. they have the same primary key. All LegalEntity instances are created from database values by EJB:
List<LegalEntity> allLegalEntities = myEJB.getLegalEntityfindAll());
LegalEntity currentLegalEntity = myEJB.getLegalEntityfindById(123L);
My first naive idea never finds matches:
if (allLegalEntities.contains(currentLegalEntity)) {
}
I then thought that perhaps I need to create my own equals() method:
public boolean equals(LegalEntity other) {
return legalEntityId.equals(other.legalEntityId);
}
But this method is not even being invoked. Is there a way to find an object in a list that doesn't involve looping?
I'm learning Java so it might easily be some foolish misunderstanding on my side.
Your approach is correct, but you need to override the method equals that accepts an Object:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LegalEntity other = (LegalEntity) obj;
// check if equals based one some properties
}
However you also need to override hashCode:
#Override
public int hashCode() {
// return a unique int
}
So this might not be the easiest solution.
Another approach is to use filter:
LegalEntity myLegalEntity = myEJB.getLegalEntityfindAll().stream()
.filter(legalEntity -> legalEntity.getProperty().equals("someting"))
.findAny()
.orElse(null);
More info here
If you're using Java 8 you can use streams:
List<LegalEntity> allLegalEntities = myEJB.getLegalEntityfindAll());
LegalEntity currentLegalEntity = allLegalEntities.stream().filter(entity -> entity.getId() == 123L).findFirst();
Related
This question ask many times in stackoverflow and i tried all masters answers.
But list.contain() return always false.
and also overide equal() method.
Here is my pojo class
public class RecentStickerPojo
{
File stickerName;
File folderName;
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RecentStickerPojo other = (RecentStickerPojo) obj;
if (folderName != other.folderName&&stickerName!=other.stickerName)
return false;
return true;
}
}
in activity class
RecentStickerPojo recentStickerPojo=new RecentStickerPojo();
recentStickerPojo.setStickerName(s1);
recentStickerPojo.setFolderName(f1);
list.contains(recentStickerPojo) // return false
Don't forget to implement hashcode.
For strings, use equals (or !equals) and not == (or !=)
Also the equals' last 3 lines can be changed to:
return (folderName.equals(other.folderName) && stickerName.equals( other.stickerName);
No need to override hashcode, as List contains method will use equals method for comparing object. It seems you are comparing File objects directly which can be different. Yes, try by changing last comparison,
if (folderName.equals(other.folderName) && stickerName.equals(other.stickerName))
i am trying to test singly linked list using Assert.assertEqual(expected, actual) the linked list has a node index and a value. how can i use Assert.assertEquals() to test it.
This is my code
#Test
void nonEmptyTest() throws ListAccessError {
SingleLinkedList<Integer> list = new SingleLinkedList<Integer>();
SingleLinkedList<Integer> expList = new SingleLinkedList<Integer>();
list.add(0,10);
list.add(1,20);
list.add(2,30);
expList.add(0,10);
expList.add(1,20);
expList.add(2,30);
Assert.assertEquals(expList, list);
}
You need to override boolean equals(Object obj) method for you to expect the assert on the actual values of the list.
Here's a sample on how to override
(Note: I don't know your implementation of SingleLinkedList, you can get an idea from the following code and implement accordingly)
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
SingleLinkedList<Integer> listToCompare = (SingleLinkedList<Integer>) obj;
SingleLinkedList<Integer> thisList = this;
while (listToCompare != null && thisList != null) {
if (!listToCompare.getData().equals(thisList.getData()))
return false;
listToCompare = listToCompare.getNext();
thisList = thisList.getNext();
}
if (listToCompare == null && thisList == null)
return true;
return false;
}
If you want to compare two different objects to find out whether they're equal, your class that defines those objects generally needs to implement the equals() method. Otherwise Java has no way to know what 'equality' is supposed to mean.
That is, your problem is not in the unit test, it's in the class being tested. The
unit test did its job :-)
Consider that I would like to create a class which manages a TreeSet of custom objects with two keys: A String instance identifier, and a long order identifier. The Long value would be used to determine the order of the elements in the list, while the string would be used to determine if two of these elements are duplicates. To clarify, here is what the methods would look like for the custom object
#Override
public boolean equals(Object o) {
if(o == null)
return false;
if(!(o instanceof CustomObject))
return false;
//Determined by string_id values ONLY. Used in TreeSet implementation
CustomObject obj = (CustomObject) o;
return obj.string_id.equals(this.string_id);
}
#Override
public int compareTo(Object another) {
if(another == null || !(another instanceof CustomObject))
return -1;
CustomObject other = (CustomObject) another;
if(other.long_id > this.long_id)
return -1;
else if(other.long_id < this.long_id)
return 1;
else
return 0;
}
Can my TreeSet function this way? I ask, because while testing this, I've found that my implementation only keeps the latest entry, and discards the rest. I'm looking to find out if this is simply an error with my implementation, or if I'm not properly using the TreeSet class and need to refactor my approach.
I have 2 classes.
public class klass1 {
String bir;
String myID;
klass1(String bir, String myID)
{
this.bir=bir;
this.myID=myID;
}
}
.
import java.util.*;
public class dd {
public static void main(String[] args) {
ArrayList<Object> ar=new ArrayList();
ar.add(new klass1("wer","32"));
ar.add(new klass1("das","23"));
ar.add(new klass1("vz","45"));
ar.add(new klass1("yte","12"));
ar.add(new klass1("rwwer","43"));
ar.remove(new klass1("vz","45"));//it's not worked!!!
System.out.println(ar.size());
}
}
What I want is removing or getting an object from array list with object's second attribute. How can I do that? Is there an easy way for it?
Just implement the equals method in the class Klass1.
public class Klass1 {
String bir;
String myID;
Klass1(String bir, String myID)
{
this.bir=bir;
this.myID=myID;
}
public boolean equals(Object o){
if(o instanceof Klass1)
return ((Klass1)o).myID.equals(myID);
else
return false;
}
}
Its because you are trying to delete a new object which isnt in the arraylist. When you use new klass1("vz","45") you are creating a new instance of this class which isnt in the arraylist.
What the system does internally is to compare those classes using equals. Why this doesn't work is explained in the following code:
Object o1 = new Object();
Object o2 = new Object();
System.out.println(o1 == o2); // false, obviously
System.out.println(o1.equals(o2)); // false
System.out.println(o1); // java.lang.Object#17046822
System.out.println(o2); // java.lang.Object#22509bfc
You can tell by the number following the # that these objects have a different hash values, and this is what the equals function of Object does check.
This is relevant for your klass, because unless you overwrite equals, you will use the equals of Object. And if you implement equals you should always implement hashcode as well. Because both tell you something about whether or not two objects are the "same", and if the one says something else than the other, some part of your code might get confused.
How to properly implement equals for your class:
#Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + Objects.hashCode(this.bir);
hash = 17 * hash + Objects.hashCode(this.myID);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final klass1 other = (klass1) obj;
if (!Objects.equals(this.bir, other.bir)) {
return false;
}
if (!Objects.equals(this.myID, other.myID)) {
return false;
}
return true;
}
This can be done in most IDEs btw with a shortcut (i.E. alt-insert in Netbeans). Note that I did this in Java 7 using Objects. If you are in Java 6, you need to manually type(a == b) || (a != null && a.equals(b)); with the appropriate objects to compare.
Creating a proper hashcode is not always trivial, for more complex objects you might want to read a bit about hashcodes first. For simple objects: multiply primes with something.
The equals method is usually trivial, it is just important to first check for null and for class equality. This is often forgotten by programmers and a common source for NullPointerExceptions and ClassCastExceptions.
Problem Statement
I have two Collections of the same type of object that I want to compare. In this case, I want to compare them based on an attribute that does not factor into equals() for the Objects. In my example, I'm using ranked collections of Names for instance:
public class Name {
private String name;
private int weightedRank;
//getters & setters
#Override
public boolean equals(Object obj) {
return this.name.equals(obj.name); //Naive implementation just to show
//equals is based on the name field.
}
}
I want to compare the two Collections to assert that, for position i in each Collection, the weightedRank of each Name at that position is the same value. I did some Googling but didn't find a suitable method in Commons Collections or any other API so I came up with the following:
public <T> boolean comparatorEquals(Collection<T> col1, Collection<T> col2,
Comparator<T> c)
{
if (col1 == null)
return col2 == null;
if (col2 == null)
return false;
if (col1.size() != col2.size())
return false;
Iterator<T> i1 = col1.iterator(), i2 = col2.iterator();
while(i1.hasNext() && i2.hasNext()) {
if (c.compare(i1.next(), i2.next()) != 0) {
return false;
}
}
return true;
}
Question
Is there another way to do this? Did I miss an obvious method from Commons Collections?
Related
I also spotted this question on SO which is similar though in that case I'm thinking overriding equals() makes a little more sense.
Edit
Something very similar to this will be going into a release of Apache Commons Collections in the near future (at the time of this writing). See https://issues.apache.org/jira/browse/COLLECTIONS-446.
You could use the Guava Equivalence class in order to decouple the notions of "comparing" and "equivalence". You would still have to write your comparing method (AFAIK Guava does not have it) that accepts an Equivalence subclass instead of the Comparator, but at least your code would be less confusing, and you could compare your collections based on any equivalence criteria.
Using a collection of equivance-wrapped objects (see the wrap method in Equivalence) would be similar to the Adapter-based solution proposed by sharakan, but the equivalence implementation would be decoupled from the adapter implementation, allowing you to easily use multiple Equivalence criteria.
You can use new isEqualCollection method added to CollectionUtils since version 4. This method uses external comparsion mechanism provided by Equator interface implementation. Please, check this javadocs: CollectionUtils.isEqualCollection(...) and Equator.
I'm not sure this way is actually better, but it is "another way"...
Take your original two collections, and create new ones containing an Adapter for each base object. The Adapter should have .equals() and .hashCode() implemented as being based on Name.calculateWeightedRank(). Then you can use normal Collection equality to compare the collections of Adapters.
* Edit *
Using Eclipse's standard hashCode/equals generation for the Adapter. Your code would just call adaptCollection on each of your base collections, then List.equals() the two results.
public class Adapter {
public List<Adapter> adaptCollection(List<Name> names) {
List<Adapter> adapters = new ArrayList<Adapter>(names.size());
for (Name name : names) {
adapters.add(new Adapter(name));
}
return adapters;
}
private final int name;
public Adapter(Name name) {
this.name = name.getWeightedResult();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + name;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Adapter other = (Adapter) obj;
if (name != other.name)
return false;
return true;
}
}
EDIT: Removed old answer.
Another option that you have is creating an interface called Weighted that could look like this:
public interface Weighted {
int getWeightedRank();
}
Then have your Name class implement this interface. Then you could change your method to look like this:
public <T extends Weighted> boolean weightedEquals(Collection<T> col1, Collection<T> col2)
{
if (col1 == null)
return col2 == null;
if (col2 == null)
return false;
if (col1.size() != col2.size())
return false;
Iterator<T> i1 = col1.iterator(), i2 = col2.iterator();
while(i1.hasNext() && i2.hasNext()) {
if (i1.next().getWeightedRank() != i2.next().getWeightedRank()) {
return false;
}
}
return true;
}
Then as you find additional classes that need to be weighted and compared you can put them in your collection and they could be compared with each other as well. Just an idea.