Lambda this reference in java - java

I want to convert an anonymous class to a lambda expression. But this anonymous class uses the this keyword.
For example, I wrote this simple Observer/Observable pattern:
import java.util.ArrayList;
import java.util.Collection;
public static class Observable {
private final Collection<Observer> notifiables = new ArrayList<>();
public Observable() { }
public void addObserver(Observer notifiable) { notifiables.add(notifiable); }
public void removeObserver(Observer notifiable) { notifiables.add(notifiable); }
public void change() {
notifiables.forEach(notifiable -> notifiable.changed(this));
}
}
public interface Observer {
void changed(Observable notifier);
}
and this sample code with an anonymous class (use the this keyword):
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(new Observer() {
#Override
public void changed(Observable notifier) {
notifier.removeObserver(this);
}
});
observable.change();
}
}
but when I convert it to a lambda expression:
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(notifier -> { notifier.removeObserver(this); });
observable.change();
}
}
I get this compilation error:
Cannot use this in a static context and in a non `static` context
public class Main {
public void main(String[] args) {
method();
}
private void method() {
Observable observable = new Observable();
observable.addObserver(notifier -> {
notifier.removeObserver(this);
});
observable.change();
}
}
The compilation error is:
The method removeObserver(Main.Observer) in the type Main.Observable is not applicable for the arguments (Main)
Is there a way to reference the lambda object with this?

You can't reference to this in a lambda expression. The semantic of this has been changed to reference the instance of the surrounding class only, from within the lambda. There is no way to reference to the lambda expression's this from inside the lambda.
The problem is that you use this in the main() method. The main method is static and there is no reference to an object that represents this.
When you use this inside an instance of an inner class you are referencing to the instance of the inner class.
A lambda expression is not an inner class, this is not referencing to the instance of the lambda expression. It is referencing to the instance of the class you define the lambda expression in. In your case it would be a instance of Main. But since your are in a static method, there is no instance.
This is what your second compilation error is telling you. You hand over an instance of Main to your method. But your method signature requires an instance of Observer.
Update:
The Java Language Specification 15.27.2 says:
Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).
The transparency of this (both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.
Practically speaking, it is unusual for a lambda expression to need to talk about itself (either to call itself recursively or to invoke its other methods), while it is more common to want to use names to refer to things in the enclosing class that would otherwise be shadowed (this, toString()). If it is necessary for a lambda expression to refer to itself (as if via this), a method reference or an anonymous inner class should be used instead.

Workaround 1
Your change() method throws ConcurrentModificationException anyway.
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
final Observer[] a = new Observer[1];
final Observer o = er -> er.removeObserver(a[0]); // !!
a[0] = o;
observable.addObserver(o);
observable.change();
}
}
public class Observable {
private final java.util.Collection<Observer> n
= java.util.new ArrayList<>();
public void addObserver(Observer notifiable) {
n.add(notifiable);
}
public void removeObserver(Observer notifiable) {
n.add(notifiable);
}
public void change() {
for (final Observer o : n.toArray(new Observer[n.size()])) {
o.changed(this);
}
}
}
public interface Observer {
void changed(Observable notifier);
}
Workaround 2
I changed the changed(Observable) to changed(Observable, Observer) so that an observer can handle itself.
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
final Observer o = (er, ee) -> er.removeObserver(ee); // !!
observable.addObserver(o);
observable.change();
}
}
public class Observable {
private final java.util.Collection<Observer> n
= new java.util.ArrayList<>();
public void addObserver(Observer notifiable) {
n.add(notifiable);
}
public void removeObserver(Observer notifiable) {
n.add(notifiable);
}
public void change() {
for (final Observer o : n.toArray(new Observer[n.size()])) {
o.changed(this, o);
}
}
}
public interface Observer {
void changed(Observable notifier, Observer notifiee);
}

Related

Conditionally invoke method with same name from two different classes

I want an implementation where I need to invoke a method from one of two classes based on a condition. To illustrate, lets say I have two simplistic classes:
public class A implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTA");
}
}
public class B implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTB");
}
}
and an interface
public interface IObject {
void doIt();
}
My method to dynamically call a class function is implemented as:
void call(String s, A a, B b, Consumer<IObject> o) {
if(s.equalsIgnoreCase("CONDITION")) {
o.accept(a);
} else {
o.accept(b);
}
}
I can call the method as
A objectA = new A();
B objectB = new B();
call("CONDITION", objectA, objectB, IObject::doIt);
call("OTHER", objectA, objectB, IObject::doIt);
This will essentially invoke doIt on class A or B depending upon the condition parameter
Is there a cleaner way to achieve this by perhaps reducing the number of parameters an hence the function call signature?
Thanks
For my understanding of your problem:
You have a condition
You have a context to use (object a and b)
You would not ask such a question if there was not an intent to generalize your code for more than one condition or object (a, b). Otherwise, a ternary operator or a if would be far more easier to maintain (eg: ((condition) a:b).doIt() vs the code below).
Why not using a pattern like this:
A a = new A();
B b = new B();
String hint = ...;
List<Executor> list = new ArrayList<>();
list.add(new Executor("CONDITION"::equalsIgnoreCase, a::doIt));
list.add(new Executor(s -> true, b::doIt));
for (Executor executor : list) {
if (executor.process(hint)) {
break;
}
}
With Executor class:
class Executor {
private final Predicate<String> predicate;
private final Runnable runnable;
...
public boolean process(String s) {
if (!predicate.test(s)) {
return false;
}
runnable.run();
return true;
}
}
The loop will evaluate the condition, then run the code if true, otherwise continue onto the next element.
The Executor class is technically not bound to a or b; only the initial setup is.
Here is a complete different approach, utilizing java.lang.reflect.Proxy:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* #author ben
*/
public class Test {
public interface IObject {
void doIt();
}
public static class A implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTA");
}
}
public static class B implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTB");
}
}
public static void main(String[] args) {
final boolean condition = true;
IObject proxyObj = (IObject)Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{IObject.class}, new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (condition)
new A().doIt();
else
new B().doIt();
return null;
}
});
proxyObj.doIt();
}
}
Here, you are creating a Proxy-Object for your Interface.
When you call .doIt() on this object, the invocation-handler will call the appropriate implementation, based on a condition.
You could then pass the proxy around and work with the invocation handler.
(It should be clear that this code should only give an idea and is only an example of how proxied interfaces/objects could be used to solve this problem.)
The above requirement can be implemented easily by using the 'Factory design pattern'
The factory design pattern involves these 3 steps:
Define the common interface for both the object types
Define the different classes that implement the common interface
Create a Factory class with a static method that returns one of the object types based on the input condition
Here is a working demo:
// File name: Demo.java
interface IObject {
public void doIT();
}
class A implements IObject {
public void doIT() {
System.out.println("DoIT - Class A");
}
}
class B implements IObject {
public void doIT() {
System.out.println("DoIT - Class B");
}
}
class IObjectFactory {
static IObject getObject(String CONDITION) {
if(CONDITION.equalsIgnoreCase("CONDITION")) {
return (new A());
}
return (new B());
}
}
public class Demo {
public static void main(String[] args) {
IObject io1 = IObjectFactory.getObject("condition");
IObject io2 = IObjectFactory.getObject("no condition");
io1.doIT();
io2.doIT();
}
}
Output:
> javac Demo.java
> java Demo
DoIT - Class A
DoIT - Class B
It really depends on your use cases. If the use cases are as simple as what you've described, you could remove the Consumer and just call doIt directly in the call function. However, I would recommend generalizing the function even further:
static <T> void ifElse(boolean decider, T optionA, T optionB, Consumer<T> callback) {
if (decider) {
callback.accept(optionA);
} else {
callback.accept(optionB);
}
}
Then call it with:
A a = new A();
B b = new B();
ifElse(condition.equals("CONDITION"), a, b, IObject::doIt);
Doing it this way is cleaner and more expandable. It also takes the same amount of code. (Untested, may have errors, but you get the idea). This approach is what you might see in purely ("purely") functional programming languages, where an if statement is just a function that takes a conditional and two functions (one for true, one for false).

C# vs JAVA instance of Interface

I am not sure how am I suppose to go about my question. It is about Android can Instantiate Interface. I am trying to do in C#. Now I am pretty sure that the rules for both Java and C# is you can't create an Instance of abstract and Interface as being said.
But I would really like to know how Android does this practice.
In Android you can do this.
public interface Checkme{
void Test();
void Test2();
}
public void myFunc(Checkme my){
//do something
}
// Now this is the actual usage.
public void Start(){
myFunc(new Checkme(){
#Override
public void Test()
{
}
#Override
public void Test2()
{
}
});
}
Actually once you press Enter on new Checkme() You will automatically get the Override methods of the Interface. Like auto Implement method of an Interface in C#.
I hope my question make sense.
C# doesn't support anonymously auto-implemented interfaces because it has delegates:
public void Foo(Func<string> func, Action action) {}
// call it somewhere:
instance.Foo(() => "hello world", () => Console.WriteLine("hello world"));
With delegates you can fill the gap and it can be even more powerful than implementing interfaces with anonymous classes.
Learn more about delegates.
This is an Anonymous Class:
public void Start(){
myFunc(new Checkme() {
#Override
public void Test() {
}
#Override
public void Test2() {
}
});
}
An anonymous class is an unnamed class implemented inline.
You could also have done it using a Local Class, but those are rarely seen in the wild.
public void Start(){
class LocalCheckme implements Checkme {
#Override
public void Test() {
}
#Override
public void Test2() {
}
}
myFunc(new LocalCheckme());
}
These both have the advantage that they can use method parameters and variables directly, as long as they are (effectively) final.
As a third option, you could do it with an Inner Class.
private class InnerCheckme implements Checkme {
#Override
public void Test() {
}
#Override
public void Test2() {
}
}
public void Start(){
myFunc(new InnerCheckme());
}
An inner class cannot access method variables (obviously because it's outside the method), but can be used by multiple methods.
Any local values from the method can however be passed into the constructor and stored as fields of the inner class, to get the same behavior. Just requires a bit more code.
If the inner class doesn't need access to fields of the outer class, it can be declared static, making it a Static Nested Class.
So, all 3 ways above a very similar. The first two are just Java shorthands for the third, i.e. syntactic sugar implemented by the compiler.
C# can do the third one, so just do it that way for C#.
Of course, if the interface only has one method, using a Java lambda or C# delegate is much easier than Anonymous / Local / Inner classes.
If I understand correcly, you're defining a class that implements an interface, and when you specify that the class implements an interface, you want it to automatically add the interface's methods and properties.
If you've declared this:
public interface ISomeInterface
{
void DoSomething();
}
And then you add a class:
public class MyClass : ISomeInterface // <-- right-click
{
}
Right-click on the interface and Visual Studio will give you an option to implement the interface, and it will add all the interface's members to the class.
you mean something like this?
pulic interface Foo{
void DoSomething();
}
public class Bar : Foo {
public void DoSomething () {
//logic here
}
}
myFunc(new Checkme(){
#Override
public void Test()
{
}
#Override
public void Test2()
{
}
});
You're passing into myFunc() something that is called an anonymous class. When it says "new Checkme() { .... }", it is defining an anonymous implementation of the Checkme interface. So, it's not an instance of the interface itself, just an instance of a type that implements it.
In C# anonymously implemented classes for Interface are not auto generated just like in java, you need to follow the below procedure to workout.
public class MyClass {
public void someMethod (string id, IMyInterface _iMyInterface) {
string someResponse = "RESPONSE FOR " + id;
_iMyInterface.InterfaceResponse (someResponse);
}
}
public interface IMyInterface {
void InterfaceResponse (object data);
void InterfaceResponse2 (object data, string x);
}
public class MyInterfaceImplementor : IMyInterface {
private readonly Action<object> actionname;
private readonly Action<object, string> actionInterfaceResponse2;
public MyInterfaceImplementor (Action<object> InterfaceResponse) {
this.actionname = InterfaceResponse;
}
public MyInterfaceImplementor(Action<object> interfaceResponseMethod, Action<object, string> interfaceResponseMethod1) {
this.actionname = interfaceResponseMethod ?? throw new ArgumentNullException(nameof(interfaceResponseMethod));
this.actionInterfaceResponse2 = interfaceResponseMethod1 ?? throw new ArgumentNullException(nameof(interfaceResponseMethod1));
}
public void InterfaceResponse (object data) {
this.actionname (data);
}
public void InterfaceResponse2(object data, string x) {
this.actionInterfaceResponse2(data, x);
}
}
Gist Source : https://gist.github.com/pishangujeniya/4398db8b9374b081b0670ce746f34cbc
Reference :

Invoking method of anonymous class

Java 7
First of all, I'm going to simplify the example to avoid posting unnecesary code. My specific concrete example a little bit complicated, but I' try to preserve the point.
public class Test {
public static void main(String[] args){
Test t = new Test(){ //<---------------------------------------------------------
public void m(){ // |
Test t = new Test(){// |
public void m(){// |
//Here I need to invoke the most inclosing class's m() method
}
//other actions
};
}
public void someMethod(){
//action
}
};
}
public void m(){
}
}
Is it possible to do in Java? I mean, to invoke the method of anonymous class that way?
No it's impossible because there is no reference to the anonymous classes.
This is the only possible way to call the instance m() method :
new Test(){
public void m(){
}
}.m();
By definition according to the oracle documentation here :
Anonymous classes enable you to make your code more concise. They
enable you to declare and instantiate a class at the same time. They
are like local classes except that they do not have a name. Use them
if you need to use a local class only once
So if you have to use one of the methods of your class you have to create a local one.
You cannot access the methods of the anonymous class using normal java, but you are able using reflection:
Test t = new Test{
public void m() {
System.out.println("Welcome to my class");
}
};
Class<?> c = t.getClass();
Method m = c.getDeclaredMethod("m");
// m.setaccessible(true); // if private
m.invoke(t);
Here is a way to do it:
public class Test
{
public static void main(String[] args)
{
Test t = new Test()
{
public void m() // this one will be called
{
Runnable r = new Runnable()
{
#Override
public void run()
{
m();
}
};
Test t = new Test()
{
public void m()
{
r.run();
}
};
}
};
}
public void m()
{
}
}
If the method returns a value, use Callable<V> instead.

how to invoke method of annoymous class from the main method of the outer class

I'm new to Java and is trying to learn the concept of anonymous class. Could someone please tell me how I can invoke the 'awesomeMethod' from the main method of the LocallClassExample?
public class LocalClassExample {
interface Awesome {
public void awesomeMethod();
}
class AwesomeClass {
public int finalInt= 10;
Awesome a1 = new Awesome() {
#Override
public void awesomeMethod() {
System.out.println(finalInt);
}
};
}
public static void main(String[] args) {
}
}
Consider this:
new AwesomeClass().a1.awesomeMethod();
will invoke the method awesomeMethod() on the member variable a1 (which is something Awesome) of the newly created instance of AwesomeClass.
It will get more tricky once your main is outside of your AwesomeClass - and more so once it's outside of the package. In these cases you'd have to provide a getter like
public Awesome getAwesome() {
return a1;
}
Which would when invoked still execute the method as defined in your anonymous class.
Try to use this to create inner class object as:
public static void main(String[] args) {
LocalClassExample.AwesomeClass oi = new LocalClassExample().new AwesomeClass();
oi.awesomeMethod();
}

Can I access new methods in anonymous inner class with some syntax?

Is there any Java syntax to access new methods defined within anonymous inner classes from outer class? I know there can be various workarounds, but I wonder if a special syntax exist?
For example
class Outer {
ActionListener listener = new ActionListener() {
#Override
void actionPerformed(ActionEvent e) {
// do something
}
// method is public so can be accessible
public void MyGloriousMethod() {
// viva!
}
};
public void Caller() {
listener.MyGloriousMethod(); // does not work!
}
}
MY OWN SOLUTION
I just moved all methods and members up to outer class.
Once the anonymous class instance has been implicitly cast into the named type it can't be cast back because there is no name for the anonymous type. You can access the additional members of the anonymous inner class through this within the class, in the expression immediate after the expression and the type can be inferred and returned through a method call.
Object obj = new Object() {
void fn() {
System.err.println("fn");
}
#Override public String toString() {
fn();
return "";
}
};
obj.toString();
new Object() {
void fn() {
System.err.println("fn");
}
}.fn();
identity(new Object() {
void fn() {
System.err.println("fn");
}
}).fn();
...
private static <T> T identity(T value) {
return value;
}
A student in my class asked our professor if this could be done the other day. Here is what I wrote as a cool proof of concept that it CAN be done, although not worth it, it is actually possible and here is how:
public static void main(String[] args){
//anonymous inner class with method defined inside which
//does not override anything
Object o = new Object()
{
public int test = 5;
public void sayHello()
{
System.out.println("Hello World");
}
};
//o.sayHello();//Does not work
try
{
Method m = o.getClass().getMethod("sayHello");
Field f = o.getClass().getField("test");
System.out.println(f.getInt(o));
m.invoke(o);
} catch (Exception e)
{
e.printStackTrace();
}
}
By making use of Java's Method class we can invoke a method by passing in the string value and parameters of the method. Same thing can be done with fields.
Just thought it would be cool to share this!
Your caller knows listener as an ActionListener and therefore it doesn't know anything about that new method. I think the only way to do this (other than doing reflection gymnastics, which really would defeat the purpose of using an anonymous class, i.e. shortcut/simplicity) is to simply subclass ActionListener and not use an anonymous class.
Funny enough, this is now allowed with var construct (Java 10 or newer). Example:
var calculator = new Object() {
BigDecimal intermediateSum = BigDecimal.ZERO;
void calculate(Item item) {
intermediateSum = Numbers.add(intermediateSum, item.value);
item.sum= intermediateSum;
}
};
items.forEach(calculator::calculate);
Here with method reference, but works with dot method call as well, of course. It works with fields as well. Enjoy new Java. :-)
I found more tricks with var and anonymous classes here: https://blog.codefx.org/java/tricks-var-anonymous-classes/
No, it's imposible. You would need to cast the ActionListener to its real subclass name, but since it's anonymous, it doesn't have a name.
The right way to do it is using reflection:
import java.lang.reflect.InvocationTargetException;
public class MethodByReflectionTest {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Object obj = new Object(){
public void print(){
System.out.println("Print executed.");
}
};
obj.getClass().getMethod("print", null).invoke(obj, null);
}
}
You can check here: How do I invoke a Java method when given the method name as a string?
Yes you can access the method see the example below if any doubt please comment
package com;
interface A
{
public void display();
}
public class Outer {
public static void main(String []args)
{
A a=new A() {
#Override
public void display() {
System.out.println("Hello");
}
};
a.display();
}
}

Categories

Resources