I have a doubt, I want to check if TreeSet in java really uses shallow copy for its clone(), but as per my program if I remove a element from parent treeset, its not reflecting in its cloned treeset object.
public class TreeSetExample {
public static void main(String[] args) {
TreeSet<Name> nameTreeSet = new TreeSet<>();
nameTreeSet.add(new Name("Compiere"));
nameTreeSet.add(new Name("Aristotle"));
nameTreeSet.add(new Name("CompierE"));
nameTreeSet.add(new Name("COmpiere"));
nameTreeSet.add(new Name("ArisTotle"));
nameTreeSet.add(new Name("arisTotle"));
nameTreeSet.add(new Name("aristotle"));
System.out.println(nameTreeSet);
TreeSet<Name> cloneNameTreeSet = (TreeSet<Name>) nameTreeSet.clone();
System.out.println(nameTreeSet);
Iterator<Name> itr = nameTreeSet.iterator();
/*while (itr.hasNext()) {
if (itr.next().getName().equals("aristotle"))
itr.remove();
}*/
for(Name name: nameTreeSet) {
if(name.getName().equals("aristotle"))
nameTreeSet.remove(name);
}
System.out.println(nameTreeSet);
System.out.println(cloneNameTreeSet);
}
}
/*
*Name class which is used in my treeset to store its objects
*/
public class Name implements Cloneable, Comparable<Name>, Comparator<Name> {
#Override
public String toString() {
return "Name [name=" + name + "]";
}
private String name;
public Name(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#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;
Name other = (Name) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
#Override
public int compare(Name name1, Name name2) {
return name1.name.compareTo(name2.name);
}
#Override
public int compareTo(Name name) {
return (this.name).compareTo(name.name);
}
}
if I remove a element from parent treeset, its not reflecting in its cloned treeset object.
You are misunderstanding what shallow copy means. It means that for each element of the TreeSet, the reference is copied to the new TreeSet. So if you mutate one of the Name objects located in one Set, the corresponding element in the other Set will also be mutated, since both refer to the same object.
For example, this will affect both Sets :
for(Name name: nameTreeSet) {
if(name.getName().equals("aristotle"))
name.setName("new name");
}
However, the cloned TreeSet is a different object than the original TreeSet, and removing elements from one doesn't affect the other. Removing elements from one Set would affect the other only if instead of cloning you just copy the reference - TreeSet<Name> cloneNameTreeSet = nameTreeSet;.
Related
I have a list of an Object and I want to detect whether Object Id is duplicate or not.
Here is the object:
public class data{
private String id;
private String value;
private String status;
}
All duplicate data will have "invalid" status except the first one.
What is the most effective way for this?
You could consider overriding the .equals() method of the data class.
Doing so would allow you to do the following to check for duplicate elements:
ArrayList<data> array_list = new ArrayList<data>();
// add some elements to array list
// check for duplicates
for(int i =0; i < array_list.size(); i++){
for(int j=0; j<array_list.size(); j++){
// compare for equality if it is not the same element
if(i != j){
if(array_list.get(i).equals(arrayList.get(j))){
// than we know there is a duplicate at index i,j
System.out.println("duplicate indexes: " + i + ", " + "j");
}
}
}
}
Here is an example of how you would override the .equals method of the data class.
#Override
public boolean equals(Object obj) {
if (!(obj instanceof data)){ return false; }
if (obj == this) { return true; }
// compare strings to see if they are equal
data other_data = (data)obj;
boolean id_equal = other_data.id.equals(this.id);
boolean value_equal = other_data.value.equals(this.value);
boolean status_equal = other_data.status.equals(this.status);
return id_equal && value_equal && status_equal
}
Edit
If you only want to know whether the id's are equal or not you don't need to override .equals() of the data class.
In this case you need only need to use the first loop and compare the id stings instead of the data objects.
So instead of array_list.get(i).equals(arrayList.get(j),
you would do (assuming you have getter methods for the private members of data):
array_list.get(i).get(id).equals(array_list.get(j).get(id));
Alternatively you could use a method similar to the first one and override .equals() to only compare the id strings.
use java ConcurrentHashMap instead of arraylist.
ConcurrentHashMap<yourid, YourBean> chp = new ConcurrentHashMap<>();
chp.putIfAbsent(yourid, YourBean);
and to list all your id do something like this
for (Entry<yourid, YourBean> e : chp.entrySet())
{
YourBean object = (YourBean )chp.get(e.getKey());
//do what u want with your object, guess that helps
}
Try like this first you should override equals method to check duplicates
private class data{
private String id;
private String value;
private String status;
public data(String id, String value, String status) {
this.id = id;
this.value = value;
this.status = status;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#Override
public String toString() {
return "data{" +
"id='" + id + '\'' +
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof data)) return false;
data data = (data) o;
return !(id != null ? !id.equals(data.id) : data.id != null);
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
Then test like this
public class Test {
public static void main(String[] args ) {
List<data> dataList=new ArrayList<>();
dataList.add(new data("1","somevalue","somestatus"));
dataList.add(new data("1","somevalue","somestatus"));
dataList.add(new data("1","somevalue","somestatus"));
dataList.add(new data("2","somevalue","somestatus"));
dataList.add(new data("3","somevalue","somestatus"));
List<data>validList=new ArrayList<>();
List<data>duplicateList=new ArrayList<>();
for (data data:dataList){
if (!(validList.contains(data))){
validList.add(data);
System.out.println(validList);
}else{
duplicateList.add(data);
System.out.println(duplicateList);
}
}
}
Make a list of the id of objects. Loop over the list of objects. See if the id of each object is already in the list. If the id is already present, then change the status of the object. Otherwise, add the id of the object to the list.
I got two "lists" of objects, which i want to compare if elements are equal. If they are not equal, the loop should take the not equal object and put it into the other list. Very simple. My problem is: the equals method doesnt work as intended.
Here is the object Class with my custom equals method:
public class Profil {
private String vorname;
private String name;
private String adLoginBenutzer;
public Profil() {
}
public String getAdLoginBenutzer() {
return adLoginBenutzer;
}
public void setAdLoginBenutzer(String adLoginBenutzer) {
this.adLoginBenutzer = adLoginBenutzer;
}
public String getVorname() {
return vorname;
}
public void setVorname(String vorname) {
this.vorname = vorname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
if (name == null || vorname == null) {
return "<keiner>";
}
return vorname + ", " + name + " " + adLoginBenutzer;
}
#Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass()) {
return false;
}
Profil other = (Profil)obj;
if(!this.getVorname().equals(other.getVorname()) || !this.getName().equals(other.getName()) || !this.getAdLoginBenutzer().equals(other.getAdLoginBenutzer()))
{
return false;
}
return true;
}
}
And here is the loop: (note: I basically want to merge the list into a comboboxmodel, if the profil-object is not equal than it should add it to the first position in the comboboxmodel)
public void putProfilesIntoCbx(HashSet<Profil> profile)
{
DefaultComboBoxModel<Profil> cbx = (DefaultComboBoxModel <Profil>)cbBearbeiter.getModel();
for(Profil p : profile)
{
for(int i = 0; i< cbx.getSize(); i++)
{
if(!p.equals(cbx.getElementAt(i)))
{
cbx.insertElementAt(p, 0);
}
}
}
cbBearbeiter.setModel(cbx);
}
I debugged the code and took breakpoints at the last if of the equals method. Although there are equal objects, the last if return false for no reason even if the objects are really equal. Even if i invert the equals if-statement it does not work.
As everyone is saying, there is a relationship between the equals() method and the hashcode() method.
If you #Override the equals() method, you need to #Override the hashcode() method as well
I created my own linkedlist. I wanted to sort my linkedlist using Collections.sort method.
So I extends MyLinkedList class to java.util.LinkedList. I also created Comparator and Comparable implementation. But both are not working. Please find below code.
// Linked List implementation.
package com.java.dsa;
class Node<E> {
E data;
Node<E> nextLink;
public Node(E data) {
this.data = data;
}
}
public class MyLinkedList<E> extends java.util.LinkedList<E>{
private static final long serialVersionUID = 1L;
private Node<E> firstNodePointer;
private Node<E> nodePointer;
public boolean isEmpty() {
return nodePointer == null;
}
public boolean add(E data) {
super.add(data);
Node<E> node = new Node<E>(data);
if (firstNodePointer == null) {
firstNodePointer = node;
nodePointer = node;
}else{
nodePointer.nextLink = node;
}
nodePointer = node;
return true;
}
public boolean remove(Object data){
super.remove(data);
Node<E> counterNodePointer = firstNodePointer;
Node<E> tempNodePointer = firstNodePointer;
while (counterNodePointer != null && !counterNodePointer.data.equals(data)) {
tempNodePointer = counterNodePointer;
counterNodePointer = counterNodePointer.nextLink;
}
if(tempNodePointer.equals(firstNodePointer)){
firstNodePointer = firstNodePointer.nextLink;
return true;
}
else if(counterNodePointer != null && tempNodePointer != null){
tempNodePointer.nextLink = counterNodePointer.nextLink;
return true;
}
return false;
}
public void printList() {
Node<E> counterNodePointer = firstNodePointer;
while (counterNodePointer != null) {
System.out.println(counterNodePointer.data);
counterNodePointer = counterNodePointer.nextLink;
}
}
}
// Test Linkedlist
package com.java.dsa;
import java.util.Collections;
import java.util.Comparator;
//Employee Class
class Employee implements Comparable<Employee> {
private String name;
private int id;
public Employee(String name, int id) {
super();
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
#Override
public String toString() {
return this.name + " " + this.id;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
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;
Employee other = (Employee) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
#Override
public int compareTo(Employee employee) {
return this.id - employee.id;
}
}
class EmployeeSort implements Comparator<Employee> {
#Override
public int compare(Employee emp1, Employee emp2) {
if (emp2.getId() - emp1.getId() > 0)
return 1;
else
return -1;
}
}
public class TestLinkedList {
public static void main(String[] args) {
MyLinkedList<Employee> myList = new MyLinkedList<Employee>();
for (int i = 10; i > 0; i--) {
Employee emp = new Employee("Sohan "+i, i);
myList.add(emp);
}
myList.printList();
Collections.sort(myList, new EmployeeSort());
myList.printList();
}
}
Actually it works. It's just that your internal data structure is not updated by Collections.sort(), and since you base your assertion that the program doesn't work on the output of printList(), and this relies on that data structure, you see the order of elements untouched. Use this method instead:
public void printParentDataStructure() {
for ( E e : this ) System.out.println( e );
}
and see that your comparator perfectly does its job. So your problem is that you have two data structures and don't keep them in sync. Your next question may be "And how can I keep them sync'ed?" - Well, essentially you should override each and every method, and call super() like you do in add() and remove(). Don't do that! It'd be a complete nonsense.
It's clear that you want to implement a linked list for learning the data strcuture, but maybe you should first better understand the basic principles of OOP programming.
java.util.LinkedList is not a class designed for subclassing and your code is probably just breaking its internals and invariants.
If you want to implement a linked list on your own, but want to save yourself the effort of implementing the full List interface, then use AbstractList as your base class. This class's express purpose is exactly what you are trying to do.
I have an array list of objects which contains eg:
Name
Address
Phone
Many other properties...
I wish to remove some objects in this list, if some of the properties has the same value as other objects in the array list. I need to loop though the whole list and see if the Name, Address and Phone already exists in this list. I can not do a simple:
for (...)
if (!newlist.contains(element)) { newlist.add(element); }
As I only need to check specific properties are the same before adding the element to a new list.
Can anyone guide me in the right direction?
How about using Set with a custom Comparator ? Have your object class implement Comparable. In the compare method you can then write your test to match the objects exactly how you need it.
Create a Key Class let us say Employee.java with below code.
package com.innovation;
public class Employee {
private String name;
private String address;
private String phone;
public Employee() {
super();
}
public Employee(String name, String address, String phone) {
super();
this.name = name;
this.address = address;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((phone == null) ? 0 : phone.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;
Employee other = (Employee) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (phone == null) {
if (other.phone != null)
return false;
} else if (!phone.equals(other.phone))
return false;
return true;
}
#Override
public String toString() {
return "Employee [name=" + name + ", address=" + address + ", phone="
+ phone + "]";
}
}
Now create a Client class where you want to apply your logic let us assume a class containing main method say Client.java
package com.innovation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Client {
public static void main(String[] args) {
Set<Employee> empSet = new HashSet<Employee>(populateList());
for (Employee employee : empSet)
{
System.out.println(employee);
}
}
public static List<Employee> populateList()
{
List<Employee> lsts = new ArrayList<Employee>();
lsts.add(new Employee("rais","gurgaon","123456"));
lsts.add(new Employee("alam","Delhi","123685"));
lsts.add(new Employee("shyam","Mumbai","1257456"));
lsts.add(new Employee("ramesh","Ahmadabad","196356"));
lsts.add(new Employee("rais","gurgaon","123456"));
lsts.add(new Employee("rais","gurgaon","123456"));
lsts.add(new Employee("rais","gurgaon","123456"));
return lsts;
}
}
You will see below out put. it is clearly visible that duplicate entry present in list is removed in set. it all magic of good implementation of equals and hashcode method.
Employee [name=rais, address=gurgaon, phone=123456]
Employee [name=ramesh, address=Ahmadabad, phone=196356]
Employee [name=alam, address=Delhi, phone=123685]
Employee [name=shyam, address=Mumbai, phone=1257456]
I'm looking for a suggestion.
I have a Person class with String firstName and String lastName
When i'm tying to insert the list values with the same String like :
set.add(new Person("firstName","lastName"))
set.add(new Person("firstName","lastName"))
The set doesn`t filter the objects and they still getting in the set.
There is any suggestion to create set list without overriding the equales and hashcode functions?
Maybe with guava or some groovy list?
Thanks,
Or.
In Guava there's an Equivalence class designed to such things. Create your own Equivalence class like this one:
import com.google.common.base.Equivalence;
import com.google.common.base.Objects;
public class PersonEquivalence extends Equivalence<Person> {
#Override
protected boolean doEquivalent(Person p1, Person p2) {
return Objects.equal(p1.getFistName(), p2.getFistName())
&& Objects.equal(p1.getLastName(), p2.getLastName());
}
#Override
protected int doHash(Person person) {
return Objects.hashCode(person.getFistName(), person.getLastName());
}
}
And then this code
Set<Equivalence.Wrapper<Person>> set = Sets.newHashSet();
PersonEquivalence personEquivalence = new PersonEquivalence();
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Jane", "Doe")));
System.out.println(set);
prints
[PersonEquivalence#8813f2.wrap(Person{firstName=Jane, lastName=Doe}),
PersonEquivalence#8813f2.wrap(Person{firstName=Joe, lastName=Doe})]
Of course it's a bit verbose, but you can create ForwardingSet to automatically wrap and unwrap Persons for you.
You can create a TreeSet with your own Comparator.
Set<Person> set = new TreeSet<Person>(new Comparator<Person>() {
#Override
public int compare(Person p1, Person p2) {
// Your own compare logic
}
});
You can't, without violating the contract of Set. Either don't use a Set, or wrap the Person in another class that implements equals and hashcode based on the inner Person (see the other answer for a way to do this in Guava).
Here's a rough attempt at my map suggestion.
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class PeopleCarrier implements Iterable<Person>{
private Map<PersonKey, Person> storage = new HashMap<PersonKey, Person>();
public void add(Person p) {
PersonKey pk = new PersonKey(p);
storage.put(pk, p);
}
public boolean contains(Person p) {
return storage.containsKey(new PersonKey(p));
}
#Override
public Iterator<Person> iterator() {
return new Iterator<Person>() {
private Iterator<PersonKey> i = storage.keySet().iterator();
#Override
public void remove() {
throw new UnsupportedOperationException();
}
#Override
public Person next() {
return storage.get(i.next());
}
#Override
public boolean hasNext() {
return i.hasNext();
}
};
}
private class PersonKey {
private String firstname;
private String lastname;
public PersonKey(Person p) {
this.firstname = p.getFirstname();
this.lastname = p.getLastname();
}
/* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result
+ ((firstname == null) ? 0 : firstname.hashCode());
result = prime * result
+ ((lastname == null) ? 0 : lastname.hashCode());
return result;
}
/* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof PersonKey))
return false;
PersonKey other = (PersonKey) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (firstname == null) {
if (other.firstname != null)
return false;
} else if (!firstname.equals(other.firstname))
return false;
if (lastname == null) {
if (other.lastname != null)
return false;
} else if (!lastname.equals(other.lastname))
return false;
return true;
}
private PeopleCarrier getOuterType() {
return PeopleCarrier.this;
}
}
}