Is it possible to use method reference with static method of interface? - java

This is my first code:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator.reverseOrder()).forEach(System.out::print);
//...
}
}
Result: grizzlybrown bear
This is my second code:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator::reverseOrder()).forEach(System.out::print);
//...
}
}
Result: compiler error
My questions:
Why is there a compiler error in the second code?
Can't I use the method reference for static method of functional interface?
I know I can't use method reference with default method of functional interface.
I know I can use method reference with a class in 5 cases:
Class
Class::staticMethod
Class::instanceMethod
instance::instanceMethod
Class::new
Functional Interface
Interface::abstractMethod
Thanks a lot!

Comparator.reverseOrder() is an expression which resolves to the Comparator type, because that's what it returns.
Comparator::reverseOrder is an expression which resolves to a method which takes no arguments and returns a Comparator e.g. a Supplier<Comparator<String>>, though it could be any matching functional interface.
In the second instance you are trying to pass a method (which provides a Comparator) as an argument. The method doesn't want that - it just wants the Comparator itself.
You could think of it like this (just pseudo-code to demonstrate the point):
s.sorted(new Comparator())
vs
s.sorted(new Supplier(new Comparator()))
To answer your second question as to whether it's ever possible to use a method reference for a static method of an interface - yes, absolutely!
If we declare the following method:
<T> void giveMeAComparatorSupplier(Supplier<Comparator<T>> supplier) { }
then we can definitely call it with a method reference
giveMeAComparatorSupplier(Comparator::reverseOrder);
(And FYI your method reference syntax is wrong - it never uses ())

Two things are wrong with your second code. First, method references do not use parentheses or arguments at all. You would need to supply only the method that would be called later; you are not calling the method at that point.
Second, the sorted method takes a Comparator, not a functional interface that would supply a Comparator. The method needs a Comparator already created and ready to go, not a functional interface that will supply a Comparator when needed.
It has nothing to do with the fact that Comparator is an interface; one can generally create a method reference to a static interface method. It has everything to do with the fact that sorted needs an actual Comparator instance and not an instance of a functional interface, which is when you could supply a method reference.
So even if you take off the parentheses, it still won't compile. Only your first code, which directly passes a Comparator, will compile and work as expected.

Related

Can you explain why the first unwrapped method reference does not compile?

In this example, passing a method reference to Stream.of does not work but once it's wrapped it works. I can't quite get my head around why this is. Isn't the method reference equivalent to the functional interface?
public class A {
String a() {
return "";
}
void b() {
Stream.of(this::a); // won't compile
Stream.of(wrap(this::a)); // will compile
}
static <T> Supplier<T> wrap(Supplier<T> f) {
return f;
}
}
Stream.of has the following signature:
public static<T> Stream<T> of(T t)
The following example will compile because you explicitly providing a type information for T.
Stream<Supplier<String>> a = Stream.of(this::a);
The first example Stream.of(this::a); equivalent to:
Object a = this::a;
where Object is not a functional interface and will not compile.
Providing with a functional interface this example compiles:
Runnable a = this::a;
Stream.of(a);
In the second example, wrap provides a functional interface Supplier
Stream.of(T) expects an Object and you pass to it a method reference in the first statement. But an Object parameter is not a functional interface, so it cannot accept a method reference or a lambda that is not specifically typed.
With lambda, it would produce also an error : Stream.of(()->this.a()).
A simpler example could be Stream.of(()-> "foo") that will just not compile.
But if you type the method reference or the lambda it works :
Stream.of((Supplier<String>) this::a)
or
Stream.of((Supplier<String>) () -> this.a())
In the working statement you pass to Stream.of(T) a parameter that is a Supplier<String>. That refers to a functional interface but that is typed as in the previous working examples, so it is valid as parameter that expects an Object.
this::a is contextless and could mean different things. You need to provide some context to help the compiler to figure out what you actually meant by this::a.
Stream.<Supplier<String>>of(this::a);
Though, that Stream<Supplier<String>> doesn't seem to be what you wanted. If you need a Stream<String>, use Stream.generate: no extra type information needed since the method takes a Supplier<T> (no ambiguity here).
Stream.generate(this::a);
On a side note, both statements expect you to save their results into variables. Defining variables of the right type often facilitates resolving such issues.
Stream<Supplier<String>> s1 = Stream.of(this::a);
Stream<String> s2 = Stream.generate(this::a);
All credit to #J-Alex and #Holger for their precious comments.

java8 + internal working of for each loop

I am new to java8. I was trying to understand working of foreach loop in Streams.
My code is as follows:-
Stream<String> s = someist.stream();
Consumer<String> consumer = (String s1)->System.out.println(s1);
s.forEach(consumer);
Question is how does foreach loop know to call consumer.accept(T t) when i am just passing the reference of Consumer and not calling consumer.accept(T t) inside it. Although, when we provide some lambda expression for a functional interface we need to call its abstract method, we are just not calling it here.
So how does foreach loop comes to know what should it do with the consumer reference provided as a parameter?
The concrete implemention of forEach will call accept, for example:
public class MyStream implements Stream<String> {
#Override
public void forEach(Consumer<? super String> action) {
while (hasNext()) {
action.accept(next());
}
}
...
}
As the java doc states:
void forEach​(Consumer<? super T> action)
Performs an action for each
element of this stream.
i.e the behavioural parameter passed to the forEach method will be called internally for each element of the source.
This is how Functional Interface works. They have only one abstract method. There might be optional default methods. The behaviour of the abstract method is passed in form of lambda expression (passing behaviour as if data). This behaviour is, in turn, the method body for the abstract method of the Functional Interface. The default methods are called using their names.
So when you pass a Functional Interface as a method parameter to another method, in this case, Consumer<T> to the forEach() method of java.util.stream.Stream interface, its abstract method accept(T t) is called for each item of the stream.
Put it this way, logically, there's only one method to be invoked if only the Functional Interface is passed as a parameter.

how to refer to instance method

I created a class (class Special) whose method (Special.method()) will react differently depending on the method that calls Special.method(). so, lets say method X in some class calls Special.method(), if certain annotation is present in method X, the calc process invoked inside Special.method() will be different when such annotations didnt exist in the calling method. Also, since I'll be using third party library, it's not guaranteed that same thread will be used when calling Special.method() and method X.
I want to know ways to get reference to an instance method in Java 7
public class MyClass{
public void myMethod(){
....
}
}
I know I can do this
MyClass.class.getMethod(methodName);
but this technique is prone to error since it relies on String input (i.e. when method name is changed, etc). Is there a more reliable way to refer to a method?
Thanks
Java doesn't support method references without some fairly gnarly reflection. Java has functional interfaces that can work like references, but due to their targeted usage, they all take or return at least one value. There's no interface for methods which take no arguments and return void like you have in your example.
// Assignment context
Predicate<String> p = String::isEmpty;
Will declare a method reference to the String#isEmpty() method, which returns a boolean. That and similar interfaces exist in the java.lang.function package.
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
Regarding your edit: If you want to find the caller of your method, see here:
How do I find the caller of a method using stacktrace or reflection?
The currently-accepted answer is incorrect: There is a functional interface compatible with your myMethod (e.g., accepting no parameters, with a void return type), it's just not in java.util.function, it's in java.lang: Runnable:
public class MyClass{
public void myMethod(){
System.out.println("myMethod was called");
}
}
class Example
{
public static void main (String[] args)
{
MyClass c = new MyClass();
Runnable r = c::myMethod; // <===
r.run(); // <===
}
}
Live on IDEOne
They just didn't duplicate it in java.util.function.

Java generic method. Why is T deduced to be Map?

Consider the following code
class MyClass {
public MyClass(Map<String, String> m) {
System.out.println("map");
}
public MyClass(SortedMap<String, String> m) {
System.out.println("sortedmap");
}
}
public class Test {
public <T extends Map<String,String>> Test(T t) {
new MyClass(t);
}
public static void main(String[] args) {
new Test(new TreeMap<String,String>());
}
}
It prints map. Why is T deduced to be Map instead of SortedMap in public <T extends Map<String, String>> Test(T t) ? Is there a way to change this behaviour in order to use the most concrete constructor for MyClass?
The resolving which constructor of MyClass is called is done at compile time. When the compiler compiles the code of the Test constructor, it does not know what T actually is, it just knows that it is guaranteed to be a Map<String, String>, so it cannot do anything else than binding the constructor call to the constructor that takes a Map.
The knowledge that in your code T is a TreeMap is only present within the body of the method main, not outside. Consider for example what would happen if you added a second caller of the Test constructor that actually passes a HashMap.
Java generics work such that the code of a generic method is only compiled once for all possible generic parameter values (and only present once in the byte code), there is not like in other languages a copy of the generic method for each generic type.
In general, it is not possible in Java to let a single method/constructor call in the code actually call different methods/constructors at runtime depending on the type of arguments. This is only possible for method calls depending on the runtime type of the called object (dynamic binding with overwritten methods).
Overloading (what you have here) works only at compile time by looking at the static type of the arguments.
The typical solution for this situation would be to use an instanceof SortedMap check within the constructor of MyClass.
Another possible (more elegant) solution is the visitor pattern, but this works only with classes that are prepared for it (so not with Map instances if you do not wrap them within a class of your own).

Java varargs for multiple arguments

Is it considered a good programing idiom to use Java varargs as an optional parameter?
Even more: if I have an interface, and some implementations need the additional parameter, and some don't, is it okay to use varargs in the method signature for the optional parameter?
In Java it is possible to use the following idiom:
public static void x(String ... strings)
which gets an array of strings, possibly empty. You could call it with
x() (empty array), x("1","2","3") etc
Varargs is usually used when you don't know the number of arguments of a "particular type" that the users of the api will like to pass. I don't think there is any problem with that since the user can decide to pass any number of parameter or not to pass any at all. For eg
public class NewClass {
public void print(String... a) {
System.out.println(a);
}
public static void main(String[] args) {
new NewClass().print();
}
}
Doen't hurt. Since you know the type of in the varargs.
I would say no. Using a varargs will allow any number of arguments to be provided for your optional parameter. How will you communicate to people implementing your interface or calling your method that only one value is expected? What should the behavior be when multiple values are provided? These are unnecessary complications.
If your method requires exactly 0 or 1 value for the optional argument, then you should use a language construct that only allows 0 or 1 value to be provided. It would be more appropriate to overload the method signature or allow the optional parameter to be null.
I don't think it is a good idea to use varargs to implement optional parameters.
Animal a = new Dog();
a.speak("bow");
You have no idea looking at the reference in above example what arguments should be applied as you may not know that it is a dog if the animal was extracted from say a List of animals.
As said by #Oli explicit overload is a good approach instead.

Categories

Resources