HashSet.remove() fails to behave according to spec? - java

According to JDK docs for HashSet, remove() :
removes an element e such that (o==null ? e==null : o.equals(e)), if
this set contains such an element.
Well, here is a tiny bit of code that proves otherwise. The Set points definitely contains my point, as evidenced by equals(), and yet, remove() mysteriously fails to remove it. The trouble seems to be somehow due to the change of value of point.x (line 4 of main()). Omitting this makes everything behave as expected.
Note that the following behaves normally if points is an ArrayList rather than a HashSet.
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.HashSet;
public class RemoveTest2 {
public static void main(final String[] args) {
final Collection<Point2D.Double> points = new HashSet<Point2D.Double>();
final Point2D.Double point = new Point2D.Double();
points.add(point);
point.x++;
// make sure that points definitely contains the point we are trying to remove...
for (final Point2D.Double p : points) {
if (point.equals(p)) {
System.out.println("points definitely contains " + point);
System.out.println(point.hashCode() + " == " + p.hashCode());
}
}
if (!points.remove(point)) {
System.out.println("and yet... failed to remove " + point);
}
System.out.println("points cointains " + points.size());
}
}
The spec seems painfully clear... Please, somebody explain to me what I am missing here.

The problem is you change the hashcode of an object after using it, so the Hashset cannot get the existing object using the new hashcode (as it is stored using old hashcode).
When changing such fields, you need to first remove this object before changing it, than store it again.
Take a look at this

Related

Java constructor creates many null instances before the required object

this is my first question on here and I did a search before forming it, so I hope everything is as required.
I am working on a school assignment in Java. I am able to produce the required output but there are a lot of null instances created first. I don't understand why. Information about the library the professor created for the course and the code are below
Library included with this course: i2c.jar. It can be found here.
included in this Library are the classes Country and CountryDB. The API for the Country class can be found at http://130.63.94.24/~roumani/book/doc/i2c/ca/roumani/i2c/Country.html
The API for the CountryDB class can be found at http://130.63.94.24/~roumani/book/doc/i2c/ca/roumani/i2c/CountryDB.html
I am asked to create a class called Game, using the Country and CountryDB APIs.
The only attribute is db, which is an instance of CountryDB.
The constructor only sets the attribute (db) for this instance to a new CountryDB object.
The class is also meant to include a method (called qa) that follows this pseudocode:
get a reference to the database's capital city list
determine the size of this list. Cal it n.
generate a random number in [0,n) called index.
invoke get(index) on the list to get a random capital city. Call it c
get a reference to the database's data map
invoke get(c) on the map to get a reference to a country. Call it ref.
The method is then supposed to return one of two Strings (which will be clear in the code). Everything works as it should, except I get a lot of "nulls" before the desired output. When made into a List, db has size 241 so I suspect I am creating 241 null instances and 1 proper instance. I have no idea why though. I have tested every line of code in my method and the constructor was dictated by the textbook.
CODE
package ca.yorku.eecs.caps;
import java.util.List;
import java.util.Map;
import ca.roumani.i2c.Country;
import ca.roumani.i2c.CountryDB;
public class Game
{
private CountryDB db;
public Game()
{
this.db = new CountryDB();
}
public String qa()
{
List<String> capitals = db.getCapitals();
System.out.println(capitals.toString());
int n = capitals.size();
System.out.println(n);
int index = ((int) (n * Math.random()));
System.out.println(index);
String c = capitals.get(index);
System.out.println(c);
Map<String, Country> data = db.getData();
Country ref = data.get(c);
if (Math.random() > 0.5)
{
return "What is the capital of " + ref.getName() + "? \n" + ref.getCapital();
}
else
{
return ref.getCapital() + " is the capital of? \n" + ref.getName();
}
}
public static void main(String[] args)
{
Game g = new Game();
System.out.println(g.qa());
}
}
the System.out.println() statements are only there to test when the nulls occur. It clearly happens immediately because my psvm output is 241 nulls (on separate lines) followed by my desired output. Can somebody please tell me what I am doing wrong?
And, more generally (to help more people) how do you implement classes, the constructor of which instantiates another class and sets it as an attribute value?
I appreciate any help. Also, please note, I am not trying to get others to do my work for me. I've spent hours on this and my lab TA also wasn't sure why it happens either. He would have helped me correct it had he known how.
Thank you.

Advice needed: What and how to removeNulls (I'm not sure exactly what to do)

I have a practice question from lectures which I am not sure how to solve and would appreciate insight into what should be done and an explanation:
Q: Give code for the method removeNulls(q) which removes from the Queue q all null elements. The method main contains a simple example illustrating the effect of method removeNulls.
package labsSGTsCoursework.cw1;
import net.datastructures.NodeQueue;
import net.datastructures.Queue;
public class CW1_q4 {
public static <E> void removeNulls( Queue<E> q) {
... // YOUR CODE REPLACES DOTS HERE
}
public static void main(String[] args) {
// test method removeNulls
Queue<Integer> que = new NodeQueue<Integer>();
que.enqueue(5);
que.enqueue(null);
que.enqueue(8);
que.enqueue(2);
que.enqueue(null);
System.out.println(que); // should print: "(5, null, 8, 2, null)"
removeNulls(que);
System.out.println(que); // should print: "(5, 8, 2)"
}
}
Sorry I did not notice it was a generic, so the markers approach will not work (thought is is a usefull trick sometimes so I leave it below).
Inside the method, make a new queue, copy all non null values from the old one to new, and then back to the original queue (as the values are consumed from orginal so you need to put them back).
For not, generic methods, the marker approach may work (as long as some values can never appearch in the input):
Insert a marker for example Integer.MAX_VALUE, iterate over the que and insert back all the elements which are not null, stop once you encounter your marker.

Is there a way to highlight a row in GlazedLists?

I have a list which is used to monitor arrival of certain entities in a strictly ascending numeric sequence and want to display an entry where there is an apparent break in the sequence.
Is there any way to highlight an entry in GlazeLists?
It's difficult to be certain about whether you're asking about how to highlight new elements within a list, or literally highlight a row in a UI component backed by a GlazedLists EventList.
For now I'll assume the former but feel free to clarify.
There is the notion of ListEvents within the GlazedLists package that allows one to get a small peak into changes that affect a list. It's not something I've played with much, and it seems rather rudimentary, but it's possible to use this mechanism given the right circumstances.
Here's a sample class which has a BasicEventList containing some integers. I've created a ListEventListener and attached it to the EventList. The ListEvents tell you where the element was inserted. It also contains a reference to the eventlist, so it's possible to get the newly inserted value, and also the value of the element preceding it. I do a quick comparison to see whether they're out of sequence.
Of course there are some major caveats here. The event handling is asynchronous, so it's entirely possible that the underlying list will changed considerably between the time of the original trigger and the time at which the listener is processing the event. In my sample it's ok because I'm only using append operations. Also I'm only using a BasicEventList; if it were a SortedList then the items would be inserted in different indexes, so the method I use for getting the current and previous values would be extremely unreliable. (There may be ways around this but I haven't applied myself to this problem in all honesty.)
At the very least you can use the listener to at least alert you to a list change and have another method outside of the listener class perform a scan of your list to determine whether there are items out of order.
import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;
public class GlazedListListen {
private final EventList<Integer> numbers = new BasicEventList<Integer>();
public GlazedListListen() {
numbers.addListEventListener(new MyEventListListener());
numbers.addAll(GlazedLists.eventListOf(1,2,4,5,7,8));
}
class MyEventListListener implements ListEventListener<Integer> {
#Override
public void listChanged(ListEvent<Integer> le) {
while (le.next()) {
if (le.getType() == ListEvent.INSERT) {
final int startIndex = le.getBlockStartIndex();
if (startIndex == 0) continue; // Inserted at head of list - nothing to compare with to move on.
final Integer previousValue = le.getSourceList().get(startIndex-1);
final Integer newValue = le.getSourceList().get(startIndex);
System.out.println("INSERTING " + newValue + " at " + startIndex);
if ((newValue - previousValue) > 1) {
System.out.println("VALUE OUT OF SEQUENCE! " + newValue + " # " + startIndex);
}
}
}
}
}
public static void main(String[] args) {
new GlazedListListen();
}
}
Note: I've only tested against GlazedLists v1.8.

deletion from Set iterator

Could someone explain to me why the following doesn't work (runways is a Hibernate PersistentSet) ?
System.out.println("size before " + runways.size());
Iterator<Runway> deleteIterator = runways.iterator();
while (deleteIterator.hasNext()) {
Runway rwy = deleteIterator.next();
if (rwy == rwy3) {
System.out.println("remove !");
deleteIterator.remove();
}
}
System.out.println("size after " + runways.size());
I get the system.Out logs:
INFO: size before 3
INFO: remove !
INFO: size after 3
I thought that deletion through the iterator was safe and possible.
You see the log "remove"! which indicates that the remove() method is called.
EDIT : PersistentSet has problem with the remove method from the Iterator interface.
Check to make sure your hashCode() and equals() methods are overridden and correct on your Runway object.
//EDIT: FYI this code is an example of failing code. Override your equals() and hashCode() properly.
To follow up on JustinKSU's point, if you don't implement your hashCode() and equals() well, what you are doing won't work. I can replicate your situation if I muddy the equals() and the hashCode().
public static void main(String[] args) {
Set<Runway> runways = new HashSet<Runway>();
Runway rwy1 = new Runway();
Runway rwy2 = new Runway();
Runway rwy3 = new Runway();
runways.add(rwy1);
runways.add(rwy2);
runways.add(rwy3);
System.out.println("size before " + runways.size());
Iterator<Runway> deleteIterator = runways.iterator();
while (deleteIterator.hasNext()) {
Runway rwy = deleteIterator.next();
if (rwy == rwy3) {
System.out.println("remove !");
deleteIterator.remove();
}
}
System.out.println("size after " + runways.size());
}
private static class Runway {
#Override
public boolean equals(Object obj) {
return false;
}
#Override
public int hashCode() {
return (new Random()).nextInt();
}
}
From looking at the JDK source code (I found it here), the iterator returned by a HashSet uses one of the HashSet's internal remove methods for performing the actual removal.
For a HashSet to work correctly, you need to either leave both equals and hashCode in your Runway class alone, or override them both. This SO question talks about this issue: What issues should be considered when overriding equals and hashCode in Java?
My equals and hashCode methodes were created by Eclipse itself. So it doesn't come from them.
But I was too quick at the beginning of my question. I forgot that Runways is a PersistentSet from Hibernate (and not a java.util.HashSet)
And I found this bug which explaines why it is not possible to remove a object from a PersistenSet iterator.
The bug seems old and complicated to solve.
My only option is then to recreate a set from the first one, and without the element I don't want.

How to write a recursive function using static variables

I am trying to write a code to get the set of points (x,y) that are accessible to a monkey starting from (0,0) such that each point satisfies |x| + |y| < _limitSum. I have written the below code and have used static HashSet of members of Coordinate type (not shown here) and have written a recursive method AccessPositiveQuadrantCoordinates. But the problem is the members of the HashSet passed across the recursive calls is not reflecting the Coordinate members added in previous calls. Can anybody help me on how to pass Object references to make this possible? Is there some other way that this problem can be solved?
public class MonkeyCoordinates {
public static HashSet<Coordinate> _accessibleCoordinates = null;
private int _limitSum;
public MonkeyCoordinates(int limitSum) {
_limitSum = limitSum;
if (_accessibleCoordinates == null)
_accessibleCoordinates = new HashSet<Coordinate>();
}
public int GetAccessibleCoordinateCount() {
_accessibleCoordinates.clear();
Coordinate start = new Coordinate(0,0);
AccessPositiveQuadrantCoordinates(start);
return (_accessibleCoordinates.size() * 4);
}
private void AccessPositiveQuadrantCoordinates(Coordinate current) {
if (current.getCoordinateSum() > _limitSum) { return; }
System.out.println("debug: The set _accessibleCoordinates is ");
for (Coordinate c : _accessibleCoordinates) {
System.out.println("debug:" + c.getXValue() + " " + c.getYValue());
}
if (!_accessibleCoordinates.contains(current)) { _accessibleCoordinates.add(current); }
AccessPositiveQuadrantCoordinates(current.Move(Coordinate.Direction.East));
AccessPositiveQuadrantCoordinates(current.Move(Coordinate.Direction.North));
}
I will give points to all acceptable answers.
Thanks ahead,
Somnath
But the problem is the members of the HashSet passed across the recursive calls is not reflecting the Coordinate members added in previous calls.
I think that's very unlikely. I think it's more likely that your Coordinate class doesn't override equals and hashCode appropriately, which is why the set can't "find" the values.
As an aside, using static variables like this seems like a very bad idea to me - why don't you create the set in GetAccessibleCoordinateCount() and pass the reference to AccessPositiveQuadrantCoordinates, which can in turn keep passing it down in the recursive calls?
(As another aside, I would strongly suggest that you start following Java naming conventions...)
i don't see any problem with making the field _accessibleCoordinates non-static
and you should know that HashSet does not guarantee the same iteration order everytime, you could better use a LinkedList for that purpose...
and about pass by reference, i found this post very useful
java - pass by value - SO link
From what you are doing you would be updating _accessibleCoordinates in every recursive call correctly.

Categories