Java 8 autoboxing + generics: different behaviour with variable vs. method

前端 未结 4 754
日久生厌
日久生厌 2021-02-07 07:43

I found a piece of code that after switching from Java 7 to Java 8 stopped compiling. It does not feature any of the new Java 8 stuff like lambda or streams.

I narrowed

4条回答
  •  一生所求
    2021-02-07 08:01

    Method invocation expressions are special in that they may be Poly Expressions, subject to target typing.

    Consider the following examples:

    static Double aDouble() {
        return 0D;
    }
    …
    Double d = g == null ? 0 : aDouble();
    

    this compiles without any problems

    static  T any() {
        return null;
    }
    …
    Double d = g == null ? 0 : any();
    

    here, the invocation of any() is a Poly Expression and the compiler has to infer T := Double. This reproduces the same error.

    This is the first inconsistency. While your method getData() refers to the type parameter T of GenericData, it is not a generic method (there is/should be no type inference involved to determine that T is Double here.

    JLS §8.4.4. Generic Methods

    A method is generic if it declares one or more type variables

    getData() doesn’t declare type variables, it only uses one.

    JLS §15.12. Method Invocation Expressions:

    A method invocation expression is a poly expression if all of the following are true:

    • The method to be invoked, as determined by the following subsections, is generic (§8.4.4) and has a return type that mentions at least one of the method's type parameters.

    Since this method invocation is not a poly expression, it should behave like the example with the aDouble() invocation, rather than the any().

    But note §15.25.3:

    Note that a reference conditional expression does not have to contain a poly expression as an operand in order to be a poly expression. It is a poly expression simply by virtue of the context in which it appears. For example, in the following code, the conditional expression is a poly expression, and each operand is considered to be in an assignment context targeting Class:

    Class choose(boolean b,
                                  Class c1,
                                  Class c2) {
        return b ? c1 : c2;
    }
    

    So, is it a reference conditional or a numeric conditional expression?

    §15.25. Conditional Operator ? : says:

    There are three kinds of conditional expressions, classified according to the second and third operand expressions: boolean conditional expressions, numeric conditional expressions, and reference conditional expressions. The classification rules are as follows:

    • If both the second and the third operand expressions are boolean expressions, the conditional expression is a boolean conditional expression.
    • If both the second and the third operand expressions are numeric expressions, the conditional expression is a numeric conditional expression.
      For the purpose of classifying a conditional, the following expressions are numeric expressions:
      • An expression of a standalone form (§15.2) with a type that is convertible to a numeric type (§4.2, §5.1.8).
      • A parenthesized numeric expression (§15.8.5).
      • A class instance creation expression (§15.9) for a class that is convertible to a numeric type.
      • A method invocation expression (§15.12) for which the chosen most specific method (§15.12.2.5) has a return type that is convertible to a numeric type.
      • A numeric conditional expression.
    • Otherwise, the conditional expression is a reference conditional expression.

    So according to these rules, not precluding generic method invocations, all of the shown conditional expressions are numeric conditional expression and should work, as only “otherwise” they are to be considered to be reference conditional expression. The Eclipse version, I tested, compiled all of them without reporting any error.

    This leads to the strange situation that for the any() case we need target typing to find out that it has a numeric return type and deducing that the conditional is a numeric conditional expression, i.e. a stand-alone expression. Note that for boolean conditional expressions, there is the remark:

    Note that, for a generic method, this is the type before instantiating the method's type arguments.

    but for numeric conditional expression, there’s no such note, whether intentional or not.

    But as said, this only applies to the any() example anyway, as the getData() method is not generic.

提交回复
热议问题