【问题标题】:Pass lambda (Object -> Object) to function in Java [duplicate]将 lambda(对象-> 对象)传递给 Java 中的函数 [重复]
【发布时间】:2020-11-11 16:05:55
【问题描述】:

当我希望将 lambda 传递给函数时使用什么类型,而 lambda 接受并返回一个对象?

使用示例如下所示。我希望能够创建 Foo 的实例,在此示例中,每个实例都可以调用预先指定的 getter 函数。

class Foo() {
public ? lambdaFunction;

public Object doSomething(Object arbitraryClass);
    return lambdaFunction(arbitraryClass);
}

foo.lambdaFunction = (Object object) -> ((SomeClass) object).getAttribite())
foo.doSomething(someClassInstance);

我有大量具有许多可获取属性的类,并且需要能够在不同的地方获取所有这些属性,但唯一改变的是实际类的 getter 名称。

【问题讨论】:

    标签: java functional-interface


    【解决方案1】:
    class Foo {
        private final Function<Object, ?> func;
    
        public Foo(Function<Object, ?> func) {
            this.func = func;
        }
    
        public Object doSomething(Object in) {
            return func.apply(in);
        }
    }
    

    但我怀疑你是否真的想要那样。 Java 是一种名义上的类型化语言——你应该使用名称,而且很多。 “对象”没有多大意义。例如,假设函数需要能够转换 any 对象,那么您传入的函数不能对该对象执行任何操作(嗯,除了toStringhashCode 和所有对象都有的其他方法)。该函数可以强制转换输入,但这很丑。

    这听起来已经是一个更好的计划了:

    class Foo<F, T> {
        private final Function<? super F, ? extends T> func;
    
        public Foo(Function<? super F, ? extends T> func) {
            this.func = func;
        }
    
        public T doSomething(F in) {
            return func.apply(in);
        }
    }
    

    F 和 T 是 'from' 和 'to' 的缩写。它是? super F 的原因是因为如果您希望将字符串转换为整数,并且您有一个将任何对象转换为整数的函数,那也很好:您希望它转换字符串或其任何超类型,对于 'to',任何子类型也可以。


    根据您最近的 cmets 扩展此答案:

    Java 不是动态类型。鉴于提供的输入,没有任何可能有意义或可能没有意义的随机神秘功能。因此,如果你想要一个描述 setter 的函数,例如需要 2 个输入参数',那么这是一个完全不同的概念:那将是一个需要设置接收器和新值的函数,并且什么也不返回。 2 个输入,0 个输出。 j.u.f.Function 是 1 个输入,1 个输出。

    2 个输入,0 个输出将是 java.util.function.BiConsumer&lt;T, U&gt;。查看这些类型的 java.util.function API。

    class Example {
        private String name;
    
        public void setName(String name) { this.name = name; }
        public String getName() { return name; }
    
        public static final BiConsumer<Example, String> SETTER = Example::setName;
    }
    
    class SomeplaceElse {
        void foo() {
            Example e = new Example();
            String n = "hello";
            Example.SETTER.accept(e, n);
            System.out.println(e.getName()); // prints 'hello'
        }
    }
    

    【讨论】:

    • 可以通过将类作为另一个参数传递给构造函数来以某种方式指定输入和输出类型吗?这个类的使用实际上知道正在使用什么类型。它只是Foo 必须能够覆盖所有这些。但是输出的类可以传递给构造函数(当时是已知的)。
    【解决方案2】:

    java.util.function.Function&lt;T,R&gt;,其中T 是其参数的类型,R 是其返回类型。

    但如果你真的打算有一个 public Function&lt;Object,Object&gt; lambdaFunction; 字段,那可能不是最好的设计,你应该使用你的实际类型,而不是来回转换。


    对于出现在评论中的扩展:查看包含的包,https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/function/package-summary.html 看看还有什么“准备好”。
    对于有 2 个参数并返回一些内容,您可以使用 BiFunction&lt;T,​U,​R&gt;。对于有 2 个参数并且不返回任何内容,您可以使用 BiConsumer&lt;T,​U&gt;。如果你没有找到你需要的东西,那么你可以创建自己的interface 并将其标记为@FunctionalInterface。但这会导致一个重复的问题,What are functional interfaces used for in Java 8?

    【讨论】:

      【解决方案3】:

      java.util.function.Function 是要使用的类型。

      【讨论】:

      • java.util.function.Function
      • 如果我介意一个额外的问题,你如何将它扩展到 setter,也就是接受 2 个对象参数(第一个是类,第二个是属性值)?
      猜你喜欢
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-10
      • 1970-01-01
      • 2020-07-27
      相关资源
      最近更新 更多