1

Section 15.13 of the Java Language Specification for Java 8 describes this form of the method reference syntax for creating a constructor reference:

    ClassType :: [TypeArguments] new

For example:

    String s = "abc";
    UnaryOperator<String> test0 = String::new; // String(String) constructor.
    String s0 = test0.apply(s);
    System.out.println("s0 = " + s0); // Prints "abc".

    char[] chars = {'x','y','z'};
    Function<char[], String> test1 = String::new; // String(char[]) constructor.
    String s1 = test1.apply(chars);
    System.out.println("s1 = " + s1); // Prints "xyz"

That all works fine, but it seems that absolutely anything (excluding primitives) can be also supplied for the [TypeArguments] and everything still works:

Here's a silly example to prove the point:

    Function<String, String> test2 = String::<LocalDateTime, Thread[]>new; // Compiles !!!???
    String s2 = test2.apply("123");
    System.out.println("s2 = " + s2); // Prints "123"

A few questions arising:

[1] Since the String class doesn't even use generics, is it valid that the compiler allows the creation of that test2 constructor reference with those meaningless [TypeArguments]?

[2] What would be a meaningful example of using [TypeArguments] when creating a constructor reference?

[3] Under what conditions is it essential to specify [TypeArguments] when creating a constructor reference?

skomisa
  • 16,436
  • 7
  • 61
  • 102

1 Answers1

5

1 15.13.1. Compile-Time Declaration of a Method Reference

If the method reference expression has the form ClassType :: [TypeArguments] new, the potentially applicable methods are a set of notional methods corresponding to the constructors of ClassType. ...

Otherwise, the candidate notional member methods are the constructors of ClassType, treated as if they were methods with return type ClassType. Among these candidates, the methods with appropriate accessibility, arity (n), and type argument arity (derived from [TypeArguments]) are selected, as specified in §15.12.2.1.

JLS 15.12.2.1. Identify Potentially Applicable Methods

This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored.

2 Whenever a constructor is parameterized. I've never stumbled upon one.

public class Foo {

   public <T> Foo(T parameter) {
...
Function<String, Foo> test = Foo::<String>new

3 When the compiler can't infer the type.

a better oliver
  • 26,330
  • 2
  • 58
  • 66
  • Re [1], section 15.12 of JLS relates to method invocation, not class instance creation, which is discussed in 15.9. Section 15.9.1 states "If ClassOrInterfaceTypeToInstantiate ends with TypeArguments, then ClassOrInterfaceTypeToInstantiate must denote a well-formed parameterized class, or a compile-time error occurs.". That suggests that the final example I gave should not have compiled, since the String class does not use type arguments. And I'm wary of assuming that any rules for method references automatically apply to constructor references. – skomisa Mar 20 '15 at 19:25
  • 1
    15.13 refers to 15.12.2.1. It's about finding the appropriate method. The constructor is regarded as method in this case. It's called method reference after all. 15.9. doesn't apply here, as your example is about method references. I expanded my answer. – a better oliver Mar 20 '15 at 19:43
  • Re "your example is about method references": well...yes and no. I am using the double colon syntax for method references, but all my examples are clearly about constructor references (as opposed to method references), since they are all using "::new". I'd be fine if JLS stated that if [TypeArgument] is not meaningful or relevant it is simply ignored for constructor references. But I don't see that, so it looks like a compiler error to me; my final example obviously contains gibberish which the compiler is happily accepting. – skomisa Mar 20 '15 at 20:12
  • 2
    `ClassType :: [TypeArguments] new` **is** a method reference. There is no such thing as a constructor reference (as for the specification that is). The JLS describes it as a reference to a _**notional method** corresponding to the constructor_. There's no point in arguing against the JLS. – a better oliver Mar 20 '15 at 21:51