在Java中的lambda函数树?

huangapple go评论72阅读模式
英文:

Tree of lambda functions in Java?

问题

我正在移植一些软件,它在Swift和JavaScript中运行正常,但我无法弄清楚如何在Java中实现。

JavaScript版本如下:

var obj = { 
  "A": {
    "1": (params) => { console.log("A1", params); },  
    "2": (params) => { console.log("A2", params); }
  }, 
  "B": {
    "1": (params) => { console.log("B1", params); },  
    "2": (params) => { console.log("B2", params);}
  }
}; 

在运行时,应用引擎调用:

var a = 'A'; 
var i = '2';
obj[a][i](params);

我无法想出如何在Java中实现这一点。一个关键约束是代码结构必须与其他移植版本相似。

之前,我尝试使用Object[][],例如:

Map<String, Object> map = Stream.of(obj).collect(Collectors.toMap(data -> (String) data[0], data -> (Object) data[1]));

以便能够嵌入一些Map<String, Integer>对象。例如:

Map<String, Integer> colorMap = Stream.of(new Object[][] {
    {"black", 0x000000},
    {"navy", 0x000080},
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Integer) data[1]));

我试图得到类似的代码,但Java不喜欢它,因为Lambda表达式和Object不兼容。

我希望得到的代码是:

Map<String, Map<String, Callable<Void>>> obj = Stream.of(new Object[][] {
  {"A", Stream.of(new Object[][] {
    {"1", (params) -> { System.out.println("A1"); } },
    {"2", (params) -> { System.out.println("A2"); } }
  })},
  {"B", Stream.of(new Object[][] {
    {"1", (params) -> { System.out.println("B1"); } },
    {"2", (params) -> { System.out.println("B2"); } }
  })}
}).collect(Collectors.toMap(data -> (String) data[0], data -> data[1]));
...
// 调用函数(假设A和1存在)
obj.get("A").get("1").call();

但我被如何将其转换为能够使用Lambda表达式所困扰。我一直收到的错误是:
error: incompatible types: Object is not a functional interface
error: lambda expression not expected here

英文:

I am porting some software and it's working in Swift and JavaScript, but I cannot figure out how to do it in Java.

The JavaScript version looks like:

var obj = { &quot;A&quot;: {
      &quot;1&quot;: (params) =&gt; { console.log(&quot;A1&quot;, params); },  
      &quot;2&quot;: (params) =&gt; { console.log(&quot;A2&quot;, params); }
    }, // A
    &quot;B&quot;: {
      &quot;1&quot;: (params) =&gt; { console.log(&quot;B1&quot;, params); },  
      &quot;2&quot;: (params) =&gt; { console.log(&quot;B2&quot;, params);}
     }, //B
}; // obj

Where at runtime, the application engine calls

var a = &#39;A&#39;; 
var i = &#39;2&#39;;
obj[a][i](params);

I for the life of me cannot figure out how to do this in Java. One key constraint (no pun intended) is that the code must be structurally similar to the other ports.

Previously, I was trying to use Object[][], with

Map&lt;String, Object&gt; map = Stream.of(obj).collect(Collectors.toMap(data -&gt; (String) data[0], data -&gt; (Object) data[1]));

to be able to embed some Map<String, Integer> objects. Example:

Map&lt;String, Integer&gt; colorMap = Stream.of(new Object[][] {
		{&quot;black&quot;, 0x000000},
		{&quot;navy&quot;, 0x000080},
};

I tried to arrive at similar code, but Java did not like it, because lambdas and Object are not compatible.

The code I am looking to arrive at is:

Map&lt;String, Map&lt;String, Callable&lt;Void&gt; &gt; &gt; obj =  Stream.of(new Object[][] {
  {&quot;A&quot;, Stream.of(new Object[][] {
    {&quot;1&quot;, (params)-&gt;{ System.out.println(&quot;A1&quot;); } },
    {&quot;2&quot;, (params)-&gt;{ System.out.println(&quot;A2&quot;); } } }),
  {&quot;B&quot;, Stream.of(new Object[][] {
    {&quot;1&quot;, (params)-&gt;{ System.out.println(&quot;B1&quot;); } },
    {&quot;2&quot;, (params)-&gt;{ System.out.println(&quot;B2&quot;); } } } )}
  } 
});
...
// call the function (assuming A and 1 exist)
obj.get(&quot;A&quot;).get(&quot;1&quot;)(params);

But I am stumped on how to convert this to being able to use lambdas. The error I keep getting is:
error: incompatible types: Object is not a functional interface
or error: lambda expression not expected here

答案1

得分: 6

一种可能的保留结构的 Java 翻译是:

Map<String, Map<String, Runnable>> obj = Map.of(
    "A", Map.of(
        "1", () -> System.out.println("A1"),
        "2", () -> System.out.println("A2")
    ),
    "B", Map.of(
        "1", () -> System.out.println("B1"),
        "2", () -> System.out.println("B2")
    )
);

// 使用方式
obj.get("A").get("2").run();

// 如果需要传递参数或从函数返回值,请用不同的函数式接口替换 Runnable。你可能需要自己定义一个,例如:

@FunctionalInterface
interface FunctionWithObjectParameters {
    void run(Object... args);
}

更新: 如果你需要在 Java 8 中进行此操作,一个选择是使用一个具有更方便构造映射的方法的外部库,比如 guava collect

另一个选项是自己实现这些便捷方法。Map.of 并没有任何魔法,你可以轻松地用自己的 "mapOf" 方法替换它:

static <K, V> Map<K, V> mapOf(K key1, V value1) {
    return mapOfEntries(entry(key1, value1));
}

static <K, V> Map<K, V> mapOf(K key1, V value1, K key2, V value2) {
    return mapOfEntries(entry(key1, value1), entry(key2, value2));
}

static <K, V> Map<K, V> mapOf(K key1, V value1, K key2, V value2, K key3, V value3) {
    return mapOfEntries(entry(key1, value1), entry(key2, value2), entry(key3, value3));
}

// 如果需要,添加更多的重载

static <K, V> Map<K, V> mapOfEntries(Map.Entry<K, V>... args) {
    // 在 Android 上,你可能想使用 ArrayMap 而不是 HashMap
    Map<K, V> map = new HashMap<>();
    for (Map.Entry<K, V> arg : args) {
        map.put(arg.getKey(), arg.getValue());
    }
    return map;
}

static <K, V> Map.Entry<K, V> entry(K key, V value) {
    return new AbstractMap.SimpleEntry<>(key, value);
}
英文:

One possible structure-preserving translation to Java is:

Map&lt;String, Map&lt;String, Runnable&gt;&gt; obj = Map.of(
    &quot;A&quot;, Map.of(
        &quot;1&quot;, () -&gt; System.out.println(&quot;A1&quot;),
        &quot;2&quot;, () -&gt; System.out.println(&quot;A2&quot;)
    ),
    &quot;B&quot;, Map.of(
        &quot;1&quot;, () -&gt; System.out.println(&quot;B1&quot;),
        &quot;2&quot;, () -&gt; System.out.println(&quot;B2&quot;)
    )
);

You use it like this:

obj.get(&quot;A&quot;).get(&quot;2&quot;).run();

If you need to pass arguments, or return values from the functions, replace Runnable with a different functional interface. You may have to defined one of your own. For example:

@FunctionalInterface
interface FunctionWithObjectParameters {
    void run(Object... args);
}

Update: If you need to do this in Java 8, one option is to use an external library that has methods to construct maps in a more convenient way - like guava collect.

Another option is to implement the convenience methods yourself. Map.of does not do any magic, you can easily replace it with your own "mapOf" method:

static &lt;K, V&gt; Map&lt;K, V&gt; mapOf(K key1, V value1) {
    return mapOfEntries(entry(key1, value1));
}

static &lt;K, V&gt; Map&lt;K, V&gt; mapOf(K key1, V value1, K key2, V value2) {
    return mapOfEntries(entry(key1, value1), entry(key2, value2));
}

static &lt;K, V&gt; Map&lt;K, V&gt; mapOf(K key1, V value1, K key2, V value2, K key3, V value3) {
    return mapOfEntries(entry(key1, value1), entry(key2, value2), entry(key3, value3));
}

// Add  more overloads if you need

static &lt;K, V&gt; Map&lt;K, V&gt; mapOfEntries(Map.Entry&lt;K, V&gt;... args) {
    // On Android, you may want to use ArrayMap instead of HashMap
    Map&lt;K, V&gt; map = new HashMap&lt;&gt;();
    for (Map.Entry&lt;K, V&gt; arg : args) {
        map.put(arg.getKey(), arg.getValue());
    }
    return map;
}

static &lt;K, V&gt; Map.Entry&lt;K, V&gt; entry(K key, V value) {
    return new AbstractMap.SimpleEntry&lt;&gt;(key, value);
}

huangapple
  • 本文由 发表于 2020年8月21日 06:12:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/63513810.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定