LoginSignup
1
0

Switch文を実行したら、Cannot invoke "String.hashCode()" because "XXXXXX" is nullというエラーを吐く件

Last updated at Posted at 2023-08-14

下記のようなコードを実行すると
Cannot invoke "String.hashCode()" because "XXXXXX" is null
というエラーが出力されました。

qiita.java
public class Sample2 {
	static String str;

	public static void main(String[] args) {
		switch (str) {
		case "10":
			str += 10;
		default:
			str += "def";
		case "20":
			str += 20;
		}
		
		System.out.println(str);
	}
}

hashCode??なんのエラーなん??となりswitch(str)のところでブレイクポイントを張り、この部分をステップインしみていくと、次のようなメソッドがあります。

スクリーンショット 2023-08-14 8.46.15.png

ふむふむ。どうやらuncaughtExceptionとかいうエラーが発生している模様です、、
このuncaughtExceptionとは、
スクリーンショット 2023-08-14 8.54.37.png
このメソッドで色々な確認項目はありますが、とにかく値を取得できなかったときに発生するExceptionであると考えられます。

今回は、strがnull値なので、これに値を代入して実行してみます。
すると、こんなメソッドに飛びます。
どうやらswitch文を実行する際には下記のメソッドが呼び出されるという仕様になっているようです。

String.class
 /**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    public int hashCode() {
        // The hash or hashIsZero fields are subject to a benign data race,
        // making it crucial to ensure that any observable result of the
        // calculation in this method stays correct under any possible read of
        // these fields. Necessary restrictions to allow this to be correct
        // without explicit memory fences or similar concurrency primitives is
        // that we can ever only write to one of these two fields for a given
        // String instance, and that the computation is idempotent and derived
        // from immutable state
        int h = hash;
        if (h == 0 && !hashIsZero) {
            h = isLatin1() ? StringLatin1.hashCode(value)
                           : StringUTF16.hashCode(value);
            if (h == 0) {
                hashIsZero = true;
            } else {
                hash = h;
            }
        }
        return h;
    }

つまりここのメソッドの処理をする際に対象となる変数がnullだとエラーになるということでした。

結論、switch文で条件分岐する際には対照となる値はnull値ではなく、値を代入すること!ということでした。

後書き:
今回、switchの内部の処理を追いたくてソースコード見たんですけど、よく分からず今回のような解説となってしまいました。もし有識者の方でhashはswitch文内でこう呼び出していてこういう処理をする時に必要でだからエラーになる等の理由がわかる方いらっしゃいましたら、是非ご教授頂きたいです。。
下記がswitch文を定義していると思われるjavaクラスファイルです、、
https://github.com/openjdk/jdk/blob/master/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

下記の部分のところでエラーになるってことなのか?

javacParder.java
/* ---------- doc comments --------- */

    /** A table to store all documentation comments
     *  indexed by the tree nodes they refer to.
     *  defined only if option flag keepDocComment is set.
     */
    private final DocCommentTable docComments;

    /** Make an entry into docComments hashtable,
     *  provided flag keepDocComments is set and given doc comment is non-null.
     *  @param tree   The tree to be used as index in the hashtable
     *  @param dc     The doc comment to associate with the tree, or null.
     */
1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0