是否可以使用具有lambda值的Map Map <key,function =“”>?

时间:2017-02-01 15:17:52

标签: java lambda

我为我生成了一系列课程因此我无法修改这些类以添加多态行为。不幸的是,我需要根据其继承中的类型有一些不同的行为。

一种解决方案是为所有这些对象编写装饰器,这样我就可以使用类似DDD的行为来扩充这些对象,或者使用一些访问者模式。但是,我想到了另一种更简单的方法来根据类型执行一些不同的行为。

以下是我的想法,本身就是一个有趣的练习,探讨了Lambda在Java中的可能性:

Map<Class, SomeLambdaFunction<String>> typeMap = ImmutableMap.<Class, SomeLambdaFunction<String>>builder()
    .put(SubClassA.class, () -> someCondition() ? "valueA" : "valueB")
    .put(SubClassB.class, () -> aStringMethod() + anotherStringMethod())
    .build();

我想查找&#39;这样一种行为。由于我不希望这些生成的课程集合再次发生变化(这是旧的遗留内容),我并不担心违反Open / Closed Principle

这可能吗?

2 个答案:

答案 0 :(得分:2)

Lambda你是什么意思? Class不是Java语言中的类型,也不是Java标准库中定义的类型。在运行时没有“lambda”这样的东西。至少,如果没有定义它,就没有这样的事情。

lambda 表达式只是一种创建新对象的方法。当然,您不能使用它来创建任何对象,但您可以使用它来创建属于实现某些特定功能接口的匿名类的对象。但是,lambda的结果与所有其他类型的对象并没有本质的区别。它只是 一个对象。

所以,你真正要问的是,“是否有可能创建一个将Map<Class, Foobar>类型的键映射到某些其他类型的值的地图?”

是。这是可能的。

更具体地说,您要求的是Foobar,其中SomeLambdaFunction<String>是您的lambda所有实现的功能接口类型的名称。

我认为如果你这样编写它会更有意义,而不是写@FunctionalInterface interface CustomBehavior { String doCustomThing(); } Map<Class, CustomBehavior> typeMap = ImmutableMap.<Class, CustomBehavior>builder() .put(SubClassA.class, () -> someCondition() ? "valueA" : "valueB") .put(SubClassB.class, () -> aStringMethod() + anotherStringMethod()) .build();

String

那些lambda表达式不返回CustomBehavior个对象;他们返回@FunctionalInterface interface CustomBehavior { String doCustomThing(); } class CustomBehaviorA implements CustomBehavior { public String doCustomThing() { return someCondition() ? "valueA" : "valueB"; } } class CustomBehaviorB implements CustomBehavior { public String doCustomThing() { return aStringMethod() + anotherStringMethod(); } } Map<Class, CustomBehavior> typeMap = ImmutableMap.<Class, CustomBehavior>builder() .put(SubClassA.class, new CustomBehaviorA()) .put(SubClassB.class, new CustomBehaviorB()) .build(); 个对象。下面的代码与上面的代码完全相同,除了它使用命名的classess而不是匿名类。

List<User> userList = new List<User>()
    {
        new User {IdUser = 1, Login = "Frank" },
        new User {IdUser = 2, Login = "Pat" },
        new User {IdUser = 3, Login = "Max" },
        new User {IdUser = 4, Login = "Paul" },
        new User {IdUser = 5, Login = "John" }
    };

User newUser = new User()
{
    IdUser = 3,
    Login = "Chris"
};

var foundUser = userList.FirstOrDefault(item => item.IdUser == newUser.IdUser);
if(foundUser != null)
    userList.Remove(foundUser)
userList.Add(newUser);

答案 1 :(得分:-1)

这是可能的,但您必须使用接口作为值类型,然后使用lambda定义实现该接口。

一些常见的界面是RunnableCallableSupplierFunction Runnable 没有返回值而 Callable 抛出Exception强制您抓住它, Function 需要一个参数。 供应商仍然是一个很好的候选人。

以下是基于供应商和子类的密钥的示例:

public String getLambdaValueForKey(String key) {
    final Map<Class<? extends YourBaseClass>, Supplier<String>> lambdaMap = ImmutableMap.<Class<? extends YourBaseClass>, Supplier<String>>builder()
        .put(SubclassA.class, () -> someCondition() ? "valueA" : "valueB")
        .put(SubclassB.class, () -> aStringMethod() + anotherStringMethod())
        .build();
    return lambdaMap.get(key).get(); // the 2nd get is Supplier's .get()
}

但是,正如评论中提到的那样,一般情况下,您可以通过明确的instanceof检查获得更好的效果。只有在非常具体的情况下(如固定生成的课程因遗留问题而无法改变),这将在长期内发挥作用。