Java 8 stream max() function argument type Comparator vs Comparable
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I wrote some simple code like below. This class works fine without any errors.
public class Test {
public static void main(String args) {
List<Integer> intList = IntStream.of(1,2,3,4,5,6,7,8,9,10).boxed().collect(Collectors.toList());
int value = intList.stream().max(Integer::compareTo).get();
//int value = intList.stream().max(<Comparator<? super T> comparator type should pass here>).get();
System.out.println("value :"+value);
}
}
As the code comment shows the max()
method should pass an argument of type Comparator<? super Integer>
.
But Integer::compareTo
implements Comparable
interface - not Comparator
.
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
How can this work? The max()
method says it needs a Comparator
argument, but it works with Comparable
argument.
I know I have misunderstood something, but I do now know what. Can someone please explain?
java java-8 java-stream
add a comment |
I wrote some simple code like below. This class works fine without any errors.
public class Test {
public static void main(String args) {
List<Integer> intList = IntStream.of(1,2,3,4,5,6,7,8,9,10).boxed().collect(Collectors.toList());
int value = intList.stream().max(Integer::compareTo).get();
//int value = intList.stream().max(<Comparator<? super T> comparator type should pass here>).get();
System.out.println("value :"+value);
}
}
As the code comment shows the max()
method should pass an argument of type Comparator<? super Integer>
.
But Integer::compareTo
implements Comparable
interface - not Comparator
.
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
How can this work? The max()
method says it needs a Comparator
argument, but it works with Comparable
argument.
I know I have misunderstood something, but I do now know what. Can someone please explain?
java java-8 java-stream
4
Integer::compareTo
does not return a Comparable - it is the short definition for: "Please compiler generate a matching implementation for the type that is needed (in this caseComparator
) and map the arguments to the specified function." In this case the function requires two "arguments" (this
and the one parameter ofcompareTo
) and the Comparator provides two arguments -> works.
– Robert
yesterday
6
""Please compiler, generate..." ... compilers always respond best to politeness and courtesy :-)
– scottb
yesterday
1
Related: stackoverflow.com/questions/22561614/…
– Oleksandr
yesterday
add a comment |
I wrote some simple code like below. This class works fine without any errors.
public class Test {
public static void main(String args) {
List<Integer> intList = IntStream.of(1,2,3,4,5,6,7,8,9,10).boxed().collect(Collectors.toList());
int value = intList.stream().max(Integer::compareTo).get();
//int value = intList.stream().max(<Comparator<? super T> comparator type should pass here>).get();
System.out.println("value :"+value);
}
}
As the code comment shows the max()
method should pass an argument of type Comparator<? super Integer>
.
But Integer::compareTo
implements Comparable
interface - not Comparator
.
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
How can this work? The max()
method says it needs a Comparator
argument, but it works with Comparable
argument.
I know I have misunderstood something, but I do now know what. Can someone please explain?
java java-8 java-stream
I wrote some simple code like below. This class works fine without any errors.
public class Test {
public static void main(String args) {
List<Integer> intList = IntStream.of(1,2,3,4,5,6,7,8,9,10).boxed().collect(Collectors.toList());
int value = intList.stream().max(Integer::compareTo).get();
//int value = intList.stream().max(<Comparator<? super T> comparator type should pass here>).get();
System.out.println("value :"+value);
}
}
As the code comment shows the max()
method should pass an argument of type Comparator<? super Integer>
.
But Integer::compareTo
implements Comparable
interface - not Comparator
.
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
How can this work? The max()
method says it needs a Comparator
argument, but it works with Comparable
argument.
I know I have misunderstood something, but I do now know what. Can someone please explain?
java java-8 java-stream
java java-8 java-stream
edited yesterday
MyStackRunnethOver
1,007919
1,007919
asked yesterday
ShalikaShalika
4031618
4031618
4
Integer::compareTo
does not return a Comparable - it is the short definition for: "Please compiler generate a matching implementation for the type that is needed (in this caseComparator
) and map the arguments to the specified function." In this case the function requires two "arguments" (this
and the one parameter ofcompareTo
) and the Comparator provides two arguments -> works.
– Robert
yesterday
6
""Please compiler, generate..." ... compilers always respond best to politeness and courtesy :-)
– scottb
yesterday
1
Related: stackoverflow.com/questions/22561614/…
– Oleksandr
yesterday
add a comment |
4
Integer::compareTo
does not return a Comparable - it is the short definition for: "Please compiler generate a matching implementation for the type that is needed (in this caseComparator
) and map the arguments to the specified function." In this case the function requires two "arguments" (this
and the one parameter ofcompareTo
) and the Comparator provides two arguments -> works.
– Robert
yesterday
6
""Please compiler, generate..." ... compilers always respond best to politeness and courtesy :-)
– scottb
yesterday
1
Related: stackoverflow.com/questions/22561614/…
– Oleksandr
yesterday
4
4
Integer::compareTo
does not return a Comparable - it is the short definition for: "Please compiler generate a matching implementation for the type that is needed (in this case Comparator
) and map the arguments to the specified function." In this case the function requires two "arguments" (this
and the one parameter of compareTo
) and the Comparator provides two arguments -> works.– Robert
yesterday
Integer::compareTo
does not return a Comparable - it is the short definition for: "Please compiler generate a matching implementation for the type that is needed (in this case Comparator
) and map the arguments to the specified function." In this case the function requires two "arguments" (this
and the one parameter of compareTo
) and the Comparator provides two arguments -> works.– Robert
yesterday
6
6
""Please compiler, generate..." ... compilers always respond best to politeness and courtesy :-)
– scottb
yesterday
""Please compiler, generate..." ... compilers always respond best to politeness and courtesy :-)
– scottb
yesterday
1
1
Related: stackoverflow.com/questions/22561614/…
– Oleksandr
yesterday
Related: stackoverflow.com/questions/22561614/…
– Oleksandr
yesterday
add a comment |
4 Answers
4
active
oldest
votes
int value = intList.stream().max(Integer::compareTo).get();
The above snippet of code is logically equivalent to the following:
int value = intList.stream().max((a, b) -> a.compareTo(b)).get();
Which is also logically equivalent to the following:
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
}).get();
Comparator
is a functional interface and can be used as a lambda or method reference, which is why your code compiles and executes successfully.
I recommend reading Oracle's tutorial on Method References (they use an example where two objects are compared) as well as the Java Language Specification on §15.13. Method Reference Expressions to understand why this works.
9
Although it's absolutely correct, it doesn't answer "How can this work?"
– Andrew Tobilko
yesterday
add a comment |
I can relate to your confusion.
We've got a Comparator
's method which declares two parameters
int compare(T o1, T o2);
and we've got an Integer
's method which takes one parameter
int compareTo(Integer anotherInteger)
How on earth does Integer::compareTo
get resolved to a Comparator
instance?
When a method reference points to an instance method, the parser can look for methods with arity n-1
(n
is the expected number of parameters).
Here's an excerpt from the JLS on how applicable methods are identified. I will drop the first part about parsing the expression preceding the ::
token.
Second, given a targeted function type with
n
parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form
ReferenceType :: [TypeArguments] Identifier
, then the potentially applicable methods are:
the member methods of the type to search that would be potentially applicable (§15.12.2.1) for a method invocation which names Identifier, has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression; plus
the member methods of the type to search that would be potentially applicable for a method invocation which names
Identifier
, has arity n-1, has type arguments TypeArguments, and appears in the same class as the method reference expression.
Two different arities,
n
andn-1
, are considered, to account for the possibility that this form refers to either a static method or an instance method.
...
A method reference expression of the form
ReferenceType :: [TypeArguments] Identifier
can be interpreted in different ways. IfIdentifier
refers to an instance method, then the implicit lambda expression has an extra parameter compared to ifIdentifier
refers to a static method.
https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.13.1
If we were to write an implicit lambda expression from that method reference, the first (implicit) parameter would be an instance to call the method on, the second (explicit) parameter would be an argument to pass in the method.
(implicitParam, anotherInteger) -> implicitParam.compareTo(anotherInteger)
Note that a method reference differs from a lambda expression, even though the former can be easily transformed into the latter. A lambda expression needs to be desugared into a new method, while a method reference usually requires only loading a corresponding constant method handle.
Integer::compareTo
implementsComparable
interface - notComparator
.
Integer::compareTo
as an expression doesn't implement any interface. However, it can refer to/represent different functional types, one of which is Comparator<Integer>
.
Comparator<Integer> a = Integer::compareTo;
BiFunction<Integer, Integer, Integer> b = Integer::compareTo;
ToIntBiFunction<Integer, Integer> c = Integer::compareTo;
add a comment |
Integer
implements Comparable
by overriding compareTo
.
That overriden compareTo
, however, can be used in a way that satisfies and implements the Comparator
interface.
In its usage here
int value = intList.stream().max(Integer::compareTo).get();
it's translated to something like
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
}).get();
A method reference (or lambda expression) must satisfy the signature of the corresponding functional interface's single abstract method and, in this case (Comparator
), compareTo
does.
The idea is that max
expects a Comparator
and its compare
method expects two Integer
objects. Integer::compareTo
can satisfy those expectations because it also expects two Integer
objects. The first is its receiver (the instance on which the method is to be called) and the second is the argument. With the new Java 8 syntax, the compiler translates one style to the other.
(compareTo
also returns an int
as required by Comparator#compare
.)
how doesInteger::compareTo
satisfy the signature ofComparator#compare
?compareTo(Integer)
vscompare(Integer, Integer)
?
– Andrew Tobilko
yesterday
I disagree with "the compiler translates one style to the other". I think the compiler may validate a syntactic construct, but not translate it into another one. I am sure the compiler doesn't turn a method reference in a lambda. I didn't downvote your answer, btw.
– Andrew Tobilko
23 hours ago
add a comment |
First trick: all instance methods actually take 1 additional implicit argument, the one you refer to as this
in method body. E.g.:
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(/* Integer this, */ Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
Integer a = 10, b = 100;
int compareResult = a.compareTo(b);
// this actually 'compiles' to Integer#compareTo(this = a, anotherInteger = b)
Second trick: Java compiler can "transform" the signature of a method reference to some functional interface, if the number and types of arguments (including this
) satisfy:
interface MyInterface {
int foo(Integer bar, Integer baz);
}
Integer a = 100, b = 1000;
int result1 = ((Comparator<Integer>) Integer::compareTo).compare(a, b);
int result2 = ((BiFunction<Integer, Integer, Integer>) Integer::compareTo).apply(a, b);
int result3 = ((MyInterface) Integer::compareTo).foo(a, b);
// result1 == result2 == result3
As you can see class Integer
implements none of Comparator
, BiFunction
or a random MyInterface
, but that doesn't stop you from casting the Integer::compareTo
method reference as those interfaces.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55694015%2fjava-8-stream-max-function-argument-type-comparator-vs-comparable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
int value = intList.stream().max(Integer::compareTo).get();
The above snippet of code is logically equivalent to the following:
int value = intList.stream().max((a, b) -> a.compareTo(b)).get();
Which is also logically equivalent to the following:
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
}).get();
Comparator
is a functional interface and can be used as a lambda or method reference, which is why your code compiles and executes successfully.
I recommend reading Oracle's tutorial on Method References (they use an example where two objects are compared) as well as the Java Language Specification on §15.13. Method Reference Expressions to understand why this works.
9
Although it's absolutely correct, it doesn't answer "How can this work?"
– Andrew Tobilko
yesterday
add a comment |
int value = intList.stream().max(Integer::compareTo).get();
The above snippet of code is logically equivalent to the following:
int value = intList.stream().max((a, b) -> a.compareTo(b)).get();
Which is also logically equivalent to the following:
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
}).get();
Comparator
is a functional interface and can be used as a lambda or method reference, which is why your code compiles and executes successfully.
I recommend reading Oracle's tutorial on Method References (they use an example where two objects are compared) as well as the Java Language Specification on §15.13. Method Reference Expressions to understand why this works.
9
Although it's absolutely correct, it doesn't answer "How can this work?"
– Andrew Tobilko
yesterday
add a comment |
int value = intList.stream().max(Integer::compareTo).get();
The above snippet of code is logically equivalent to the following:
int value = intList.stream().max((a, b) -> a.compareTo(b)).get();
Which is also logically equivalent to the following:
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
}).get();
Comparator
is a functional interface and can be used as a lambda or method reference, which is why your code compiles and executes successfully.
I recommend reading Oracle's tutorial on Method References (they use an example where two objects are compared) as well as the Java Language Specification on §15.13. Method Reference Expressions to understand why this works.
int value = intList.stream().max(Integer::compareTo).get();
The above snippet of code is logically equivalent to the following:
int value = intList.stream().max((a, b) -> a.compareTo(b)).get();
Which is also logically equivalent to the following:
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
}).get();
Comparator
is a functional interface and can be used as a lambda or method reference, which is why your code compiles and executes successfully.
I recommend reading Oracle's tutorial on Method References (they use an example where two objects are compared) as well as the Java Language Specification on §15.13. Method Reference Expressions to understand why this works.
edited yesterday
answered yesterday
Jacob G.Jacob G.
16.8k52466
16.8k52466
9
Although it's absolutely correct, it doesn't answer "How can this work?"
– Andrew Tobilko
yesterday
add a comment |
9
Although it's absolutely correct, it doesn't answer "How can this work?"
– Andrew Tobilko
yesterday
9
9
Although it's absolutely correct, it doesn't answer "How can this work?"
– Andrew Tobilko
yesterday
Although it's absolutely correct, it doesn't answer "How can this work?"
– Andrew Tobilko
yesterday
add a comment |
I can relate to your confusion.
We've got a Comparator
's method which declares two parameters
int compare(T o1, T o2);
and we've got an Integer
's method which takes one parameter
int compareTo(Integer anotherInteger)
How on earth does Integer::compareTo
get resolved to a Comparator
instance?
When a method reference points to an instance method, the parser can look for methods with arity n-1
(n
is the expected number of parameters).
Here's an excerpt from the JLS on how applicable methods are identified. I will drop the first part about parsing the expression preceding the ::
token.
Second, given a targeted function type with
n
parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form
ReferenceType :: [TypeArguments] Identifier
, then the potentially applicable methods are:
the member methods of the type to search that would be potentially applicable (§15.12.2.1) for a method invocation which names Identifier, has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression; plus
the member methods of the type to search that would be potentially applicable for a method invocation which names
Identifier
, has arity n-1, has type arguments TypeArguments, and appears in the same class as the method reference expression.
Two different arities,
n
andn-1
, are considered, to account for the possibility that this form refers to either a static method or an instance method.
...
A method reference expression of the form
ReferenceType :: [TypeArguments] Identifier
can be interpreted in different ways. IfIdentifier
refers to an instance method, then the implicit lambda expression has an extra parameter compared to ifIdentifier
refers to a static method.
https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.13.1
If we were to write an implicit lambda expression from that method reference, the first (implicit) parameter would be an instance to call the method on, the second (explicit) parameter would be an argument to pass in the method.
(implicitParam, anotherInteger) -> implicitParam.compareTo(anotherInteger)
Note that a method reference differs from a lambda expression, even though the former can be easily transformed into the latter. A lambda expression needs to be desugared into a new method, while a method reference usually requires only loading a corresponding constant method handle.
Integer::compareTo
implementsComparable
interface - notComparator
.
Integer::compareTo
as an expression doesn't implement any interface. However, it can refer to/represent different functional types, one of which is Comparator<Integer>
.
Comparator<Integer> a = Integer::compareTo;
BiFunction<Integer, Integer, Integer> b = Integer::compareTo;
ToIntBiFunction<Integer, Integer> c = Integer::compareTo;
add a comment |
I can relate to your confusion.
We've got a Comparator
's method which declares two parameters
int compare(T o1, T o2);
and we've got an Integer
's method which takes one parameter
int compareTo(Integer anotherInteger)
How on earth does Integer::compareTo
get resolved to a Comparator
instance?
When a method reference points to an instance method, the parser can look for methods with arity n-1
(n
is the expected number of parameters).
Here's an excerpt from the JLS on how applicable methods are identified. I will drop the first part about parsing the expression preceding the ::
token.
Second, given a targeted function type with
n
parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form
ReferenceType :: [TypeArguments] Identifier
, then the potentially applicable methods are:
the member methods of the type to search that would be potentially applicable (§15.12.2.1) for a method invocation which names Identifier, has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression; plus
the member methods of the type to search that would be potentially applicable for a method invocation which names
Identifier
, has arity n-1, has type arguments TypeArguments, and appears in the same class as the method reference expression.
Two different arities,
n
andn-1
, are considered, to account for the possibility that this form refers to either a static method or an instance method.
...
A method reference expression of the form
ReferenceType :: [TypeArguments] Identifier
can be interpreted in different ways. IfIdentifier
refers to an instance method, then the implicit lambda expression has an extra parameter compared to ifIdentifier
refers to a static method.
https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.13.1
If we were to write an implicit lambda expression from that method reference, the first (implicit) parameter would be an instance to call the method on, the second (explicit) parameter would be an argument to pass in the method.
(implicitParam, anotherInteger) -> implicitParam.compareTo(anotherInteger)
Note that a method reference differs from a lambda expression, even though the former can be easily transformed into the latter. A lambda expression needs to be desugared into a new method, while a method reference usually requires only loading a corresponding constant method handle.
Integer::compareTo
implementsComparable
interface - notComparator
.
Integer::compareTo
as an expression doesn't implement any interface. However, it can refer to/represent different functional types, one of which is Comparator<Integer>
.
Comparator<Integer> a = Integer::compareTo;
BiFunction<Integer, Integer, Integer> b = Integer::compareTo;
ToIntBiFunction<Integer, Integer> c = Integer::compareTo;
add a comment |
I can relate to your confusion.
We've got a Comparator
's method which declares two parameters
int compare(T o1, T o2);
and we've got an Integer
's method which takes one parameter
int compareTo(Integer anotherInteger)
How on earth does Integer::compareTo
get resolved to a Comparator
instance?
When a method reference points to an instance method, the parser can look for methods with arity n-1
(n
is the expected number of parameters).
Here's an excerpt from the JLS on how applicable methods are identified. I will drop the first part about parsing the expression preceding the ::
token.
Second, given a targeted function type with
n
parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form
ReferenceType :: [TypeArguments] Identifier
, then the potentially applicable methods are:
the member methods of the type to search that would be potentially applicable (§15.12.2.1) for a method invocation which names Identifier, has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression; plus
the member methods of the type to search that would be potentially applicable for a method invocation which names
Identifier
, has arity n-1, has type arguments TypeArguments, and appears in the same class as the method reference expression.
Two different arities,
n
andn-1
, are considered, to account for the possibility that this form refers to either a static method or an instance method.
...
A method reference expression of the form
ReferenceType :: [TypeArguments] Identifier
can be interpreted in different ways. IfIdentifier
refers to an instance method, then the implicit lambda expression has an extra parameter compared to ifIdentifier
refers to a static method.
https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.13.1
If we were to write an implicit lambda expression from that method reference, the first (implicit) parameter would be an instance to call the method on, the second (explicit) parameter would be an argument to pass in the method.
(implicitParam, anotherInteger) -> implicitParam.compareTo(anotherInteger)
Note that a method reference differs from a lambda expression, even though the former can be easily transformed into the latter. A lambda expression needs to be desugared into a new method, while a method reference usually requires only loading a corresponding constant method handle.
Integer::compareTo
implementsComparable
interface - notComparator
.
Integer::compareTo
as an expression doesn't implement any interface. However, it can refer to/represent different functional types, one of which is Comparator<Integer>
.
Comparator<Integer> a = Integer::compareTo;
BiFunction<Integer, Integer, Integer> b = Integer::compareTo;
ToIntBiFunction<Integer, Integer> c = Integer::compareTo;
I can relate to your confusion.
We've got a Comparator
's method which declares two parameters
int compare(T o1, T o2);
and we've got an Integer
's method which takes one parameter
int compareTo(Integer anotherInteger)
How on earth does Integer::compareTo
get resolved to a Comparator
instance?
When a method reference points to an instance method, the parser can look for methods with arity n-1
(n
is the expected number of parameters).
Here's an excerpt from the JLS on how applicable methods are identified. I will drop the first part about parsing the expression preceding the ::
token.
Second, given a targeted function type with
n
parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form
ReferenceType :: [TypeArguments] Identifier
, then the potentially applicable methods are:
the member methods of the type to search that would be potentially applicable (§15.12.2.1) for a method invocation which names Identifier, has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression; plus
the member methods of the type to search that would be potentially applicable for a method invocation which names
Identifier
, has arity n-1, has type arguments TypeArguments, and appears in the same class as the method reference expression.
Two different arities,
n
andn-1
, are considered, to account for the possibility that this form refers to either a static method or an instance method.
...
A method reference expression of the form
ReferenceType :: [TypeArguments] Identifier
can be interpreted in different ways. IfIdentifier
refers to an instance method, then the implicit lambda expression has an extra parameter compared to ifIdentifier
refers to a static method.
https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.13.1
If we were to write an implicit lambda expression from that method reference, the first (implicit) parameter would be an instance to call the method on, the second (explicit) parameter would be an argument to pass in the method.
(implicitParam, anotherInteger) -> implicitParam.compareTo(anotherInteger)
Note that a method reference differs from a lambda expression, even though the former can be easily transformed into the latter. A lambda expression needs to be desugared into a new method, while a method reference usually requires only loading a corresponding constant method handle.
Integer::compareTo
implementsComparable
interface - notComparator
.
Integer::compareTo
as an expression doesn't implement any interface. However, it can refer to/represent different functional types, one of which is Comparator<Integer>
.
Comparator<Integer> a = Integer::compareTo;
BiFunction<Integer, Integer, Integer> b = Integer::compareTo;
ToIntBiFunction<Integer, Integer> c = Integer::compareTo;
edited 23 hours ago
answered yesterday
Andrew TobilkoAndrew Tobilko
28.8k104592
28.8k104592
add a comment |
add a comment |
Integer
implements Comparable
by overriding compareTo
.
That overriden compareTo
, however, can be used in a way that satisfies and implements the Comparator
interface.
In its usage here
int value = intList.stream().max(Integer::compareTo).get();
it's translated to something like
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
}).get();
A method reference (or lambda expression) must satisfy the signature of the corresponding functional interface's single abstract method and, in this case (Comparator
), compareTo
does.
The idea is that max
expects a Comparator
and its compare
method expects two Integer
objects. Integer::compareTo
can satisfy those expectations because it also expects two Integer
objects. The first is its receiver (the instance on which the method is to be called) and the second is the argument. With the new Java 8 syntax, the compiler translates one style to the other.
(compareTo
also returns an int
as required by Comparator#compare
.)
how doesInteger::compareTo
satisfy the signature ofComparator#compare
?compareTo(Integer)
vscompare(Integer, Integer)
?
– Andrew Tobilko
yesterday
I disagree with "the compiler translates one style to the other". I think the compiler may validate a syntactic construct, but not translate it into another one. I am sure the compiler doesn't turn a method reference in a lambda. I didn't downvote your answer, btw.
– Andrew Tobilko
23 hours ago
add a comment |
Integer
implements Comparable
by overriding compareTo
.
That overriden compareTo
, however, can be used in a way that satisfies and implements the Comparator
interface.
In its usage here
int value = intList.stream().max(Integer::compareTo).get();
it's translated to something like
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
}).get();
A method reference (or lambda expression) must satisfy the signature of the corresponding functional interface's single abstract method and, in this case (Comparator
), compareTo
does.
The idea is that max
expects a Comparator
and its compare
method expects two Integer
objects. Integer::compareTo
can satisfy those expectations because it also expects two Integer
objects. The first is its receiver (the instance on which the method is to be called) and the second is the argument. With the new Java 8 syntax, the compiler translates one style to the other.
(compareTo
also returns an int
as required by Comparator#compare
.)
how doesInteger::compareTo
satisfy the signature ofComparator#compare
?compareTo(Integer)
vscompare(Integer, Integer)
?
– Andrew Tobilko
yesterday
I disagree with "the compiler translates one style to the other". I think the compiler may validate a syntactic construct, but not translate it into another one. I am sure the compiler doesn't turn a method reference in a lambda. I didn't downvote your answer, btw.
– Andrew Tobilko
23 hours ago
add a comment |
Integer
implements Comparable
by overriding compareTo
.
That overriden compareTo
, however, can be used in a way that satisfies and implements the Comparator
interface.
In its usage here
int value = intList.stream().max(Integer::compareTo).get();
it's translated to something like
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
}).get();
A method reference (or lambda expression) must satisfy the signature of the corresponding functional interface's single abstract method and, in this case (Comparator
), compareTo
does.
The idea is that max
expects a Comparator
and its compare
method expects two Integer
objects. Integer::compareTo
can satisfy those expectations because it also expects two Integer
objects. The first is its receiver (the instance on which the method is to be called) and the second is the argument. With the new Java 8 syntax, the compiler translates one style to the other.
(compareTo
also returns an int
as required by Comparator#compare
.)
Integer
implements Comparable
by overriding compareTo
.
That overriden compareTo
, however, can be used in a way that satisfies and implements the Comparator
interface.
In its usage here
int value = intList.stream().max(Integer::compareTo).get();
it's translated to something like
int value = intList.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
}).get();
A method reference (or lambda expression) must satisfy the signature of the corresponding functional interface's single abstract method and, in this case (Comparator
), compareTo
does.
The idea is that max
expects a Comparator
and its compare
method expects two Integer
objects. Integer::compareTo
can satisfy those expectations because it also expects two Integer
objects. The first is its receiver (the instance on which the method is to be called) and the second is the argument. With the new Java 8 syntax, the compiler translates one style to the other.
(compareTo
also returns an int
as required by Comparator#compare
.)
edited yesterday
answered yesterday
SaviorSavior
1,61021331
1,61021331
how doesInteger::compareTo
satisfy the signature ofComparator#compare
?compareTo(Integer)
vscompare(Integer, Integer)
?
– Andrew Tobilko
yesterday
I disagree with "the compiler translates one style to the other". I think the compiler may validate a syntactic construct, but not translate it into another one. I am sure the compiler doesn't turn a method reference in a lambda. I didn't downvote your answer, btw.
– Andrew Tobilko
23 hours ago
add a comment |
how doesInteger::compareTo
satisfy the signature ofComparator#compare
?compareTo(Integer)
vscompare(Integer, Integer)
?
– Andrew Tobilko
yesterday
I disagree with "the compiler translates one style to the other". I think the compiler may validate a syntactic construct, but not translate it into another one. I am sure the compiler doesn't turn a method reference in a lambda. I didn't downvote your answer, btw.
– Andrew Tobilko
23 hours ago
how does
Integer::compareTo
satisfy the signature of Comparator#compare
? compareTo(Integer)
vs compare(Integer, Integer)
?– Andrew Tobilko
yesterday
how does
Integer::compareTo
satisfy the signature of Comparator#compare
? compareTo(Integer)
vs compare(Integer, Integer)
?– Andrew Tobilko
yesterday
I disagree with "the compiler translates one style to the other". I think the compiler may validate a syntactic construct, but not translate it into another one. I am sure the compiler doesn't turn a method reference in a lambda. I didn't downvote your answer, btw.
– Andrew Tobilko
23 hours ago
I disagree with "the compiler translates one style to the other". I think the compiler may validate a syntactic construct, but not translate it into another one. I am sure the compiler doesn't turn a method reference in a lambda. I didn't downvote your answer, btw.
– Andrew Tobilko
23 hours ago
add a comment |
First trick: all instance methods actually take 1 additional implicit argument, the one you refer to as this
in method body. E.g.:
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(/* Integer this, */ Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
Integer a = 10, b = 100;
int compareResult = a.compareTo(b);
// this actually 'compiles' to Integer#compareTo(this = a, anotherInteger = b)
Second trick: Java compiler can "transform" the signature of a method reference to some functional interface, if the number and types of arguments (including this
) satisfy:
interface MyInterface {
int foo(Integer bar, Integer baz);
}
Integer a = 100, b = 1000;
int result1 = ((Comparator<Integer>) Integer::compareTo).compare(a, b);
int result2 = ((BiFunction<Integer, Integer, Integer>) Integer::compareTo).apply(a, b);
int result3 = ((MyInterface) Integer::compareTo).foo(a, b);
// result1 == result2 == result3
As you can see class Integer
implements none of Comparator
, BiFunction
or a random MyInterface
, but that doesn't stop you from casting the Integer::compareTo
method reference as those interfaces.
add a comment |
First trick: all instance methods actually take 1 additional implicit argument, the one you refer to as this
in method body. E.g.:
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(/* Integer this, */ Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
Integer a = 10, b = 100;
int compareResult = a.compareTo(b);
// this actually 'compiles' to Integer#compareTo(this = a, anotherInteger = b)
Second trick: Java compiler can "transform" the signature of a method reference to some functional interface, if the number and types of arguments (including this
) satisfy:
interface MyInterface {
int foo(Integer bar, Integer baz);
}
Integer a = 100, b = 1000;
int result1 = ((Comparator<Integer>) Integer::compareTo).compare(a, b);
int result2 = ((BiFunction<Integer, Integer, Integer>) Integer::compareTo).apply(a, b);
int result3 = ((MyInterface) Integer::compareTo).foo(a, b);
// result1 == result2 == result3
As you can see class Integer
implements none of Comparator
, BiFunction
or a random MyInterface
, but that doesn't stop you from casting the Integer::compareTo
method reference as those interfaces.
add a comment |
First trick: all instance methods actually take 1 additional implicit argument, the one you refer to as this
in method body. E.g.:
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(/* Integer this, */ Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
Integer a = 10, b = 100;
int compareResult = a.compareTo(b);
// this actually 'compiles' to Integer#compareTo(this = a, anotherInteger = b)
Second trick: Java compiler can "transform" the signature of a method reference to some functional interface, if the number and types of arguments (including this
) satisfy:
interface MyInterface {
int foo(Integer bar, Integer baz);
}
Integer a = 100, b = 1000;
int result1 = ((Comparator<Integer>) Integer::compareTo).compare(a, b);
int result2 = ((BiFunction<Integer, Integer, Integer>) Integer::compareTo).apply(a, b);
int result3 = ((MyInterface) Integer::compareTo).foo(a, b);
// result1 == result2 == result3
As you can see class Integer
implements none of Comparator
, BiFunction
or a random MyInterface
, but that doesn't stop you from casting the Integer::compareTo
method reference as those interfaces.
First trick: all instance methods actually take 1 additional implicit argument, the one you refer to as this
in method body. E.g.:
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(/* Integer this, */ Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
Integer a = 10, b = 100;
int compareResult = a.compareTo(b);
// this actually 'compiles' to Integer#compareTo(this = a, anotherInteger = b)
Second trick: Java compiler can "transform" the signature of a method reference to some functional interface, if the number and types of arguments (including this
) satisfy:
interface MyInterface {
int foo(Integer bar, Integer baz);
}
Integer a = 100, b = 1000;
int result1 = ((Comparator<Integer>) Integer::compareTo).compare(a, b);
int result2 = ((BiFunction<Integer, Integer, Integer>) Integer::compareTo).apply(a, b);
int result3 = ((MyInterface) Integer::compareTo).foo(a, b);
// result1 == result2 == result3
As you can see class Integer
implements none of Comparator
, BiFunction
or a random MyInterface
, but that doesn't stop you from casting the Integer::compareTo
method reference as those interfaces.
edited 12 hours ago
answered 12 hours ago
TairTair
3,1091329
3,1091329
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55694015%2fjava-8-stream-max-function-argument-type-comparator-vs-comparable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
4
Integer::compareTo
does not return a Comparable - it is the short definition for: "Please compiler generate a matching implementation for the type that is needed (in this caseComparator
) and map the arguments to the specified function." In this case the function requires two "arguments" (this
and the one parameter ofcompareTo
) and the Comparator provides two arguments -> works.– Robert
yesterday
6
""Please compiler, generate..." ... compilers always respond best to politeness and courtesy :-)
– scottb
yesterday
1
Related: stackoverflow.com/questions/22561614/…
– Oleksandr
yesterday