3
private HashMap<DataObject, HashSet> AllDataObjects;

...

/** Returns all DataObject elements that are NOT in the specified set. */
private DataObject[] invert( HashSet<DataObject> set )
{
    HashSet<DataObject> keys = (HashSet) AllDataObjects.keySet();
    keys = (HashSet) keys.clone();

    keys.removeAll( set );

    return (DataObject[]) keys.toArray();
}

Note that I don't want to alter AllDataObjects through this process. I casted the set of AllDataObjects' keys (which are the DataObjects I want the set parameter to subtract from) into a HashSet to use clone, which supposedly returns a shallow copy that I can then remove set from without affecting AllDataObjects.

Does this look right to you?

Brad Mace
  • 27,194
  • 17
  • 102
  • 148
Daddy Warbox
  • 4,500
  • 9
  • 41
  • 56
  • This is a perfect time to use Google Collections. You could do Set.difference to produce a SetView object, which is more memory efficient and possibly faster. Not to mention the code would be pretty. – Muhd Aug 23 '11 at 22:04

3 Answers3

12

Create a new set and give the one to be cloned as an argument. This avoids casting and so you don't lose generics.

private DataObject[] invert( Set<DataObject> set ){
    Set<DataObject> keys = new HashSet<DataObject>(AllDataObjects.keySet());
    keys.removeAll( set );
    return keys.toArray(new DataObject[]{});
}

It's also worth noting that you should use Set rather than HashSet for the parameter so as to not overly burden your clients.

Aaron Maenpaa
  • 119,832
  • 11
  • 95
  • 108
iny
  • 7,339
  • 3
  • 31
  • 36
  • 1
    In fact arguably you should declare the argument to be Collection extends DataObject>, both so they can pass in a List if they have one handy (as this will still work), and so they can pass in a collection of some kind of subclass without having to wrap it. – Andrzej Doyle Feb 04 '09 at 12:39
1

Knowing that these sets were populated by a relational query, I would suggest that you at least trade off writing a better SQL query to get what you want rather than doing it in memory. There are several reasons why. First, most relational databases are optimized to do this more efficiently than your code will. Second, you're letting the server where the relational database is running do more of the work that it was intended for. Third, if the size of the sets become large you'll be unnecessarily burdening the middle tier by having to bring back the results, allocate memory for them, and then throw away the unwanted results.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • I'm not using a database yet, but I plan too soon. There's a few parts to the basic design I haven't ironed out yet, which I'd prefer to do with ordinary code for now. – Daddy Warbox Dec 27 '08 at 20:15
1

I think this link has a better way to write that method if you must:

Java: Is there an easy, quick way to AND, OR, or XOR together sets?

Community
  • 1
  • 1
duffymo
  • 305,152
  • 44
  • 369
  • 561