Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Collections methods(removeAll() and retainAll()) for two objects. (objects are parent-child relation)

I expected to result below but actually not. I would like to know how to show the differences between two Collections. (objects are parent and child relationship) In this case, can I use standard method like removeAll() or can you recommend another approach like using apache-commons. Thanks.

CONSTRAINT
------------------------------
1.Item.class is unmodifiable(eg. I can not add equals method)
2.If id is same between two objects, they are assumed as same things.
------------------------------

EXPECTED
------------------------------
removed object are:
2
same object are:
1
3
add object are:
4
------------------------------

ACTUAL
------------------------------
removed object are:
1
2
3
same object are:
add object are:
1
3
4
------------------------------

package com.javastudy;

import java.util.ArrayList;
import java.util.List;

public class CollectionCompareToObjects {

    public static void main(String[] args) {

        List<Item> before = new ArrayList<Item>();
        List<ItemEx> after = new ArrayList<ItemEx>();

        before.add(new Item(1L));
        before.add(new Item(2L)); // delete
        before.add(new Item(3L));

        after.add(new ItemEx(1L));
        after.add(new ItemEx(3L));
        after.add(new ItemEx(4L)); // added

        List<Item> removed = new ArrayList<Item>(before);
        removed.removeAll(after);

        System.out.println("removed objects are:");
        for(Item item : removed){
            System.out.println(item.getId());
        }

        List<Item> same = new ArrayList<Item>(before);
        same.retainAll(after);

        System.out.println("same objects are:");
        for(Item item : same){
            System.out.println(item.getId());
        }

        List<Item> added = new ArrayList<Item>(after);
        added.removeAll(before);

        System.out.println("add objects are:");
        for(Item item : added){
            System.out.println(item.getId());
        }

    }

}


package com.javastudy;

public class Item {

    private Long id;

    public Item(Long id) {
        this.id = id;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

}

package com.javastudy;

public class ItemEx extends Item {

    private String name;

    public ItemEx(Long id) {
        super(id);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
like image 750
zono Avatar asked Jan 20 '23 21:01

zono


1 Answers

Java collections rely on the equals and hashCode methods (the latter is used by HashMaps, HashSets and others).

If you want to be able to use the data structure capabilities of Java collections (such as removeAll, retainAll etc.), you need to supply objects with proper implementations of equals and hashCode.

If you can't modify the Item class, you can write a wrapper class with your own implementation of equals:

public class ItemWrapper {
    private final Item item;
    public ItemWrapper(Item item) {
        this.item = item;
    }

    public Item getItem() {
        return item;
    }

    @Override
    public boolean equals(Object obj) {
        return obj instanceof ItemWrapper && item.getId().equals(((ItemWrapper) obj).item.getId());
    }

    @Override
    public int hashCode() {
        return item.getId().hashCode();
    }
}

Create a new ItemWrapper for each original Item, store the ItemWrappers in Java collections, and use the required methods (removeAll/retainAll). Then iterate over the resulting collection and retrieve the Items by calling each ItemWrapper's getItem() method.

Your other option is to subclass ArrayList, but it seems like a more convoluted solution.

Yet another option is not to use Java collections for the remove/retain logic, implementing them yourself instead.

like image 50
Eli Acherkan Avatar answered Jan 30 '23 18:01

Eli Acherkan