带有两个参数的方法的双冒号赋值

时间:2017-01-17 13:31:58

标签: java lambda java-8

我正在使用lamdbas,所以我可以根据我可以从三个不同对象检索的值一致地设置ModelObject的属性。代码的工作原理如下:

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);
}

我已阅读here,可以将bar(value -> model.setB(value), bObject);重写为bar(model::setB, bObject)。我认为这看起来更好,更简洁,但我还没有找到将setA方法重写为double :: notation的方法。任何人都可以告诉我这是否可行,如果可以的话:这怎么可能?

4 个答案:

答案 0 :(得分:5)

来自https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.htmlhttps://www.codementor.io/eh3rrera/tutorials/using-java-8-method-reference-du10866vx

将有4种不同的方法参考。相应的lambda和方法参考:

  • (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

lambda 值 - > model.setA(CONSTANT,value)与上面的任何lambda不对应,因此无法将其重写为方法引用。

答案 1 :(得分:4)

要使用双冒号表示法,您引用的方法必须与所需方法具有相同的签名。因此,除非您更改::

,否则无法使用IModel

您可以在setA中添加IModel的重载:

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

然后,您可以引用该重载:

bar(model::setA, aObject);

答案 2 :(得分:3)

您不需要特殊界面:setBConsumer<String>setABiConsumer<String, String>。然后,您可以将BiConsumer调整为Consumer

使用界面中的默认方法(如果始终使用常量调用setA,为什么不呢?):

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);
}

使用BiConsumerConsumer的适配器:

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);
}

并像这样使用它:

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

注意:我使用adapt作为示例名称,但当您将其与其他adapt重载方法混合时,这是一个糟糕的名称(因为通用和类型擦除)。我个人将其命名为fixLeftValue

请注意,每次调用adapt时都会生成foo

答案 3 :(得分:2)

不是编写Setter功能接口的方式。与setBsetC不同,setA方法需要两个参数,而接口Setter的方法只需要一个参数。您可以添加另一个接受两个参数的接口:

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

然后您可以通过bar方法调用它:

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

然后您可以按如下方式致电bar

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

注意:您可以保留其他bar方法。新的可能是一个过载。