简体   繁体   中英

Java Custom Object with multiple properties as Map key or concatenation of its properties

I have a requirement where I have to aggregate a number of objects based on its properties. Object has around 10 properties and aggregation must be done on all its properties. For example - If there are two objects A and B of some class C with properties p1, p2, p3,...p10, (all properties are of String type) then these two objects must be considered equal only if all its corresponding properties are equal. For this I have two approaches in mind using HashMap in Java-

Approach 1 - Using key as Object of tyep C and Value as Integer for count and increase the count every time an existing object is found in Map otherwise create a new key value pair. HahsMap<C, Integer> But in this approach since I have to aggregate on all the properties, I will have to write(override) an equals() method which will check all the string properties for equality and similarly some implementation for hashCode().

Approach 2 - Using key as a single string made by concatenation of all the properties of object and value as a wrapper object which will have two properties one the object of type C and another a count variable of Integer type . For each object(C) create an String key by concatenation of its properties and if key already exists in the Map, get the wrapper object and update its count property , otherwise create a new key, value pair.

HashMap<String, WrapperObj>

In this approach I don't have to do any manual task to use String as key and also it is considered a good practice to use String as key in Map.

Approach 2 seems easy to implement and efficient as opposed to Approach 2 every time when equals is called all the properties will be checked one by one. But I am not sure whether Approach 2 in a standard way of comparing two objects and performing this kind of operation.

Please suggest if there is any other way to implement this requirement, like if there is any better way to implement equals() method for using it as key when all its properties should be taken into consideration when checking for equality of objects.

Example - Class whose objects needs aggregation with hash and equals implementation in case of Approach 1

public class Report {

private String p1;
private String p2;
private String p3;
private String p4;
.
.
.
private String p10;
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((p1 == null) ? 0 : p1.hashCode());
    result = prime * result + ((p2 == null) ? 0 : p2.hashCode());
    result = prime * result + ((p3 == null) ? 0 : p3.hashCode());
    result = prime * result + ((p4 == null) ? 0 : p4.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (!(obj instanceof Report))
        return false;
    Report other = (Report) obj;
    if (p1 == null) {
        if (other.p1 != null)
            return false;
    } else if (!p1.equals(other.p1))
        return false;
    if (p2 == null) {
        if (other.p2 != null)
            return false;
    } else if (!p2.equals(other.p2))
        return false;
    if (p3 == null) {
        if (other.p3 != null)
            return false;
    } else if (!p3.equals(other.p3))
        return false;
    if (p4 == null) {
        if (other.p4 != null)
            return false;
    } else if (!p4.equals(other.p4))
        return false;
    .
    .
    .
    if (p10 == null) {
        if (other.p10 != null)
            return false;
    } else if (!p10.equals(other.p10))
        return false;
    return true;
}
}

Code For aggregation Approach 1-

Map<Report, Integer> map = new HashMap<Report, Integer>();
    for(Report report : reportList) {
        if(map.get(report) != null)
            map.put(report, map.get(report)+1);
        else
            map.put(report, 1);
    }

Approach 2 - With wrapper class and not implementing equals and hash for Report class.

public class Report {

private String p1;
private String p2;
private String p3;
private String p4;

public String getP1() {
    return p1;
}
public void setP1(String p1) {
    this.p1 = p1;
}
public String getP2() {
    return p2;
}
public void setP2(String p2) {
    this.p2 = p2;
}
public String getP3() {
    return p3;
}
public void setP3(String p3) {
    this.p3 = p3;
}
public String getP4() {
    return p4;
}
public void setP4(String p4) {
    this.p4 = p4;
}

Report warpper class - public class ReportWrapper {

private Report report;
private Integer count;

public Report getReport() {
    return report;
}
public void setReport(Report report) {
    this.report = report;
}
public Integer getCount() {
    return count;
}
public void setCount(Integer count) {
    this.count = count;
}
}

Code For aggregation Approach 2-

    Map<String, ReportWrapper> map = new HashMap<String, 
    ReportWrapper>();
    for(Report report : reportList) {
        String key = report.getP1() + ";" + report.getP2() + 
       ";" + report.getP3() +
       ";" + .....+ ";" + report.getP10();
        ReportWrapper rw = map.get(key);
        if(rw != null) {
            rw.setCount(rw.getCount()+1);
            map.put(key, rw);
        }
        else {
            ReportWrapper wrapper = new ReportWrapper();
            wrapper.setReport(report);
            wrapper.setCount(1);
            map.put(key, wrapper);
        }
    }

PSI: Here I am more concerned about, which approach is better.

Consider using the equals and hashcode methods that you can get generated from an IDE or use a tool like Lombok which will do it for you using an annotation and you don't have to write any code.

For lombok:

This is what IDEA generates if you want to go that route. No special process required.

@Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Report report = (Report) o;
        return Objects.equals(prop1, report.prop1) &&
                Objects.equals(prop2, report.prop2) &&
                Objects.equals(prop3, report.prop3) &&
                Objects.equals(prop4, report.prop4) &&
                Objects.equals(prop5, report.prop5) &&
                Objects.equals(prop6, report.prop6) &&
                Objects.equals(prop7, report.prop7) &&
                Objects.equals(prop8, report.prop8) &&
                Objects.equals(prop9, report.prop9);
    }

    @Override
    public int hashCode() {
        return Objects.hash(prop1, prop2, prop3, prop4, prop5, prop6, prop7, prop8, prop9);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM