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
- You don't need the parentheses surrounding the
p
. For a better readibility, I would suggest to replace(p)
with simply ap
. Hence, your lambda expression will becomep-> p.isHidden()
. - 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:
ContainingClass::staticMethodName
- reference to a static methodcontainingObject::instanceMethodName
- reference to an instance method of a particular objectContainingType::methodName
- reference to an instance method of an arbitrary object of a particular typeClassName::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
Differencebetween a Synchronized Method and Synchronized Block in Java
Find Maximum, Minimum, Sum and Average of a List in Java 8
Any Character Including Newline - Java Regex
Using PDFbox to Write Utf-8 Encoded Strings to a PDF
Spring Boot Actuator Without Spring Boot
Java: Local Variable Mi Defined in an Enclosing Scope Must Be Final or Effectively Final
Where Are Generic Types Stored in Java Class Files
Spring Boot Actuator Application Won't Start on Ubuntu Vps
Java Native Method Source Code
Java How Expensive Is a Method Call
How to Display Bar Value on Top of Bar Javafx
How to Specify the Jdk for a Glassfish Domain
Number of Decimal Digits in a Double
Create Custom Annotation for Lombok
Drag and Drop Custom Object from Jlist into Jlabel