What Does "An Arbitrary Object of a Particular Type" Mean in Java 8

What does an Arbitrary Object of a Particular Type mean in java 8?

It is a reference to an instance method from some type. In the case of the example, compareToIgnoreCase is a method from String. The program knows that it can invoke this method on an instance of String, so it can take the reference and any object of that type and be guaranteed the method exists.

I would compare this to the Method class in that they refer to a method and can be invoked on an arbitrary instance of some type.

For the example, it can use two String objects and call compareToIgnoreCase on one and use the other as an argument to match the method signature. This allows it to take the array and sort it based on any method of the array type instead of requiring a comparator instance to do this instead.

And here is the example for anyone who didn't click on the link in the question:

String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda", "George" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

Java 8 Method reference to instance method of an arbitrary object of a particular type

Because you referred to it as

MethodRefTest::passMeAround

You should have referred to it as

this::passMeAround

providing the instance to use for context.

A different way to view your current code is to say that MethodRefTest::passMeAround is a BiFunction<MethodRefTest, String, String> and this lambda shape does not match the target site. So, alternatively, you may have written

public BiFunction<MethodRefTest, String, String> testReferences() {
return MethodRefTest::passMeAround;
}

and in the main method

final MethodRefTest t = new MethodRefTest();
t.testReferences().apply( t, "foo" );

The material you have been reading may not be instructive enough, so let me expand. With

this::passMeAround

you get a lambda object which has captured the this instance from the context where it was created, but with

MethodRefTest::passMeAround

you get a "pure", non-capturing lambda which represents the invocation of the specified method on some instance, with some string argument, so when you apply it, you need to pass in both.

What is exactly a reference to an Instance Method of an Arbitrary Object of a Particular Type?

Method references are a feature introduced with Java 8. They are related to lambda expressions. Before Java 8, lamdas were not available as a language feature and if you wanted to pass a method/function to another method, you had to emulate it by passing either a named class instance or an anonymous class instance.

Semantically, these three statements are equivalent:

Arrays.sort(stringArray, String::compareToIgnoreCase);
Arrays.sort(stringArray, (s1, s2) -> s1.compareToIgnoreCase(s2));
Arrays.sort(stringArray, new Comparator<String>() {
@Override
public int compare(final String s1, final String s2) {
return s1.compareToIgnoreCase(s2);
}
});

Reference to an instance method of an arbitrary object of a particular type... not working with custom classes?

For a class method reference, the first Function type parameter is the type of the class and the second is the return type of the function. Try:

Function<App, String> f2 = App::toString;

How is method reference syntax working in Java 8

What is a method refernce

You can see a method reference as a lambda expression, that call an existing method.

Kinds of method references

There are four kinds of method references:

  • Reference to a static method: ContainingClass::staticMethodName
  • Reference to an instance method of a particular object: containingObject::instanceMethodName
  • Reference to an instance method of an arbitrary object of a particular type: ContainingType::methodName
  • Reference to a constructor: ClassName::new

How to understand it?

The following expression that lists all hidden files:
f.listFiles(p -> p.isHidden());

This expression is composed by the instance method listFiles(FileFilter) and your lambda expression p -> p.isHidden() that is not a anonymous method but an existing instance method of the class File.

Note that FileFilter is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. Hence, you can write your expression f.listFiles(File::isHidden);

Side notes

  1. You don't need the parentheses surrounding the p. For a better readibility, I would suggest to replace (p) with simply a p. Hence, your lambda expression will become p-> p.isHidden().
  2. Your for loop can be replaced by an enhanced for loop:
for (File value : hidden) {
System.out.println(value);
}

Documentation:

Method reference

FileFilter

Method reference for static and instance methods

Why it is not allowing AppTest::makeUppercase?

The short answer is that AppTest::makeUppercase isn't valid "reference to an instance method of an arbitrary object of a particular type".
AppTest::makeUppercase must implement interface Function<AppTest, String> to be valid reference.

Details:

There are 4 kinds of method references in Java:

  1. ContainingClass::staticMethodName - reference to a static method
  2. containingObject::instanceMethodName - reference to an instance method of a particular object
  3. ContainingType::methodName - reference to an instance method of an arbitrary object of a particular type
  4. ClassName::new - reference to a constructor

Every single kind of method reference requires corresponding Function interface implementation.
You use as a parameter the reference to an instance method of an arbitrary object of a particular type.
This kind of method reference has no explicit parameter variable in a method reference and requires implementation of the interface Function<ContainingType, String>. In other words, the type of the left operand has to be AppTest to make AppTest::makeUppercase compilable. String::toUpperCase works properly because the type of parameter and type of the instance are the same - String.

import static java.lang.System.out;

import java.util.Arrays;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

class ReferenceSource {

private String value;

public ReferenceSource() {
}

public ReferenceSource(String value) {
this.value = value;
}

public String doInstanceMethodOfParticularObject(final String value) {
return ReferenceSource.toUpperCase(value);
}

public static String doStaticMethod(final String value) {
return ReferenceSource.toUpperCase(value);
}

public String doInstanceMethodOfArbitraryObjectOfParticularType() {
return ReferenceSource.toUpperCase(this.value);
}

private static String toUpperCase(final String value) {
return Optional.ofNullable(value).map(String::toUpperCase).orElse("");
}
}

public class Main {
public static void main(String... args) {
// #1 Ref. to a constructor
final Supplier<ReferenceSource> refConstructor = ReferenceSource::new;
final Function<String, ReferenceSource> refParameterizedConstructor = value -> new ReferenceSource(value);

final ReferenceSource methodReferenceInstance = refConstructor.get();

// #2 Ref. to an instance method of a particular object
final UnaryOperator<String> refInstanceMethodOfParticularObject = methodReferenceInstance::doInstanceMethodOfParticularObject;

// #3 Ref. to a static method
final UnaryOperator<String> refStaticMethod = ReferenceSource::doStaticMethod;

// #4 Ref. to an instance method of an arbitrary object of a particular type
final Function<ReferenceSource, String> refInstanceMethodOfArbitraryObjectOfParticularType = ReferenceSource::doInstanceMethodOfArbitraryObjectOfParticularType;

Arrays.stream(new String[] { "a", "b", "c" }).map(refInstanceMethodOfParticularObject).forEach(out::print);
Arrays.stream(new String[] { "d", "e", "f" }).map(refStaticMethod).forEach(out::print);
Arrays.stream(new String[] { "g", "h", "i" }).map(refParameterizedConstructor).map(refInstanceMethodOfArbitraryObjectOfParticularType)
.forEach(out::print);
}
}

Additionally, you could take a look at this and that thread.



Related Topics



Leave a reply



Submit