Get Method reference from Method object
You just need to use Method.invoke
. Here is an example:
public class SomeObject{
public String someMethod(){
return "Test";
}
}
public String expectsMethodRef( Function<SomeObject, String> f ){
SomeObject so = new SomeObject();
return f.apply(so);
}
And here is how you invoke using plain lambda and Method object.
//plain lmbda
expectsMethodRef( SomeObject::someMethod );
//with method object
Method someMethod = SomeObject.class.getMethod("someMethod");
expectsMethodRef( (so) -> {
try {
return (String)someMethod.invoke(so);
} catch (Exception e) {
return null;
}
} );
How to get Method Reference for all methods in a class (Java)?
There is no solution that works without Reflection as the dynamic discovery of existing methods is a reflective operation. However, once methods are discovered and a method reference instance (or the dynamic equivalent of it) has been created, the actual invocation of the code runs without Reflection:
class Test {
public static double op0(double a) { ... }
public static double op1(double a) { ... }
public static double op2(double a) { ... }
public static double op3(double a) { ... }
public static double op4(double a) { ... }
static final Map<String, DoubleUnaryOperator> OPS;
static {
HashMap<String, DoubleUnaryOperator> map=new HashMap<>();
MethodType type=MethodType.methodType(double.class, double.class);
MethodType inT=MethodType.methodType(DoubleUnaryOperator.class);
MethodHandles.Lookup l=MethodHandles.lookup();
for(Method m:Test.class.getDeclaredMethods()) try {
if(!Modifier.isStatic(m.getModifiers())) continue;
MethodHandle mh=l.unreflect(m);
if(!mh.type().equals(type)) continue;
map.put(m.getName(), (DoubleUnaryOperator)LambdaMetafactory.metafactory(
l, "applyAsDouble", inT, type, mh, type).getTarget().invokeExact());
} catch(Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
OPS=Collections.unmodifiableMap(map);
}
}
Once the class has been initialized, you can invoke a particular op without Reflection using OPS.get(name).applyAsDouble(doubleValue)
or invoke all ops using, e.g.
OPS.forEach((name,op)-> System.out.println(name+'('+42+") => "+op.applyAsDouble(42)));
How can I get a reference to a method?
You want Object#method
:
---------------------------------------------------------- Object#method
obj.method(sym) => method
------------------------------------------------------------------------
Looks up the named method as a receiver in obj, returning a Method
object (or raising NameError). The Method object acts as a closure
in obj's object instance, so instance variables and the value of
self remain available.
class Demo
def initialize(n)
@iv = n
end
def hello()
"Hello, @iv = #{@iv}"
end
end
k = Demo.new(99)
m = k.method(:hello)
m.call #=> "Hello, @iv = 99"
l = Demo.new('Fred')
m = l.method("hello")
m.call #=> "Hello, @iv = Fred"
Now your code becomes:
private
def setup_map
@map = {
'a' => method(:a),
'b' => method(:b),
'c' => method(:c)
}
# or, more succinctly
# @map = Hash.new { |_map,name| _map[name] = method(name.to_sym) }
end
public
def call(arg)
@map["a"][arg] if arg > 10
@map["b"][arg] if arg > 20
@map["c"][arg] if arg > 30
end
Java 8 method reference: how to determine which method to take?
NameCreator::createName
implies that either the method is static (kind #1 in the table below), or that the functional interface target also takes an instance of the class (kind #3, for example BiFunction<NameCreator, String, String>
). Your methods are not static, and so presumably your target does not take an instance, which is why you get the "Cannot resolve method" error. You probably want to use the method reference on an instance (kind #2). From within the class, you can use:
Function<String, String> func = this::createName
From outside the class you can use:
NameCreator creator = new NameCreator();
Function<String, String> func = creator::createName;
As to whether the one- or two-parameter version is used, it depends on what functional interface is being targeted. The above will use your first method, because Function<String, String>
takes a String and returns a String. The following functional interface, as an example, would use your second method:
NameCreator creator = new NameCreator();
BiFunction<String, String, String> func = creator::createName;
See: Function
, BiFunction
, and the whole java.util.function
package
You may also be interested in the Java tutorial on method references, specifically this part:
There are four kinds of method references:
Kind | Example
==============================================================================================
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 | ContainingType::methodName
of a particular type |
-------------------------------------------------------+--------------------------------------
Reference to a constructor | ClassName::new
==============================================================================================
get reference to methods object, when method called from other class (javascript)
Updated fiddle, using apply method (same can be achieved using call, jQuery.proxy, bind) to maintain correct scope:
var callObject = {
call: function(func) {
// Needs scope object as first parameter.
func.apply(object, [3]);
}
}
This way, by using any of these methods, we are able to specify what scope our function should resolve to.
Here is a great article giving more details on this aspect.
How to get the MethodInfo of a Java 8 method reference?
No, there is no reliable, supported way to do this. You assign a method reference to an instance of a functional interface, but that instance is cooked up by LambdaMetaFactory
, and there is no way to drill into it to find the method you originally bound to.
Lambdas and method references in Java work quite differently than delegates in C#. For some interesting background, read up on invokedynamic
.
Other answers and comments here show that it may currently be possible to retrieve the bound method with some additional work, but make sure you understand the caveats.
How can I get a method reference for an instance method with a dynamically bound target
Via Reflection, you can get an equivalent behavior to that one described in Java 8. You can create an instance of a Delegate with a null
target and dynamically binding its first argument to the this
method parameter. For your example you can create the toStr
delegate in the following way:
MethodInfo methodToStr = typeof(object).GetMethod("ToString");
Func<Object, String> toStr = (Func<Object, String>) Delegate.CreateDelegate(
typeof(Func<Object, String>),
methodToStr);
Is it possible to get a reference to a Java method to invoke it later?
Yes, it is possible.
You just have the get the method and invoke it.
Here's some sample code:
$cat InvokeMethod.java
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
public class InvokeMethod {
public static void invokeMethod( Method m , Object o , Object ... args )
throws IllegalAccessException,
InvocationTargetException {
m.invoke( o, args );
}
public static void main( String [] args )
throws NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
SomeObject object = new SomeObject();
Method method = object.getClass().getDeclaredMethod( "someMethod", String.class );
invokeMethod( method, object, "World");
}
}
class SomeObject {
public void someMethod( String name ){
System.out.println( " Hello " + name );
}
}
$javac InvokeMethod.java
$java InvokeMethod
Hello World
$
Now the question is, what are you trying to do? perhaps are better ways. But as for your question the answer is YES.
Related Topics
Having Difficulty Accessing Validation Errors in Sinatra
Why Is 032 Different Than 32 in Ruby
What's Does the [5.0] in Rails 5's Activerecord::Migration Mean
How to Use Headless Chrome with Capybara and Selenium
How to Make Rake Db:Migrate Generate Schema.Rb When Using :SQL Schema Format
Ruby on Rails. Bundler. Cucumber. Rake Aborted! Command Failed with Status (1)
If 'Self' Is Always the Implied Receiver in Ruby, Why Doesn't 'Self.Puts' Work
Authorizing Namespaced and Nested Controllers Using Cancan
Generating Excel Documents with Ruby
Unescaping Characters in a String with Ruby
How to Set Up the Recipient Id in Public Activity
Ruby on Rails - Activerecord::Relation Count Method Is Wrong
Accessing the Child Instance in a Rabl Template
Rails Generate Controller Gives Me Load Error
How to Raise an Exception in an Rspec Test
Error When Installing Libv8 3.11.8.3
Rails Form Object with Reform-Rails with Collections Not Working or Validating