Consider this Minimal, Reproducible Example :
interface Code {
static void main(String[] args) {
symbol(
String.valueOf(
true ? 'a' :
true ? 'b' :
true ? 'c' :
fail()
)
);
}
private static void symbol(String symbol) {
System.out.println(symbol);
}
private static <R> R fail() {
throw null;
}
}
(Being near minimal, true is a stand in for a useful boolean expression. We can ignore beyond the first ? : (in the real code, there are lots).)
This 'obviously' gives the error.
4: reference to valueOf is ambiguous
both method valueOf(java.lang.Object) in java.lang.String and method valueOf(char) in java.lang.String match
Okay let's fix it. It's the String.valueOf(Object) overload I want - I might later want to add:
true ? "sss" :
(In fact I did have something similar earlier, but have now removed the feature.)
String.valueOf((Object)(
true ? 'a' :
fail()
))
This gives the warning:
4: redundant cast to java.lang.Object
Is this a bug in the compiler warning or error, and how do I fix it so the code is reasonable and there are no warnings or errors?
(Edits: I've change the MRE slightly. throws Throwable was from a template. The real code does use literal chars* and String.valueOf Elsewhere it uses the String.valueOf(char) overload, so toString() is problematic (oh Java!). The code avoids global state, such as System.out, and symbol and fail are in different classes. The "switch" is of a non-enumerable type. fail is a companion to an assert-like method, so that's why it throws an (unchecked non-null) exception internally.
How I actually fixed it was, unrelatedly, I rearranged code so there were some literal strings in there too. Otherwise, I would have used the pointless Object.class.cast equivalent of (Object). What I really want to know is: wtf?
*Actually the real real code goes through a lexer for a different language that doesn't distinguish between literal char, string, various numbers, boolean, enums, etc. Why would it?)