I have a HashSet and a HashMap of Class. How to modify the class variable?
so I have a class Data, then I create HashSet of Data and HashMap of Data
then do population. later, I would like to modify the value name and number.
class Data {
private String name;
private int number;
public Data(String name, int number) {
this.name = name;
this.number = number;
}
public String toString() {
return name + ":" + number;
}
public void modifyNumber (int i) {
this.number+=i;
} }
public class Main {
public static void main(String[] args) {
Set<Data> dataSet = new LinkedHashSet<Data>();
Map<String, Data> map = new LinkedHashMap<String, Data>();
// I do the dataSet and map population, then do something else
//now I want to modify the value of name and number for HashSet and HashMap of Class
}}
create the getter and setter method for Data class
then get the object and change it
public void setName(String name){
this.name=name;
}
map.get("id").setName("newname");
map.get("id").modifyNumber(number);
To work inside a HashSet, the Data class should override equals and hashcode methods.
Otherwise the set will not operate as expected.
In your implementation you failed to override those methods.
But when you do that, you cannot change the attribute values which are used in equals and hashcode. This may cause the object to be in the wrong hash bucket for its new value.
You can change the other attributes.
hashset.iterator.next().setXXX();
Related
I have a custom class as my key in my hashmap like so
// In the main function
HashMap<Drink, boolean> drinkMap = new HashMap<>();
// What I would like to be able to do:
drinkMap.get("beer");
// My drink Class which is used as the key
public class Drink implements Comparable<String> {
private String name;
private String info;
public String getName() {
return Name;
}
public Drink(String name, String info) {
this.name = name;
this.info = info;
}
}
What I want to do is have the get method for the hashmap compare the string that is passed in to Drink.name and if they are the same then return that hashmap entry, but I cannot figure out how to get this to work.
I tried implementing the equals and hashcode methods in my Drink class like so:
#Override
public int hashCode() {
return Name.hashCode();
}
#Override
public boolean equals(Object o) {
return o instanceof String && o.equals(Name);
}
But when I would do hashMap.get("beer") it kept returning null even though I know there exists a Drink object with the name "beer" in the map.
This is a terrible idea. You should always query a map with the same type (or a subtype thereof) as the intended key. Not doing that only opens you up to problems (as I'm sure you've started to notice).
You should consider either making the key of your map a String type, or querying your map by Drink.
(As to why your specific case isn't working: "beer".equals(drink) != drink.equals("beer").)
I just want to remove duplicate elements from list. To do this I have written a POJO class Student as :
class Student{
private String roll;
private String name;
public Student(String roll, String name) {
this.roll = roll;
this.name = name;
}
#Override
public boolean equals(Object obj) {
Student st = (Student) obj;
return st.getRoll().equals(roll);
}
public String getRoll() {
return roll;
}
public void setRoll(String roll) {
this.roll = roll;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return roll ;
}
}
And a test class as below :
public class TestMain {
public static void main(String[] args) {
List<Student> list = Arrays.asList(
new Student("19", "goutam kumar singh"),
new Student("20", "goutam kumar singh"),
new Student("11", "goutam kumar singh"),
new Student("19", "goutam kumar singh")
);
List<Student> arrayList = new CopyOnWriteArrayList<>(list);
Set<Student> set = new HashSet<>();
for(Student st : arrayList)
set.add(st);
System.out.println(set);
}
}
but in the output all the four elements in the set but i am expecting only three element as fourth element is duplicate and must be removed.
Where I am going wrong?
You have to override the hashCode() method too. Override hashCode() methods for those property for which you override equals() method.
While working with Collection it's useful to remember the contract between hashCode() and equals() method -
1. If two objects are equal, then they must have the same hash code.
2. If two objects have the same hashcode, they may or may not be equal.
For more information you may visit this link
A HashSet stores elements internally as keys in a HashMap. Because of this, it will use your Student object as the keys for that map, using the hash code for each object. Since you don't provide an implementation for this method hashCode(), the default one from Object is used and each of your students will have a different hash code.
You must extend this method in your class, being aware of the equals-hashCode contract. If two objects are equal, they must have the same hashCode (the reverse isn't allways true). For further details see this Object.hashCode()
In Java’s documentation for its class TreeSet one of the constructors is shown to have the following header:
TreeSet(Comparator<? super E> c)
Can someone help explain why there is a constructor for TreeSet which takes a comparator object as its argument? I have no clue why this is done.
All the above answers are correct, but I would like to add that a custom Comparator, apart from resulting in a different sorting, will also filter values differently.
Since Set's values are univocal, if the custom Comparator returns that two values are identical only one of them will appear in the Set:
Set<String> s = new TreeSet<>(new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
return s1.trim().compareTo(s2.trim());
}
});
s.add("1");
s.add(" 1");
s.add("2 ");
s.add("2");
s.add(" 2 ");
Arrays.toString(s.toArray()); // [ "1", "2 "]
The elements in a TreeSet are kept sorted.
If you use a constructor that has no Comparator, the natural ordering of the element class (defined by the implementation of Comparable) would be used to sort the elements of the TreeSet.
If you want a different ordering, you supply a Comparator in the constructor.
This constructor allows you define the Comparator that is used when inserting a T into the tree that is behind the Set.
Comparator<String> comp = (String o1, String o2) -> (o1.compareTo(o2));
Set<String> ts = new TreeSet<>(comp);
You can also use Lambda with Java8
Set<T> s = new TreeSet<>((a, b) -> func(a) - func(b));
The following code shows how to use TreeSet.TreeSet(Comparator <? super E > comparator) constructor.
/**
*Output:
F E D C B A
*/
import java.util.Comparator;
import java.util.TreeSet;
class MyComparator implements Comparator<String> {
public int compare(String a, String b) {
String aStr, bStr;
aStr = a;
bStr = b;
return bStr.compareTo(aStr);
}
// No need to override equals.
}
public class MainClass {
public static void main(String args[]) {
TreeSet<String> ts = new TreeSet<String>(new MyComparator());
ts.add("C");
ts.add("A");
ts.add("B");
ts.add("E");
ts.add("F");
ts.add("D");
for (String element : ts)
System.out.print(element + " ");
System.out.println();
}
}
A TreeSet is a binary search tree, which is based on the notion that given two elements a and b, it is either the case that a is "smaller than" b, or not. However, if you define your own class, the TreeSet doesn't know how to determine whether a given object of that class is "smaller than" another object because it can't know your intended interpretation of the objects' contents. Therefore, you can create a Comparator which can do the comparisons on behalf of the TreeSet.
It's used to sort the elements of the Set according to user-defined rules.
See the javadoc:
public TreeSet(Comparator comparator)
Constructs a new,
empty tree set, sorted according to the specified comparator.
All
elements inserted into the set must be mutually comparable by the
specified comparator: comparator.compare(e1, e2) must not throw a
ClassCastException for any elements e1 and e2 in the set.
If the user
attempts to add an element to the set that violates this constraint,
the add call will throw a ClassCastException.
Parameters:
comparator -
the comparator that will be used to order this set. If null, the
natural ordering of the elements will be used.
See here for more information on natural objects ordering.
Treeset class has the below constructor so that Treeset stores the element using the in the order as described by the Comparator c.Below is an example to illustrate the same.
**Constructor :-**
TreeSet(Comparator<? super E> c)
class Employeee {
public Employeee(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private int id;
private String name;
}
class namecomp implements Comparator<Employeee> {
public int compare(Employeee paramT1, Employeee paramT2) {
if (paramT1.getName().compareTo(paramT2.getName()) > 0)
return -1;
else if (paramT1.getName().compareTo(paramT2.getName()) < 0)
return 1;
else
return 0;
}
}
public class TreeSetImpl {
public static void main(String[] args) {
SortedSet<Employeee> treeSet = new TreeSet<Employeee>(new namecomp());
Employeee e1 = new Employeee(1, "Iftekhar");
Employeee e2 = new Employeee(2, "Khan");
Employeee e3 = new Employeee(3, "Apple");
treeSet.add(e1);
treeSet.add(e2);
treeSet.add(e3);
Iterator<Employeee> it = treeSet.iterator();
while (it.hasNext()) {
System.out.println(it.next().getId());
}
}
}
Here if you see the namecomp is implementing the Comparator interface and thus sorting the elements of the Employeee class in the descending order on the basis of the Name field.
Now the Treeset is implementing the namecomp comparator to store the element in the descending order on the basis of the Name field.
Output
2
1
3
Hope this answers the question.
Comparator interface is used to order the objects of user-defined class.
It provides multiple sorting sequence i.e. you can sort the elements based on any data member. For instance it may be on rollno, name, age or anything else.
By passing a Comparator in TreeSet(Comparator<? super E> c) it means that you can order your TreeSet based on the parameter you desire.
We can say that by passing a Comparator in TreeSet we can order the TreeSet as we desire and not use the natural ordering used by TreeSet.
Suppose you have TreeSet<User> and you have a User class with field id in it.
Now if you want to sort your TreeSet based on User id you can pass a Comparator object in your TreeSet to obtain the desired ordering.
TreeSet with default constructor will sort the element in natural ascending order, but if you want some custom sorting according to your requirement then you should go for the Comparator interface.
eq
This is your default class Employee and you want to sort this class according to salary then.
public class Employee {
private int Id;
private String name;
private int salary;
public Employee(int id, String name, int salary) {
super();
Id = id;
this.name = name;
this.salary = salary;
}
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String toString() {
return "ID : "+Id +" Name : "+name+" Salary : "+salary+"\n";
}
}
Here we have created another class by implementing Comparator.
public class EmpSalaryComparator implements Comparator{
public int compare(Object o1, Object o2) {
Employee e1=(Employee) o1;
Employee e2=(Employee) o2;
return e1.getSalary()-e2.getSalary();
}
}
public class Test1 {
public static void main(String[] args) {
TreeSet t1=new TreeSet(new EmpSalaryComparator());
Employee e1=new Employee(1001, "Ram", 1000);
Employee e2=new Employee(1002, "lucky", 7000);
Employee e3=new Employee(1003, "sumo", 3000);
Employee e4=new Employee(1004, "kharvi", 3000);
Employee e5=new Employee(1005, "priya", 1000);
t1.add(e1);
t1.add(e2);
t1.add(e3);
t1.add(e4);
t1.add(e5);
System.out.println(t1);
}
}
I have a class UserFunction and it have two method getAudioFunction and getPromptFunction with returning String value, my problem is that i want to return both value in one method
how can i able to do that
UserFunction.java
public class UserFunction{
Map<String,PromptBean> promptObject=new HashMap<String,PromptBean>();
Map<String,AudioBean> audioObject = new HashMap<String,AudioBean>();
XmlReaderPrompt xrpObject=new XmlReaderPrompt();
public String getAudioFunction(String audioTag,String langMode )
{
Map<String, AudioBean> audioObject=xrpObject.load_audio(langMode);
AudioBean audioBean=(AudioBean)audioObject.get(audioTag);
String av=StringEscapeUtils.escapeXml(audioBean.getAudio());
return av;
}
public String getPromptFunction(String promptTag,String langMode )
{
Map<String, PromptBean> promptObject=xrpObject.load(langMode);
PromptBean promptBean= (PromptBean)promptObject.get(promptTag);
String pv=StringEscapeUtils.escapeXml(promptBean.getPrompt());
return pv;
}
}
You need to return an object which holds both values. You could create a class for this purpose. The class can have two getter methods for retrieving the values.
It is not possible to return more than one value from a method in java. You can set multiple value into Map or List or create a custom class and can return that object.
public Map<String,String> getAudioAndPromptFunction(String audioTag,String langMode )
{
Map<String,String> map =new HashMap();
...
map.put("audioBean",StringEscapeUtils.escapeXml(audioBean.getAudio()));
map.put("promptBean",StringEscapeUtils.escapeXml(promptBean.getPrompt());
return map;
}
or you can create a custom bean class like.
public class AudioPrompt{
private String audioBean;
private String promptBean;
...
}
public AudioPrompt getAudioAndPromptFunction(String audioTag,String langMode )
{
AudioPrompt audioPrompt =new AudioPrompt();
...
audioPrompt.set(StringEscapeUtils.escapeXml(audioBean.getAudio()));
audioPrompt.set(StringEscapeUtils.escapeXml(promptBean.getPrompt());
return audioPrompt ;
}
You'll need to return an object that includes both of the values. This could be an array with two elements, a Pair<A,B> class (which holds two generic values, typically from some pan-project utility library), or a method-specific class such as:
public class UserFunctionXmlPairing {
public final String audioBeanXml;
public final String promptBeanXml;
}
Create a new class that holds your two strings and return that.
class AudioPromptPair {
private String audio;
private String prompt;
public AudioPromptPair(String audio, String prompt) {
this.audio = audio;
this.prompt = prompt;
}
// add getters and setters
}
You can wrap all the values you wish into a single object and return that:
public class Prompts {
private Map<String, Object> prompts = new HashMap<String, Object>();
public void addPrompt(String name, Object prompt) {
this.prompts.put(name, prompt);
}
public Object getPrompt(String name) {
this.prompts.get(name);
}
}
It's even easier if your AudioBean and PromptBean have a common super class or interface.
My preference would be to lose the "Bean" in your class names. AudioPrompt and TextPrompt would be preferred.
So, I have this class:
public class Product {
private String name, id, info ;
private int quantity;
public Product(String newName, String newID, String newInfo, Integer newQuantity){
setName(newName);
setID(newID);
setPrice(newInfo);
setQuantity(newQuantity);}
public void setName(String name) {
this.name = name; }
public void setID(String id) {
this.id = id; }
public void setPrice(String info) {
this.info = info; }
public void setQuantity(Integer quantity) {
this.quantity = quantity; }
public String getID( ) {
return id; }
public String getName( ) {
return name; }
public String getInfo( ) {
return info; }
public int getQuantity( ) {
return quantity; }
In another class i have this:
public class Invoice implements Group<Product> {
private HashMap<String, Product> prod = new HashMap<String, Product>( );
public Invoice(){ }
public void addProd(Product a) {
prod.put(??getID()??,new Product(??));
}
}
If this data was user generated rather than me, I would use the getID() method right?
So in my class invoice, how do i use the method getID(), so that I can use it in the parameter for my key value in the HashMap? Also is there a way to add 3 values (name info quan) to the hashmap without making a new class?
I see that you get Product object with ref "a" as parameter to your addProd method.
And you can get id by just using a.getID(). It should look as:
public void addProd(Product a) {
prod.put(a.getID(),a);
}
I didn't understand second part of your question.. I think you already have 3 values in your Product object and you put Product object to Map, So why do you require another way ?
Your class Product does not compile, because you have the name Item in your constructor. The constructor name must match the class name. So change that to Product. The same applies to Invoice vs ShoppingCart. Constructor and Class names must match.
As per your comment, you'd like to add four product values to a Map. The key being one of the values of the product itself. Try this:
Product p = new Product(name, id, info, quantity);
cart.addProd(p);
...
public void addProd(Product p) {
prod.put(p.getId(), p);
}
Maps can only map a single value to a single key, so you must have some sort of container for the values you wish to collate into one value. This can be an object (Product) or you could use a collection (e.g. List). I strongly recommend the former.
For your question about putting 3 values in your map, I don't think there's a way for you to put 3 values into one key without creating a class. An alternative is to store a Map<String, List<String>> assuming your 3 values are type String, or, Map<String, Map<String, String>>.