Java Delegates

Java Delegates?

Not really, no.

You may be able to achieve the same effect by using reflection to get Method objects you can then invoke, and the other way is to create an interface with a single 'invoke' or 'execute' method, and then instantiate them to call the method your interested in (i.e. using an anonymous inner class).

You might also find this article interesting / useful : A Java Programmer Looks at C# Delegates (@blueskyprojects.com)

Java equivalent of C# Delegates (queues methods of various classes to be executed)

Extracted from https://msdn.microsoft.com/en-gb/library/aa288459(v=vs.71).aspx :

A delegate in C# is similar to a function pointer in C or C++. Using a
delegate allows the programmer to encapsulate a reference to a method
inside a delegate object. The delegate object can then be passed to
code which can call the referenced method, without having to know at
compile time which method will be invoked. Unlike function pointers in
C or C++, delegates are object-oriented, type-safe, and secure.

That said, Java does not have delegates like C#. However, since Java 8, we do have some sort of function pointers by using method references and functional interfaces.

As you politely requested, I am not going to tell you exactly how to implement this code, but you should be able to come up with a solution with this information.

Conditional Delegates in Java

If we are in control of the Foo consumer code, is the pattern below suitable?

public class FooDelegateSelector {
public static boolean selectDelegate1; //true for 1, false for 2

private Foo delegate1;
private Foo delegate2;
//delegates setup...

public Foo getSelectedDelegate() {
return selectDelegate1 ? delegate1 : delegate2;
}
}

Foo consuming code:

final FooDelegateSelector fooSelector = new FooDelegateSelector(...);

final Foo selectedFoo = fooSelector.getSelectedDelegate();
selectedFoo.bar();

Note: I think this idea is close to the one suggested by qwwqwwq in his comments above.

Java Delegate Interface

OK, as Sweeper pointed out, that is just the Runnable interface. I just don't like the naming, since I immediately associate it with multithreading.

For comparison:

@FunctionalInterface
public interface Runnable {
public abstract void run();
}

Are there delegates in Java 8?

There are no delegates in JDK 8. Under the hood lambdas are instances of functional interfaces (an interface with exactly one abstract method). Depending on where you are passing your lambda the compiler can figure out what interface it is implementing. For example the Collections.sort method accepts a Comparator instance as a second parameter. The Comparator happens to be a functional interface so the compiler will check if the lambda you are passing matches the abstract method in Comparator or not.

A Method reference is just a simplification. When your lambda is just calling an existing method you can use this new syntax to simplify the construct.
The example from the linked tutorial shows it pretty well:

instead of:

Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);

it's simpler with method reference:

Arrays.sort(rosterAsArray, Person::compareByAge);

Have a look on the lambdafaq.

Java Abstraction: abstract class delegates abstractions vs. concrete class uses common abstractions

The two ways are not always interchangeable.

Your first example sets a constraint for subclass that requires to implement a specific method that is a part of the makeSound() method.

Using that way couples strongly the implementation of the subclass to which one of the parent class.

Besides, the subclass may still subclass makeSound() as it is not final.

So I would use that way only for very specific scenarios :

  • to define a factory method that subclass have to define because parent class relies on that (abstract factory)
  • to define a general algorithm and let subclass to define some specific parts of that algorithm (template method).

In the general case you want to use the code of the second example but by doing BaseAnimal a Animal too :

public abstract class BaseAnimal implements Animal {
public void doCommonStuff() {
//any common logic that can be shared between concrete implementation goes here
}
}

public class Dog extends BaseAnimal implements Animal {
@Override
public void makeSound() {
doCommonStuff();
//do something specific to a dog
}
}

Note that in Java 8, default interfaces rely you from defining the abstract class that only defines common methods :

public interface Animal {
void makeSound();
default void doCommonStuff() {
//any common logic that can be shared between concrete implementation goes here
}

Note also that exposing doCommonStuff() in the API of the abstract class is not necessarily fine. Is client should be able to call it ?
If that is an implementation detail, you could extract it into a support class (AnimalDelegate) and favor composition over inheritance by composing an AnimalDelegate into the Animal subclasses.

What does providing a delegate mean in the context of a lambda expression?

Delegation is when one object has a method which simply calls an equivalent method on another object; so for example, in the class below, the method foo is delegated to the object obj:

class Example {
private final Bar obj;
public Example(Bar obj) {
this.obj = obj;
}
public Baz foo(Qux x) {
return obj.foo(x);
}
}

A lambda expression like x -> obj.foo(x) is syntactically similar to return obj.foo(x);, and the evaluation of the lambda expression creates an object with a method which delegates the foo method to the object obj, which is semantically similar to new Example(obj). So this is an example of delegation.

Of course, obj::foo also (semantically) creates an object with a method which delegates the foo method to the object obj. So the text you quoted seems debatable; the quote does at least say the behaviour is the same, so perhaps what the author means is that the lambda syntactically resembles delegation whereas the method reference does not (because it's in point-free style). At least, this seems to be what the quote means.


To pre-empt the debate about whether lambdas and method references really create objects: if you use a debugger then you might discover some implementation details which suggest otherwise, but the Java Language Specification says, authoritatively, that (§15.27.4)

At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. [...] Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.

and (§15.13.3)

At run time, evaluation of a method reference expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. [...] either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.

What are the benefits of using expression Delegates over Java classes?

Only thing I can imagine using expression delegates over Java classes is that, whenever my custom code class required to load from spring beans using dependency injection, specially where you want to control the lifecycle of delegation instance by your application, not Camunda runtime engine.

In simple words, by using expression delegates, we can initialize the delegate class as we want using spring DI without letting Camunda engine to initialize it. And take all advantages of DI.

The scenario is that we want to load our delegation class from spring beans, where it requires runtime dependencies to be injected before our delegation code runs. So, we can use spring beans to initialize other object dependencies and create a bean referencing the delegation class injecting other initialized beans. For example,

<serviceTask id="paymentTask" camunda:delegateExpression="${myPaymentBean}" />

In above, myPaymentBean is resolved from spring and it will be an instance of JavaDelegate which has already initialized with required dependencies through dependency injection (DI). We used DI, because our business logics needs to be tested thoroughly before going into production and easier to write automated tests on top of them.


If you use Java classes, then the instance initialization part will be done by the camunda engine, and there is a restriction that there must be a public default constructor. This is very limited since most of practical applications have dependencies and must be already initialized before the code. Either you have to make your dependencies as singletons (which is I never recommend) or use factories to create instances before code (which is inefficient and harder to test).

Hope this clarifies your question.



Related Topics



Leave a reply



Submit