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?)