I want to do a backup copy of a Map (that contains other Maps).
I have something like this:
Map<TYPE1, Map<TYPE2, TYPE3>>
TYPE1, TYPE2 and TYPE3 are objects from 3 different classes created by me (e.g the components of that classes are: String, Integer, Double,....)
I tried
Map<TYPE1, Map<TYPE2, TYPE3>> Map2= new HashMap<TYPE1, Map<TYPE2, TYPE3>>(Map1)
[....make some changings in Map1...]
Map1 = new HashMap<TYPE1, Map<TYPE2, TYPE3>>(Map2)
Map1 is the original Map I want to make a copy of.
I also tried PutAll method but it didn't work (the content of the Map isn't the same of the original one).
Do you know other methods? Thank you.
Since the key and value in your collection are your self define class.
Those content int the map are not really copied but share the same instance of your "TYPE".
You need to do something like this to copy the value from all the content.
This is just a very simple example, so there's no any encapsulation.
public class Foo1 {
public Integer a = 0;
public Foo1() {
}
public Foo1(Integer a) {
this.a = a;
}
public Foo1 clone() {
return new Foo1();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((a == null) ? 0 : a.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;
Foo1 other = (Foo1) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (a == null) {
if (other.a != null)
return false;
} else if (!a.equals(other.a))
return false;
return true;
}
}
public class Foo2 {
public Integer a = 0;
public Foo2() {
}
public Foo2(Integer a) {
this.a = a;
}
public Foo2 clone() {
return new Foo2();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((a == null) ? 0 : a.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;
Foo1 other = (Foo1) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (a == null) {
if (other.a != null)
return false;
} else if (!a.equals(other.a))
return false;
return true;
}
}
public class Foo3 {
public Integer a = 0;
public Foo3() {
}
public Foo3(Integer a) {
this.a = a;
}
public Foo3 clone() {
return new Foo3();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((a == null) ? 0 : a.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;
Foo1 other = (Foo1) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (a == null) {
if (other.a != null)
return false;
} else if (!a.equals(other.a))
return false;
return true;
}
}
Copy your value by your own.
Map<Foo1, Map<Foo2, Foo3>> map1 = new HashMap<Foo1, Map<Foo2, Foo3>>();
Map<Foo1, Map<Foo2, Foo3>> map2 = new HashMap<Foo1, Map<Foo2, Foo3>>();
Map<Foo2, Foo3> tmp = new HashMap<Foo2, Foo3>();
tmp.put(foo.new Foo2(), foo.new Foo3());
map1.put(foo.new Foo1(), tmp);
for (Foo1 key : map1.keySet()) {
Map<Foo2, Foo3> tmp2 = new HashMap<>();
for (Foo2 key2 : map1.get(key).keySet()) {
tmp2.put(key2.clone(), map1.get(key).get(key2).clone());
}
map2.put(key, tmp2);
}
for (Foo1 key : map1.keySet()) {
for (Foo2 key2 : map1.get(key).keySet()) {
map1.get(key).get(key2).a = 10;//change map1's value
}
}
for (Foo1 key : map2.keySet()) {
for (Foo2 key2 : map2.get(key).keySet()) {
System.out.println(map2.get(key).get(key2).a);// the value in map2 still 0
}
}
very interesting article about deep copy:
How do you make a deep copy of an object in Java?
with serialization/deserialization, you dont need to go inside your classes,
and you dont forget some variable.
it gives:
Map<Integer, Map<String,String>> mimss =new HashMap<Integer, Map<String,String>>();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(mimss);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
Map<Integer, Map<String,String>> mimss_copy=(Map<Integer, Map<String,String>>) new ObjectInputStream(bais).readObject();
You can also convert to B64 in the middle if you want to save it in text:
String serial= DatatypeConverter.printBase64Binary(byteData);
byte[] byteData_reverse=DatatypeConverter.parseBase64Binary(serial);
REQUIREMENT: TYPE1, TYPE2, TYPE3 must be serializable
to be serializable, your class must be like that
public class myclass implements Serializable
and you should (not mandatory) declare inside
private static final long serialVersionUID = 6569838532917408380L;
If anything inside in serializable too, it's OK (standard types are, collections, ...)
Related
I would like to know how to sort Apache Commons MultiValuedMap by Key. The below is the key class used.
public class VssKey implements Comparable<VssKey> {
private String funCode;
private String varntCode;
private String itemNb;
public VssKey(SummaryDataOracle summaryDataOracle) {
this.funCode = summaryDataOracle.getFuncCode();
this.varntCode = summaryDataOracle.getVariantCd();
this.itemNb = summaryDataOracle.getItemNB();
}
public String getFunCode() {
return funCode;
}
public void setFunCode(String funCode) {
this.funCode = funCode;
}
public String getVarntCode() {
return varntCode;
}
public void setVarntCode(String varntCode) {
this.varntCode = varntCode;
}
public String getItemNb() {
return itemNb;
}
public void setItemNb(String itemNb) {
this.itemNb = itemNb;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((funCode == null) ? 0 : funCode.hashCode());
result = prime * result + ((itemNb == null) ? 0 : itemNb.hashCode());
result = prime * result + ((varntCode == null) ? 0 : varntCode.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;
VssKey other = (VssKey)obj;
if (funCode == null) {
if (other.funCode != null)
return false;
} else if (!funCode.equals(other.funCode))
return false;
if (itemNb == null) {
if (other.itemNb != null)
return false;
} else if (!itemNb.equals(other.itemNb))
return false;
if (varntCode == null) {
if (other.varntCode != null)
return false;
} else if (!varntCode.equals(other.varntCode))
return false;
return true;
}
#Override
public String toString() {
return String.format("VssKey [funCode=%s, varntCode=%s, itemNb=%s]", funCode, varntCode, itemNb);
}
#Override
public int compareTo(VssKey o) {
int k1 = Integer.parseInt(this.varntCode);
int k2 = Integer.parseInt(o.getVarntCode());
return k2 - k1;
}
}
The below map is constructed by iterating SummerDataOracle values. The values are pushed into the map by VssKey object as shown below.
MultiValuedMap<VssKey, String> partNumberVarientMap = new ArrayListValuedHashMap<>();
for (SummaryDataOracle summaryDataOracle : summeryDataOracleList) {
VssKey key = new VssKey(summaryDataOracle);
String varntText = null;
if (!StringUtils.isEmpty(summaryDataOracle.getVariantSmText())) {
varntText = summaryDataOracle.getVariantSmText().trim();
}
partNumberVarientMap.put(key, varntText);
}
I need to achieve the order in the Map.
Thanks
HashMap/MultivaluedHashMap cannot be sorted directly.
Better, to get its key and sort them and parse map in sorted order.
Map<String, List<String>> map = new MultivaluedHashMap<>();
map.put("b", new ArrayList<>());
map.put("a", new ArrayList<>());
List<String> keylist = new ArrayList<>(map.keySet());
Collections.sort(keylist);
for(String key : keylist) {
System.out.println(key + " : " + map.get(key));
}
By design, you can't sort a HashMap. If you need to keep a specific order in your map, it is recommended to use a Map implementation like TreeMap.
What you can do if you want to iterate over a HashMap in a specific order, is getting the keys and sort them. Then you can iterate over the keys and lookup your values accordingly:
HashMap<String, List<String>> map = new HashMap<>();
for(String key : new TreeSet<String>(map.keySet())){
map.get(key);
}
I have some entity class
class Data{
private String quoteID;
private String bidOrOffer;
private float price;
private long volume;
private Date createDate;
public Data(String quoteID, String bidOrOffer, float price, long volume) {
this.quoteID = quoteID;
this.bidOrOffer = bidOrOffer;
this.price = price;
this.volume = volume;
createDate = new Date();
}
#Override
public int hashCode() {
int hash = 5;
hash = 13 * hash + Objects.hashCode(this.quoteID);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Data other = (Data) obj;
if (!Objects.equals(this.quoteID, other.quoteID)) {
return false;
}
return true;
}
}
and I push some elements into TreeSet whit special order
Comparator<Data> offerOrder = (Data o1, Data o2) -> {
if(o1.equals(o2))
return 0;
if(o1.getPrice() == o2.getPrice()
&& o1.getVolume() == o2.getVolume()){
return o1.getCreateDate().after(o2.getCreateDate())? 1:-1;
}
if(o1.getPrice() == o2.getPrice()){
return o1.getVolume() > o2.getVolume()? 1:-1;
}
if(o1.getPrice() > o2.getPrice())
return 1;
else
return -1;
};
Set<Data> treeSet = new TreeSet<>(offerOrder);
treeSet.add(new Data("Q1", "OFFER", 1.32f, 1000000));
treeSet.add(new Data("Q6", "OFFER", 1.32f, 1000000));
treeSet.add(new Data("Q7", "OFFER", 1.33f, 200000));
The main goal of this task it is remove and update some data by quoteID
but if I do this
treeSet.contains(new Data("Q7", "OFFER", 0, 0)); //return false
thereafter method remove doesn't work too.
Any ideas?
While inserting "Q7" the comparator returns 1 in compare to "Q1".
If you now want to remove "Q7" with new Data("Q7", "OFFER", 0, 0) the comparator returns -1.
So the child of the "wrong" path of the tree compared next.
treeSet.contains(new Data("Q7", "OFFER", 2, 0)) would return true (compare to "Q1" returns 1).
You should take care of change the implementation of your Comparator<Data> offerOrder because that implementation does not permit to find the object you're looking for with treeSet.contains.
For example in your case:
Comparator<Data> offerOrder = (Data o1, Data o2) -> {
return o1.quoteID.compareTo(o2.quoteID);
};
And then returns true:
treeSet.contains(new Data("Q7", "OFFER", 0, 0)); //return true
There is also an error in your equals method:
final Quote other = (Quote) obj;
if (!Objects.equals(this.quoteID, other.quoteID)) {
return false;
}
You should use:
if (!this.quoteID.equals(other.quoteID)) {
return false;
}
And given that quoteID is a String is not clear what is the Quote class.
I suggest to change use hashCode and equals methods in this way:
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((quoteID == null) ? 0 : quoteID.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;
Data other = (Data) obj;
if (quoteID == null) {
if (other.quoteID != null)
return false;
} else if (!quoteID.equals(other.quoteID))
return false;
return true;
}
You cannot search "quoteID" as is inside Data object. You have to iterate each Data object and match for "quoteID".
Iterator<Data> iterator = treeSet.iterator();
while(iterator.hasNext()){
Data dataobj = iterator.next();
String qID = dataobj.quoteID;
if(qID.equals("Q7")){
//write your code.
}
}
I have a class X:
public class X implements Cloneable {
private int a;
private int b;
#Override
public X clone() throws CloneNotSupportedException {
return (X) super.clone();
}
}
I want to remember its initial state. Therefore get his clone:
try {
old = new X();
old = x.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
x - an object of class X, a and b installed.
For example i do with old:
old.setA(7)
How do I now compare the old and the new object, find out whether there were changes. I do so but does not work:
//if object is changed
if (!old.equals(x)){
}
How to check the object has changed or not?
Add below code in your X class
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + a;
result = prime * result + b;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
X other = (X) obj;
if (a != other.a)
return false;
if (b != other.b)
return false;
return true;
}
public boolean equals(Object object2) {
return object2 instanceof MyClass && a.equals(((MyClass)object2).a);
}
So, I have this code written in Java:
import java.util.HashSet;
class Interval{
long from;
long to;
public Interval(long from, long to) {
this.from = from;
this.to = to;
}
public boolean equals(Interval other) {
return from == other.from && to == other.to;
}
}
public class Test {
public static void main(String[] args) {
HashSet<Interval> mySet = new HashSet<Interval>();
mySet.add(new Interval(1,2));
mySet.add(new Interval(1,2));
for(Interval in : mySet) {
System.out.println(in.from + " " + in.to);
}
}
}
The problem is that the set doesn't recognize that there is already an interval from 1 to 2. I defined the function equals, but still it doesn't work. I tried implementing the Comparable interface and overloading the compareTo function, but again nothing. Can somebody tell me how can I solve this problem?
Thank you!
You need to override equals from java.lang.Object.
You did not as yours does not accept Object as parameter.
public boolean equals(Object obj) {
if (obj == null)
return false;
else if (this.getClass() != obj.getClass())
return false;
else {
Interval other = (Interval) obj;
return from == other.from && to == other.to;
}
}
For hashCode, you can do this for example.
public int hashCode() {
return new Long(this.from).hashCode();
}
So overall you get this code.
import java.util.HashSet;
class Interval {
long from;
long to;
public Interval(long from, long to) {
this.from = from;
this.to = to;
}
public boolean equals(Object obj) {
if (obj == null)
return false;
else if (this.getClass() != obj.getClass())
return false;
else {
Interval other = (Interval) obj;
return from == other.from && to == other.to;
}
}
public int hashCode() {
return new Long(this.from).hashCode();
}
}
public class Test003 {
public static void main(String[] args) {
HashSet<Interval> mySet = new HashSet<Interval>();
mySet.add(new Interval(1, 2));
mySet.add(new Interval2(1, 2));
for (Interval in : mySet) {
System.out.println(in.from + " " + in.to);
}
}
}
Use equals and hashCode methods like below it will work perfectly alright
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (from ^ from >>> 32);
result = prime * result + (int) (to ^ to >>> 32);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Interval other = (Interval) obj;
if (from != other.from) {
return false;
}
if (to != other.to) {
return false;
}
return true;
}
I have a class called MyClass:
public class MyClass extends abstractClass implements
someInterface {
Set<VNode> relation_;
Set<VNode> x_;
Set<VNode> y_;
#Override
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof MyClass)) {
return false;
}
MyClass other = (MyClass) obj;
if (relation_ == null) {
if (other.relation_ != null) {
return false;
}
} else if (!relation_.equals(other.relation_)) {
return false;
}
if (x_ == null) {
if (other.x_ != null) {
return false;
}
} else if (!x_.equals(other.x_)) {
return false;
}
if (y_ == null) {
if (other.y_ != null) {
return false;
}
} else if (!y_.equals(other.y_)) {
return false;
}
return true;
}
#Override
public int hashCode() {
int res = new HashCodeBuilder(17, 37).append(relation_).append(x_)
.append(y_).append(getWeight()).toHashCode();
return res;
}
}
The abstract class is as follows:
public abstract class abstractClass {
double weight_;
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof abstractClass)) {
return false;
}
abstractClass other = (abstractClass) obj;
if (Double.doubleToLongBits(weight_) != Double
.doubleToLongBits(other.weight_)) {
return false;
}
return true;
}
public double getWeight() {
return weight_;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(weight_);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
Now, if I have HashSet<MyClass> s1 and an MyClass i1, even if s1 has an element s1i whith s1i.equals(i1)=true and s1i.hashCode()=i1.hashCode(), s1.contains(i1) gives me false.
Any explanations?
Other classes:
public class VNode {
Mention mention_;
#Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof VNode)) {
return false;
}
VNode other = (VNode) obj;
if (mention_ == null) {
if (other.mention_ != null) {
return false;
}
} else if (!mention_.equals(other.mention_)) {
return false;
}
return true;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((mention_ == null) ? 0 : mention_.hashCode());
return result;
}
}
public class Mention extends Range {
private final int id_;
public Mention(final int start, final int end) {
super(start, end);
id_ = getNextMentionID();
}
}
public class Range {
private final int start_;
private final int end_;
/**
* Contr.
*
* #param start
* #param end
*/
public Range(final int start, final int end) {
start_ = start;
end_ = end;
}
#Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Range)) {
return false;
}
Range other = (Range) obj;
if (end_ != other.end_) {
return false;
}
if (start_ != other.start_) {
return false;
}
return true;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + end_;
result = prime * result + start_;
return result;
}
}
Your equals() method is not readable at all. Since you are using HashCodeBuilder in hashCode(), why not use EqualsBuilder as well?
Version a)
public boolean equals(Object obj){
if(obj == null || obj.getClass()!=getClass()){
return false;
}
MyClass other = (MyClass) obj;
return new EqualsBuilder()
// check parent properties first
.append(this.getWeight(), other.getWeight())
.append(this.relation_, other.relation_)
.append(this.x_, other.x_)
.append(this.y_, other.y_)
.isEquals();
}
Version b)
public boolean equals(Object obj){
// delegate to parent equals first
if(!super.equals(obj)){
return false;
}
MyClass other = (MyClass) obj;
return new EqualsBuilder()
.append(this.relation_, other.relation_)
.append(this.x_, other.x_)
.append(this.y_, other.y_)
.isEquals();
}
Each class should only be concerned with its own variables when calculating equals and hashcode. So, in your MyClass instead of calling getWeight() you should be using the hashcode of the super class. Like you are with equals()!. In this case the effect will be the same.
public int hashCode() {
int res = new HashCodeBuilder(super.hashcode(), 37).append(relation_).append(x_)
.append(y_);
return res;
}
This means any changes to the base class that may affect equals and hashcode are confined to the class and you don't have to update the sub classes.
(Not really an answer, more an observation but its too big for a comment)