获取lambda的参数和返回值

时间:2015-11-13 22:34:19

标签: java lambda

我有一个

的界面
public static interface MyClass{
    public boolean doSomething(boolean a, boolean b);
}

然后我实例化一个变量

MyClass a = (boolean x, boolean y) -> x && y;

现在我的问题是,如果我想获取参数x和y以及返回值,我将如何去做?我想获取参数的原因是因为我想序列化,以便我可以用它们ObjectOutputStream.writeObject()

不确定我的问题是否完全有意义。我没有太多地使用lambda,所以任何形式的指导都会受到高度赞赏。

添加:好的,所以MyClass a在另一个类中实例化,让我们称之为ParentClass。所以现在我有了

MyClass a = (x, y) -> x && y;
    ParentClass b = new ParentClass();
    b.setMyClass(a);

现在,在我正在上课的主要班级中,我通过了ParentClass b。所以我接受并做到了     MyClass c = b.getMyClass; 如果我理解正确的话,那就是对(x, y) -> x && y;的引用。现在的问题是,如何获取参数值和返回值,以便我可以序列化它。 MyClass也不总是(x,y) -> x && y,它可能是任何东西,即

MyClass a = (x, y) -> x || y;
MyClass a = (x, y) -> x^y;
MyClass a = (x, y) -> true;

我不允许修改MyClass或ParentClass。这就是为什么我试图获取传递的参数和返回值,以便我可以序列化并发送它们。

3 个答案:

答案 0 :(得分:3)

我怀疑你误解了lambda表达式是如何工作的。您的问题意味着您希望创建a对象,然后对其进行序列化,并在此过程中以某种方式记录xy的值。我理解正确吗?

如果是这样,那么从根本上讲,这不是lambdas的工作方式。它们不是普通意义上的包含状态的对象。相反,可以将它们视为可以传递的一些可执行代码,可以随时应用于一组值(我怀疑我会在评论中因为过于简单的解释而受到重创!)。

您可以序列化lambda,但在这种情况下,您将序列化由lambda表示的操作,而不是在任何给定调用中传递给它的值。

如果您希望MyClass接口的实现可序列化,则需要扩展Serializable。它应该如下所示:

@FunctionalInterface
public interface MyClass extends Serializable {
    boolean doSomething(boolean a, boolean b);
}

如果您无法修改MyClass,那么您仍然可以将MyClass对象转换为Serializable

Serializable a = (Serializable & MyClass)(a, b) -> a || b;

或者如果您使用ParentClass

中的值
Serializable a = (Serializable)b.getMyClass();

然后您应该能够序列化a

请记住,当您反序列化时,需要转回MyClass以便可以使用它。它看起来像:

MyClass b = (Serializable & MyClass)objectInStream.readObject();
b.doSomething(true, false);

答案 1 :(得分:2)

在Java中,简单地说,lambda语法是一种描述方法行为而不给它命名的方法。

e.g。 (Type1 arg1, Type2 arg2, ...) -> <expression> 定义一个看起来像这样的函数:

public TypeOfExpression anonymousMethod(Type1 arg1, Type2 arg2, ...) {
    ...
    return <expression>;
}

查看Java Tutorials以获取有关lambdas的更多信息。

实际上lambda表达式(boolean x, boolean y) -> x && y(当你定义它时给定类型MyClass)只不过是以下的语法糖:

new MyClass() {
    public boolean doSomething(boolean x, boolean y) {
        return x && y;
    }
}

希望能够清楚地说明lambdas在Java中代表什么。

在技术术语中,您提供的界面定义定义了'function type'。在Java中,任何只有一个方法的接口都称为“functional”,并且可以作为与接口中单个方法相同类型的lambda表达式的类型而不是接口使用。

这个决定可能是因为如果一个接口只有一个方法,那么指定它的所有方法就是该方法的行为,它可以用lambda表示法更简洁地写出来,如上所示。

因此,lambda表达式只是接口的一个实例 - 特别是它没有字段,但定义了一个方法行为。我认为你假设它封装了一对输入及其输出结果。如果这是您所需要的,那么您可能正在寻找更像内置操作的对类型(在本例中为&&)。

编辑:关于可串行化。

很明显,您需要序列化MyClass类型的未知函数。如果MyClass扩展Serializable,您应该能够适当地进行投射和序列化。如果您无法控制MyClass,因此无法确保这一点,以下特别观察可能有所帮助。

如果MyClass中的方法确实属于此处显示的类型(boolean, boolean) -> boolean,则可以考虑手动序列化的案例数量足够少。

类型A -> B的“可能”(总)函数的数量,对于有限大小的类型AB|B| ^ |A|B的大小与A的功率大小相同。这是因为,计算可能的函数,对于A类型的每个输入,函数可以提供|B|个可能的输出。

此外,对(A, B)类型的大小为|A| * |B|

在我们的案例中,我们有(boolean, boolean) -> boolean。但boolean只有2号!因此(boolean, boolean)的大小为4,(boolean, boolean) -> boolean的大小为2 ^ 4 = 16。

我们如何计算出我们手中的这16项功能中的哪一项?只需枚举可能的输入(只做4个)。然后我们可以在这样的变量中记录四个输出(其中a将是我们未知的函数。)

boolean ttout = a(true, true);
boolean tfout = a(true, false);
boolean ftout = a(false, true);
boolean ffout = a(false, false);

然后我们可以快乐地序列化这四个值。 :)

此外,如果我们反序列化并获得四个值(ttouttfout ...),我们可以重建这样的函数:

a = (boolean x, boolean y) -> {
    if (x) {
        if (y) return ttout;
        else return tfout;
    } else {
        if (y) return ftout;
        else return ffout;
    }
}

答案 2 :(得分:1)

如果您希望a本身可序列化,则可以编写a = (MyClass & Serializable) (boolean x, boolean y) -> x && y

x的定义中没有ya:这些仅在实际调用a时存在。