Search code examples
javaidiomsdecompilingjvm-bytecode

What does just calling .getClass(); do?


I'm looking at some decompiled code and seeing .getClass();, i.e. nothing being done with its return value.

  public String forLocale(Locale locale, String keyword) {
    Stream var10000 = getLocaleMappingList(locale, this.getSupportedLocales());
    Map var10001 = this.translations;
    var10001.getClass();
    Map<String, String> translation = (Map)var10000.map(var10001::get).filter((m) -> {
      return m.containsKey(keyword);
    }).findFirst().orElse(this.translations.get(FALLBACK));
    Preconditions.checkState(translation.containsKey(keyword), keyword + " is not a valid translation key");
    return (String)translation.get(keyword);
  }

What is that for? Was it in the original code like that? (So far I haven't seen an instance of decompiled code not matching up at least line-wise to source code.)

It kind of looks like an assertion, but then what is achieved by doing that as opposed to letting things go wrong at var10001::get? Or is it more about performance?


Update

Here's the bytecode. Cool thing to learn how to do!

 // access flags 0x1
  public forLocale(Ljava/util/Locale;Ljava/lang/String;)Ljava/lang/String;
   L0
    LINENUMBER 184 L0
    ALOAD 1
    ALOAD 0
    INVOKEVIRTUAL com/spotify/i18n/Translations.getSupportedLocales ()Ljava/util/Set;
    INVOKESTATIC com/spotify/i18n/Translations.getLocaleMappingList (Ljava/util/Locale;Ljava/util/Collection;)Ljava/util/stream/Stream;
    ALOAD 0
    GETFIELD com/spotify/i18n/Translations.translations : Ljava/util/Map;
    DUP
    INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
    POP
    INVOKEDYNAMIC apply(Ljava/util/Map;)Ljava/util/function/Function; [
      // handle kind 0x6 : INVOKESTATIC
      java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      // arguments:
      (Ljava/lang/Object;)Ljava/lang/Object;, 
      // handle kind 0x9 : INVOKEINTERFACE
      java/util/Map.get(Ljava/lang/Object;)Ljava/lang/Object; itf, 
      (Ljava/util/Locale;)Ljava/util/Map;
    ]

Solution

  • This looks like decompiled code, and my guess is that the decompiler hasn't generated Java code that is equivalent to the original source code.

    The literal meaning of

    var10001.getClass();
    

    is to return the Class object for the type of the object that var10001 refers to. But the value that is returned appears to be discarded, so the call (apparently) doesn't achieve anything. Hence, my tentative conclusion that the decompiler has stuffed up.

    You may need to read the (disassembled) bytecodes directly to discern what they are actually doing. (Or you could try a different decompiler.)


    UPDATE

    It is plausible that getClass() is called solely for the side-effect of checking for null. (I've never seen that idiom ... but it would work.) I wouldn't expect it to make the code faster, but it would make it more compact.

    However, if this is being done in the (original) source code, it would appear to be unnecessary. A couple of lines later, the code takes var10001::get and passes it as an argument in a Stream.map call. I'm pretty sure that that evaluating var10001::get will entail checking that var10001 is not null.