Does java.util.HashMap.containsKey(Object key) implementation violate java.util.Map.containsKey(Object key) documentation?

java.util.Map.containsKey(Object key) documentation says:
@throws ClassCastException if the key is of an inappropriate type for this map.

The java.util.HashMap.containsKey(Object key) implementation does not say anything about it.

My problem:

If i create a Map<String,String> map = new HashMap<>(); and call the containsKey method with an Integer the value is hashed (as a String) but the method does not throw an Exception.

Btw: The hash of 4 differs from the hash of “4”.

Is this really the intended behavior?

THX in advance!

Solution:

This seems to be an optional restriction, not applied in HashMap.

As stated in API for containsKey:

[…]

Throws:
ClassCastException – if the key is of an inappropriate type for this map (optional)

Note the “optional”, and see linked documentation:

Some collection implementations have restrictions on the elements that they may contain. For example, some implementations prohibit null elements, and some have restrictions on the types of their elements. Attempting to add an ineligible element throws an unchecked exception, typically NullPointerException or ClassCastException. Attempting to query the presence of an ineligible element may throw an exception, or it may simply return false; some implementations will exhibit the former behavior and some will exhibit the latter. More generally, attempting an operation on an ineligible element whose completion would not result in the insertion of an ineligible element into the collection may throw an exception or it may succeed, at the option of the implementation. Such exceptions are marked as “optional” in the specification for this interface.

Indexing when using a hashmap with streams

I have a HashMap of teams that I need to print out. They need to be indexed and sorted by some parameters(not relevant). Everything works fine except for the indexing part which I got working in a way but it doesn’t feel right.

int i=0;

public void printTable()
{
    StringBuilder sb = new StringBuilder();

    i = 0;

    table.keySet().stream()
                .map(key -> table.get(key))
                .sorted(Comparator.comparing(Team::getPoints).thenComparing(Team::goalDifference).reversed().thenComparing(Team::getName))
                .forEach(team -> sb.append(String.format("%2d%s %-15s%5d%5d%5d%5d%5d\n", ++i, ".", team.getName(), team.getPlayed(),
                         team.getWins(), team.getDraws(), team.getLosses(), team.getPoints())));

    System.out.print(sb.toString());
}

Is there a better way of doing this? I don’t think Intstream would help here because I wouldn’t be able to get the object from the HashMap using an index.

Solution:

You cannot modify the reference of the variables/modify primitives that you are used within a stream or lambda. You can rewrite your code like below,

AtomicInteger i = new AtomicInteger();
String result = table.values()
        .stream()
        .sorted(...)
        .map(e -> i.incrementAndGet() + "_" + e)
        .collect(Collectors.joining());

AtomicInteger will give you mutability without changing the reference/modifying the primitive. You don’t need to do look-ups in the map, you can directly iterate over values.

Edit

As @Eugene pointed out in the comment, the approach with AtomicInteger cannot be used if you are using parallel stream.

How to properly use double coordinates as a key in a HashMap?

I have a class defining a node (a point with three double coordinates).

public class Node {
    private final double x, y, z;

    public Node() {
    }

    public Node(final double x, final double y, final double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public void setCoordinates(final double x, final double y, final double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

I need to create a lot of nodes and give them integer IDs, but I must avoid duplicates.

The method to create a node looks like this:

private Node vertex = new Node(0, 0, 0);
private final AtomicInteger nodeCounter = new AtomicInteger();
private final Map<Node, Integer> nodeList = new HashMap<>();

public int addNode(final double x, final double y, final double z) {
    vertex.setCoordinates(x, y, z);

    int nodeId;

    if(nodeList.get(vertex) == null) {
        nodeId = nodeCounter.incrementAndGet();
        nodeList.put(new Node(x, y, z), nodeId);
    } else {
        nodeId = nodeList.get(vertex);
    }

    return  nodeId;
}

Of course, this does not work because the getfunction of the HashMap always returns null.

So I guess I need to override the hashCode method in the Node class.

I have seen here how to do it for a single double, but I don’t know how to create a hash function that would take into account the three coordinates of the node.

Do I also have to override the equals function? Or is the hashCode function enough?

Solution:

So I guess I need to override the hashCode method in the Node class.

That’s only part of the deal. You also need to override equals in order to make your class work as a key of hash map:

@Override
public int hashCode() {
    return 31*31*Double.valueOf(x).hashCode()
          +   31*Double.valueOf(y).hashCode()
          +      Double.valueOf(z).hashCode();
}
@Override
public boolean equals(Object other) {
    if (!(other instanceof Node)) {
        return false;
    }
    Node n = (Node)other;
    return x == n.x && y == n.y && z == n.z;
}

In Java 8+, Double.valueOf(x).hashCode() should be replaced with Double.hashCode(x) to avoid unnecessary boxing:

@Override
public int hashCode() {
    return 31*31*Double.hashCode(x)
          +   31*Double.hashCode(y)
          +      Double.hashCode(z);
}

Do I also have to override the equals function? Or is the hashCode function enough?

Yes, you must always override equals along with hashCode (why?)

Eliminate null key from hashmap which is present inside an arraylist

I am looking for an optimized solution to remove null keys from a HashMap. This HashMap is present inside an ArrayList. Please find the example below.

public class Car {
    String year;
    String model;
    Map<String,String> colors;
}

List<Car> listOfCars = new ArrayList<Car>();

Sample of the colors map could be like this:

{
   red(1),
   blue(2),
   green(3),
   black(4),
   null(5)
}

I need a solution to iterate over the listOfCars, get the map of colors and remove the null key from that. Trying to see any other options in Java8 rather than using an Iterator.

Thanks!

Solution:

Considering a map cannot contain duplicate keys, we can, therefore, say that each Map instance of a Car instance will only ever have at most one entry with a null key.

The solution using the Java-8 forEach construct is:

listOfCars.forEach(e -> e.getColors().remove(null));

Although it can be done with a for loop or an enhanced for loop as well.