method references: type inference, toString()
Paul Holser
pholser at gmail.com
Tue Feb 21 14:31:29 PST 2012
Hi lambda-dev,
Using JDK 8 Developer Preview with lambda support
(http://download.java.net/lambda/b25/windows-i586/lambda-8-b25-windows-i586-05_feb_2012.zip),
Guava 11.0, Hamcrest 1.3.RC2, and JUnit 4.10 (sans Hamcrest classes).
org.hamcrest.Matcher is not a SAM type, whereas
com.google.common.base.Predicate is.
Compiling Main.java:
==== begin Main.java ====
import com.google.common.base.Predicate;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
interface Foo {
boolean isBar();
}
abstract class PredicateMatcher<T> extends TypeSafeMatcher<T> {
protected final Predicate<? super T> predicate;
private PredicateMatcher(Predicate<? super T> predicate) {
this.predicate = predicate;
}
@Override public final boolean matchesSafely(T target) {
return predicate.apply(target);
}
public static <U> PredicateMatcher<U> matches(Predicate<? super U>
predicate) {
return new PredicateMatcher<U>(predicate) {
@Override public void describeTo(Description description) {
description.appendText("a value acceptable to predicate ");
description.appendValue(this.predicate);
}
};
}
}
class BarredUpFoo implements Foo {
@Override public boolean isBar() {
return true;
}
}
class BarredUpFooTest {
@Test public void bar() {
assertThat(new BarredUpFoo(), PredicateMatcher.matches(Foo::isBar));
}
}
public class Main {
public static void main(String... args) {
Predicate<Foo> bar = Foo::isBar;
System.out.println(bar);
}
}
==== end Main.java ====
yields:
==== begin console output ====
Main.java:41: error: no suitable method found for matches(member reference)
assertThat(new BarredUpFoo(), PredicateMatcher.matches(Foo::isBar));
^
method PredicateMatcher.<U>matches(Predicate<? super U>) is not applicable
(cyclic inference - cannot infer target type for given lambda/method refer
ence expression)
method TypeSafeMatcher.matches(Object) is not applicable
(actual argument member reference cannot be converted to Object by method
invocation conversion
(the target type of a lambda conversion must be an interface))
where U is a type-variable:
U extends Object declared in method <U>matches(Predicate<? super U>)
1 error
==== end console output ====
Couple of questions:
1) Should the usage of Foo::isBar as the predicate fed to
PredicateMatcher.matches() compile successfully? I'm hoping not to
have to perform the SAM conversion by hand:
Predicate<Foo> bar = Foo::isBar;
assertThat(new BarredUpFoo(), PredicateMatcher.matches(bar);
In Main.main(), I perform that SAM conversion by hand, as you can see
-- otherwise, it won't know to choose PrintStream.println(Object), it
says "(actual argument member reference cannot be converted to Object
by method invocation conversion)".
2) Wondering if it wouldn't be too much trouble to have method
references respond to toString() with something like "Foo::isBar" or
"method isBar on class Foo", instead of, e.g. "Main$1 at a30a4e". It'd
make the output of PredicateMatcher.matches() really slick.
Thanks for the help, and the great work thus far!
Cheers,
Paul Holser
More information about the lambda-dev
mailing list