Java 8 - how to access object and method encapsulated as lambda - java

In Java you can "capture" a "method call on object" as a Runnable, as in belows example.
Later, having access to this instance of Runnable, is it possible to actually access the "captured" object and the method parameters of a method which is called (if possible this probably needs to be done via reflection).
For example:
class SomePrintingClass {
public void print(String myText) {
System.out.println(myText);
}
}
public class HowToAccess {
public static void main(String[] args) throws Exception {
final String myText = "How to access this?";
final SomePrintingClass printer = new SomePrintingClass();
Runnable r = () -> printer.print(myText); // capture as Runnable
inspect(r);
}
private static void inspect(Runnable runnable) {
// I have reference only to runnable... can I access "printer" here
}
}
Is it possible in the "inspect" method to access (probably via reflection) "printer" object and "myText" which was passed as a parameter?

It is possible, because the captured references are translated into fields of the runnable (as with all anonymous classes). The names will be not be consistent however.
I found by testing that you need to make myText non-final, otherwise it will be seen as a compile time constant and in-lined (and will not be accessible as a field):
private static void inspect(Runnable runnable) throws Exception {
for(Field f : runnable.getClass().getDeclaredFields()) {
f.setAccessible(true);
System.out.println("name: " + f.getName());
Object o = f.get(runnable);
System.out.println("value: " + o);
System.out.println("class: " + o.getClass());
System.out.println();
}
}
Prints:
name: arg$1
value: test.SomePrintingClass#1fb3ebeb
class: class test.SomePrintingClass
name: arg$2
value: How to access this?
class: class java.lang.String

With reflection, it is not possible to get local variables and method parameter values. Instead you can use AOP to intercept the method call and inspect the parameters.

Check if you want something as the below code where I have passed the runnable to a Thread object in your inspect method.
class SomePrintingClass {
public void print(String myText) {
System.out.println(myText);
}
}
public class HowToAccess {
public static void main(String[] args) throws Exception {
final String myText = "How to access this?";
final SomePrintingClass printer = new SomePrintingClass();
Runnable r = () -> printer.print(myText); // capture as Runnable
inspect(r);
}
private static void inspect(Runnable runnable) {
Thread t = new Thread(runnable);
t.start();
}
}
output will be:
How to access this?

Related

Store references to instance methods in a static context

I would like to have a static map where the values are instance methods. Someting like:
public class MyClass {
static Map<MyEnum, Consumer<String>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, MyClass::firstMethod);
methodMapping.put(MyEnum.SECOND, MyClass::secondMethod);
}
void firstMethod(String param) {
...
}
void secondMethod(String param) {
...
}
}
This gives me an error saying "Non-static method cannot be referenced from a static context". I understand why this would be a problem if I would try to call the methods from the static context, but isn't it possible from an instance method to retrieve the method from the map and pass it this? Like:
MyClass.methodMapping.get(MyEnum.FIRST).accept(this, "string");
This is solvable as easy as changing Consumer to BiConsumer, turning the receiver instance of MyClass to a parameter of the function:
public class MyClass {
static Map<MyEnum, BiConsumer<MyClass,String>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, MyClass::firstMethod);
methodMapping.put(MyEnum.SECOND, MyClass::secondMethod);
}
void firstMethod(String param) {
...
}
void secondMethod(String param) {
...
}
void callTheMethod(MyEnum e, String s) {
methodMapping.get(e).accept(this, s);
}
}
You initialize methodMapping in a static initialization block. At that point, your instance methods can't be referred to yet because you haven't called new MyClass() yet.
You could fix this by either making your methods static, or moving the methodMapping initialization from the static block to a constructor.
PS: The keyword static can be omitted from the initialization block
isn't it possible from an instance method to retrieve the method from the map and pass it this
No. A Consumer only has a single parameter accept() method, so there's no such thing as "passing this at calling time".
You need an instance when creating the method reference, so this questions boils down to "can't call instance method from a static context".
It seems that you don't understand that
static Map<MyEnum, Consumer<String>> methodMapping;
static {
does exactly that, trying to call the methods from the static context where they don't exist.
The key thing to understand here: you intend to create a method reference; and a method reference needs some object to invoke that method on. Thus there is no "delaying"; there is no way in java to express "wait for this to be meaningful"; or in other words: there is no way in a static context to express: "you will be used in a non-static context later on; and then pick the corresponding this from there".
The key is to defer the specification of this or to be more specific: The particular instance on which a method is to be called. So instead of storing method references directly we store functions that accept an instance and return a method reference for that instance.
MyClass.java
public class MyClass {
static Map<MyEnum, Function<MyClass, Consumer<String>>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, t -> t::firstMethod);
methodMapping.put(MyEnum.SECOND, t -> t::secondMethod);
}
private String id;
public MyClass(String id) {
this.id = id;
}
void firstMethod(String param) {
System.out.println(id + ", 1st method, " + param);
}
void secondMethod(String param) {
System.out.println(id + ", 2nd method, " + param);
}
void dispatchMethod(MyEnum myEnum, String param) {
methodMapping.get(myEnum).apply(this).accept(param);
}
}
Main.java
public class Main {
public static void main(String[] args) {
MyClass instance = new MyClass("MyInstance");
MyClass.methodMapping.get(MyEnum.FIRST).apply(instance).accept("Using mapping directly");
instance.dispatchMethod(MyEnum.SECOND, "Using dispatch method");
}
}
Ideally methodMapping should be shielded against direct access from other classes so I'd suggest taking the dispatchMethod approach and making methodMapping private and immutable.

Automatically call a method from unknown class

First of all, I am new in Java and I don't know yet a lot about it I just came up with this new idea.
Let's say I have a method methodCondition(String,String,String) where I want to be put in any class.
The scenario of code is below:
Where everything is started
public class MainClass{
public static void main(String... args)
{
//Whe everything started, call StartFunction from proccesshelper class to Start a Thread.
ProccessHelper phelper = new ProccessHelper();
phelper.StartFunction();
}
public void methodCondition(String data1, String data2, String data3){
//Do something about the data when this method is fire from Thread
}
}
A class where functions can call
public class ProccessHelper{
//Some function here
public void StartFunction(){
MyThread mythread = new MyThread();
Thread t = new Thread(mythread);
t.start();
}
//Some function here
}
A thread where methodCondition(String,String,String) is able to fire
public class MyThread implements Runnable {
volatile boolean StopThread = false;
public MyThread(){}
public void Stop(boolean stopThread){
this.StopThread = stopThread;
}
public void run(){
if(dontLoop){
while(true){
if(condition = true){
/*
* if the condition here is true then call "eventMethod" from any unkown class.
*/
methodCondition(String data1, String data2, String data3);
}
}
}
}
}
So my question is, it is possible that the MyThread can call methodCondition(String,String,String) in any class where it is register just like listening and waiting to be call?
Just like what I said, I don't know yet a lot in Java, I don't know what kind of function is this or if this is possible I just came up with this Idea.
So if anyone can tell,explain or give a link for any reference about what I am trying to achieve that will be very appreciated. I am also open for any clarification. Thank you!
If you want to call methodCondition from any class you must declare like static method. The statics methods can be called without instantiate the container class.
public static void methodCondition(String data1, String data2, String data3){
//Do something about the data when this method is fire from Thread
}
After declare like static you can call it directly:
MainClass.methodCondition(...);
All classes must be in the same package, or import MainClass where you want to use methodCondition.
If you don't know the class name, better put it in an interface and accept that interface as an input to your thread and call it from interface reference. This method could be inner to thread or can be a normal interface. Below is the example with inner interface.
Thread Code:
class MyThread implements Runnable {
interface interfaceName {
void methodName(String data1, String data2, String data3);
}
interfaceName interfaceReference = null;
// Other members declaration
private MyThread(interfaceName obj) {
interfaceReference = obj;
}
public static MyThread getInstance(interfaceName obj) {
if (obj == null) {
throw new NullPointerException();
}
return new MyThread(obj);
}
public void run() {
// Do your stuff
interfaceReference.methodName("", "", "");
// Do your stuff
}
}
Other Classes Example:
public class Temp implements MyThread.interfaceName {
public static void main(String[] args) {
Temp t = new Temp();
MyThread mt = MyThread.getInstance(t);
}
public void methodName(String data1, String data2, String data3) {
// Do your stuff
}
}
I am happy to found it and it is called Invoking Methods. And to be clear, what I really want is to find for specific name of method from unknown class and if it is exist then call it to fire specific task.
in Addition, the code I've done is below and it's work:
Class c=Class.forName("MainActivity");
Method m=c.getMethod("methodCondition", String.class, String.class, String.class); //The method has 3 String paramaters so I have to intialize it otherwise it will produce an error that the method was not found.
Object t = c.newInstance();
m.invoke(t,"Hello Word!", "this is", "to Invoke Method"); //Now invoke the method with the value or paramaters.

Can you invoke nonstatic method within a static method?

Book answer: you cannot invoke a nonstatic method within a static method(unless you create an object to serve as the calling object of the non static method). I don't get the part in bracket, I tried creating object in static method and eclipse said "unreachable code". Can someone explain why and give an example too. Thanks
(language is java)
public class RoundStuff {
public static final double PI = 3.141459;
public static double area(double radius){//Area of circle
return(PI*radius*radius);
}
public static double volume(double radius){//Volume of sphere
return((4.0/3.0)*PI*radius*radius*radius);
}
public void print(){
System.out.print("I am not parasyte");
}
}
import java.util.Scanner;
public class RoundStuffDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner keyboard = new Scanner(System.in);
System.out.println("Enter radius");
double radius = keyboard.nextDouble();
RoundStuff round = new RoundStuff();
System.out.println("A circle of radius " + radius + " inches");
System.out.println("has an area of " + round.area(5.5) + " square inches.");
System.out.println("A sphere of radius " + radius + " inches");
System.out.println("has a volume of " + RoundStuff.volume(radius) + " cubic inches.");
}
}
Java lets non-static methods call other non-static methods without specifying an object reference explicitly. It is understood that the invocation is performed on the same instance on which the current non-static method has been invoked, i.e. the instance that you can access by referencing this.
Static methods, on the other hand, must provide the object. Here is an example:
class Example {
public void one() {
System.out.println("one");
}
public void two() {
one(); // <<== #1
System.out.println("two");
}
public static void three() {
Example e = new Example();
e.one(); // <<== #2
}
}
On the line marked #1 above you call one() without specifying on what object you are calling it. Line marked #2, however, must specify the object on which the method is called.
This is an example of creating an object to serve as the calling object of the non static method.
public static void call() {
new Object().doSomething();
}
public class Object {
public void doSomething() {
// Your code to do something
}
}
Say you've got a class with two methods, one static and one non-static, like this:
class Simple {
public static void doStuff () {
doMoreStuff();
}
public void doMoreStuff() {
System.out.println("doing more stuff");
}
}
This won't compile since doStuff can't call the non-static method. However, the documentation you are referring to indicates that you can call a non-static method by creating an object to serve as the calling object. This means creating an instance of Simple, and then calling doMoreStuff on that instance:
class Simple {
public static void doStuff () {
Simple simple = new Simple();
simple.doMoreStuff();
}
public void doMoreStuff() {
System.out.println("doing more stuff");
}
}
This is a rather contrived example, but I often find it handy when working with the main method (which must be declared static) so that you aren't then declaring the rest of your methods static.

Why can't I instantiate and create Object without main method? (Stack Overflow Error)

My Code:
(causes a Stack Overflow Error)
public class Overloads {
String uniqueID;
Overloads ov2=new Overloads();
public static void main(String[] args) {
System.out.println("IN MAIN");
}
public void setUniqueID(String theID) {
// II lots of validation code, and then:
uniqueID = theID;
System.out.println(uniqueID);
}
}
This Code Works Fine:
public class Overloads {
String uniqueID;
public static void main(String[] args) {
Overloads ov2=new Overloads();
System.out.println("IN MAIN");
}
public void setUniqueID(String theID) {
// II lots of validation code, and then:
uniqueID = theID;
System.out.println(uniqueID);
}
}
The presence of main method is not relevant here. The scope in which you have declared the variables, however, is very important.
Have you walked through what happens in the first version of the code?
Create new instance of Overloads
-> ov2 = Create new instance of Overloads
-> ov2 = Create new instance of Overloads
-> ov2 = Create new instance of Overloads
and so on. The variable ov2 is in scope of the class, thus it is initialized whenever an instance of the class is instantiated. This will never terminate until you run out of memory and get the stack overflow. Run it with a debugger for a clearer view.
The second version of the code only instantiates one instace of Overloads, in the scope of the main method. Thus creating one instance does not lead to the newly created instance creating new instance and so on..
You can do like this
public class Overloads {
String uniqueID;
static Overloads ov2 = new Overloads();
public static void main(String[] args) {
System.out.println("IN MAIN");
}
public void setUniqueID(String theID) {
// II lots of validation code, and then:
uniqueID = theID;
System.out.println(uniqueID);
}
}
this will create shared instance of Overloads, instantiation will be done only once, when class loaded

Referring to non-final fields of an enclosing class inside an anonymous inner class in Java

In Java, I know that it is possible to do something like this:
public class Greeter {
public void greetEventually() {
final String greeting = "Hello!";
Job j = new Job() {
public void run() {
System.out.println(greeting);
}
};
j.schedule();
}
}
This would execute the anonymous Job at some point in the future. This works because anonymous classes are allowed to refer to final variables in the enclosing scope.
What I'm not sure about is the following case:
public class Greeter {
private String greeting;
// ... Other methods that might mutate greeting ...
public void greetEventually() {
Job j = new Job() {
public void run() {
System.out.println(greeting);
}
};
j.schedule();
}
}
In this case my anonymous Job is referring to a non-final field of the enclosing class. When the Job runs, will I see the value of the greeting field as it was when the Job was created, or as it is when it is executing? I think I know the answer, but I thought it was an interesting question, and at first it left me and a couple of coworkers second-guessing ourselves for a few minutes.
You'll see the value of greeting as it is when the anonymous Job executes.
The final modifier is required only for local variables, not member variables.
You are accessing the field through (the outer) this). You can think of this as effectively a final local variable. Only the local is final, the object pointed to is not (necessarily) constant. Imagine a local variable with the same value as this and it should be clear.
public class Greeter {
private String greeting;
// ... Other methods that might mutate greeting ...
public void greetEventually() {
private final Greeter greeter = this; // <---
Job j = new Job() {
public void run() {
System.out.println( greeter.greeting ); // <---
}
};
j.schedule();
}
}
The final modifier is applied to the local variables only to provide variables for each instance of the inner class, so we use:
final String greeting;
When you need only one instance of the variable (like the case of constants or common resources), use:
private String greeting;

Categories

Resources