Dual Colon Assignment Using Two Parameters

I use lamdbas so that I can sequentially set ModelObject properties according to the values ​​that I can extract from three different objects. The code works as follows:

public class Processor { private void bar(Setter setter, MyClass myObject) { String variable = myObject.getStringByABunchOfMethods(); setter.setVariable(variable); } protected void foo(...) { ... bar(value -> model.setA(CONSTANT, value), aObject); bar(value -> model.setB(value), bObject); bar(value -> model.setC(value), cObject); ... } private interface Setter { public void setVariable(String string); } } public interface IModel { public void setA(String arg0, String arg1); public void setB(String arg0); public void setC(String arg0); } 

I read here that you can rewrite bar(value -> model.setB(value), bObject); on bar(model::setB, bObject) . I think this looks better and more concise, but I have not found a way to rewrite the setA method to double :: notation. Can someone tell me if this is possible, and if so: how is this possible?

+5
source share
4 answers

from https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html and https://www.codementor.io/eh3rrera/tutorials/using-java-8-method-reference-du10866vx

There would be 4 different types of method references. Corresponding lambda and method reference:

  • (args) β†’ Class.staticMethod (args), class :: staticMethod
  • (obj, args) β†’ obj.instanceMethod (args), ObjectType :: instanceMethod
  • (args) β†’ obj.instanceMethod (args), obj :: instanceMethod
  • (args) β†’ new ClassName (args), ClassName :: new

The lambda value β†’ model.setA (CONSTANT, value) does not match any of the above lambdas, so it is impossible to rewrite it as a reference to a method.

+5
source

To use a double colon, the method you refer to must have the same signature as the required method. Therefore, you cannot use :: unless you change your IModel :

You can add setA overload to IModel :

 default void setA(String arg0) { setA(CONSTANT, arg0); } 

Then you can reference this overload:

 bar(model::setA, aObject); 

.

+4
source

Not the way the Setter functional interface is written. Unlike setB and setC , the setA method expects two arguments, while the Setter interface has a method that expects only one argument. You can add another interface that takes two arguments:

 private interface SetterWithDefault { public void setVariable(String defaultString, String string); } 

Then you can call it using the bar method:

 private void bar(SetterWithDefault setter, String defaultString, MyClass myObject) { String variable = myObject.getStringByABunchOfMethods(); setter.setVariable(defaultString, variable); } 

Then you can call bar as follows:

 bar(model::setA, CONSTANT, aObject); 

Note. . You can save another bar method. New may be overload.

+2
source

You do not need a special interface: setB is Consumer<String> , and setA is BiConsumer<String, String> . Then you can adapt BiConsumer to Consumer :

Or with the standard method in your interface (if setA always called with a constant, why not?):

 interface Model { public void setA(String arg0, String arg1); default void setA(String arg1) {setA(CONSTANT, arg1);} public void setB(String arg0); public void setC(String arg0); } 

Or use an adapter from BiConsumer to Consumer :

 static <T, U> Consumer<V> adapt(T t, BiConsumer<T, U> biConsumer) { Objects.requireNonNull(biConsumer, "biConsumer"); Objects.requireNonNull(t, "t"); return t -> biConsummer.accept(t, u); } 

And using it like this:

  protected void foo(...) { ... bar(adapt(CONSTANT, model::setA), aObject); bar(model::setB, bObject); bar(model::setC, cObject); ... } 

Note. I used adapt as an example name, but this is a bad name when you mix it with another adapt overload adapt (due to the generic and erasable type). I call it fixLeftValue .

Beware that adapt will be generated every time foo called.

+2
source

Source: https://habr.com/ru/post/1262932/


All Articles