Map with integer as key returns null when long value is passed to get method

import java.util.HashMap;
import java.util.Map;

public class StackOverFlowQuestion {

private static final int ERROR_CODE100 = -100;
private static final int ERROR_CODE101 = -101;
private static final int ERROR_CODE102 = -102;
private static final int ERROR_CODE103 = -103;
private static final int ERROR_CODE104 = -104;

public enum ErrorDetails {

    ERROR_CODE_100(ERROR_CODE100, "Error code 100 Desc", false),

    ERROR_CODE_101(ERROR_CODE101, "Error code 101 Desc", false),

    ERROR_CODE_102(ERROR_CODE102, "Error code 102 Desc", true),

    ERROR_CODE_103(ERROR_CODE103, "Error code 103 Desc", false),

    ERROR_CODE_104(ERROR_CODE104, "Error code 104 Desc", true);

    private int errorCode;
    private String errorMsg;
    private boolean canRetry;

    private ErrorDetails(int errorCode, String errorMsg, boolean canRetry) {
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.canRetry = canRetry;
    }

    public String getErrorMsg() {
        return this.errorMsg;
    }

    public boolean canRetry() {
        return this.canRetry;
    }

    public String toString() {
        return "Error code : " + errorCode + ", errorMsg : " + errorMsg
                + ", canRetry : " + canRetry;
    }
}

private Map<Integer, ErrorDetails> errorMap;

public StackOverFlowQuestion() {
    System.out.println("StackOverFlowQuestion.StackOverFlowQuestion()");

    errorMap = new HashMap<Integer, StackOverFlowQuestion.ErrorDetails>();

    errorMap.put(ERROR_CODE100, ErrorDetails.ERROR_CODE_100);
    errorMap.put(ERROR_CODE101, ErrorDetails.ERROR_CODE_101);
    errorMap.put(ERROR_CODE102, ErrorDetails.ERROR_CODE_102);
    errorMap.put(ERROR_CODE103, ErrorDetails.ERROR_CODE_103);
    errorMap.put(ERROR_CODE104, ErrorDetails.ERROR_CODE_104);

    System.out.println("errorMap : " + errorMap);
}

/**
 * @param args
 */
public static void main(String[] args) {
    long param = -100;
    StackOverFlowQuestion question = new StackOverFlowQuestion();
    System.out.println("question.errorMap : " + question.errorMap);

    System.out.println("question.errorMap.containskey(param) : "
            + question.errorMap.containsKey(param));
    ErrorDetails errorDetails = question.errorMap.get(param);
    System.out.println("errorDetails : " + errorDetails);

    System.out.println("question.errorMap.containskey((int)param) : "
            + question.errorMap.containsKey((int) param));
    ErrorDetails errorDetailsWithInt = question.errorMap.get((int) param);
    System.out.println("errorDetailsWithInt : " + errorDetailsWithInt);

            int paramInt = -100;
    System.out.println("param == paramInt : " + (param == paramInt));
}

      

}

=============================================== === =============================== Exit:

StackOverFlowQuestion.StackOverFlowQuestion()

errorMap : {-100=Error code : -100, errorMsg : Error code 100 Desc, canRetry : false, -102=Error code : -102, errorMsg : Error code 102 Desc, canRetry : true, -101=Error code : -101, errorMsg : Error code 101 Desc, canRetry : false, -104=Error code : -104, errorMsg : Error code 104 Desc, canRetry : true, -103=Error code : -103, errorMsg : Error code 103 Desc, canRetry : false}

question.errorMap : {-100=Error code : -100, errorMsg : Error code 100 Desc, canRetry : false, -102=Error code : -102, errorMsg : Error code 102 Desc, canRetry : true, -101=Error code : -101, errorMsg : Error code 101 Desc, canRetry : false, -104=Error code : -104, errorMsg : Error code 104 Desc, canRetry : true, -103=Error code : -103, errorMsg : Error code 103 Desc, canRetry : false}

question.errorMap.containskey(param) : false
errorDetails : null

question.errorMap.containskey((int)param) : true
errorDetailsWithInt : Error code : -100, errorMsg : Error code 100 Desc, canRetry : false

param == paramInt : true

      

=============================================== === ===============================

Here are some questions that I need clarification.

  • The code compiles even if I pass the long parameter to the getter of the HashMap method, which is declared to have only Integer as keys. I was expecting a compilation error here because I somehow feel like this violates strong typing.
  • When I pass in a long variable containing the error code as a parameter to get, the HashMap () method returns null.
  • When I dump the same long parameter to int and pass it to the hashmap get method, the map returns the correct Enum.

I suspect the bottom line in the HashMap.get () method if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

I'm not sure if int == long will fail or their respective wrappers will fail. I even added a check in the main method to check for equality of int and long variables.

I would like to understand the behavior here.

+3


source to share


4 answers


The code compiles even if I pass a long parameter to the get method of the HashMap, which is declared to only have integers as keys. I was expecting a compilation error here because I somehow feel like this violates strong typing.

Have you seen the signature Map.get

?

V get(Object key)

      

Any object can be used as a key. There are other questions about this design decision; I'll find it later.

When I pass in a long variable containing the error code as a getter parameter to HashMap (), the map returns null.



Yes it will - because it will be boxed with Long

and a is Long

not equal Integer

. Therefore, the entry was not found on the map.

When I dump the same long parameter to int and pass it to the hashmap get method, the map returns the correct Enum.

Yes it will - because then it will be boxed with Integer

, which will be equal to the corresponding key.

Basically you are deceived by the fact that you can compare values int

and Long

- that only the compiler automatically promotes int

to Long

for you; if you think of Integer

and Long

as completely different types, without automatic conversion between them, your map's behavior makes sense.

+8


source


1.) The code compiles even if I pass a long parameter to the get method of the HashMap, which is declared as an integer as keys. I was expecting a compilation error because I somehow feel like this violates strong typing.

Compilation error here: The only Map methods with parameters limited to typical types are methods put

. get

and containsKey

accept Object

.

2.) When I pass a long variable containing the error code as a parameter to the get method for HashMap (), the map returns null.



When called, get(param)

it is converted to get(new Long(param))

. So the argument is never equal to keysInteger

3.) When I dump the same long parameter to an int and pass it to the hashmap get method, the map returns the correct Enum.

When called, get((int)param)

it translates to get(new Integer((int)param))

. Thus, the type of the argument is now correct and the result is what you expected.

+1


source


you need to pass long to int.

0


source


Short answer: Integer == Long will always be unequal ([Long] .equal ([Integer]) = false) and Long.hashCode () == Integer.hashCode () returns the same result.

To clarify this answer:

Due to Autoboxing, your long will be converted to Long, which will then be compared to any other object with the same hashcode on the map. Since the concrete implementation of HashCode does not need to be equal for Long and Integer, this may already be a failure. If the hashcodes are the same, though there is an equality check that will be done, because like any equals method, it checks for "instance [Type]" or returns false. That will fail in every case of comparing a long with an integer.

So all you have to do in your case is either cast you to int or do Integer.valueOf ((int) param) which will do the same (autoboxing).

0


source







All Articles