将函数映射到数组元素上

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

Mapping functions to elements of array

问题

我有一个关于在Java中映射事物的一般性问题。我并没有完全卡住,但我觉得我的方法不够优美,如果想象一下我的小型私人项目会变得更大,可能会出问题。

假设我有一个数组 = {1, 2, 3, 4},它不一定是数字,只是一般的任何标志。
然后我从用户那里得到一个输入,该输入只能是数组的一部分(不可能有无效输入)。现在取决于他们选择的元素,将执行特定的函数。我想到的唯一方法是:

switch (input) {
    case array[0]:
        doOneThing();
        break;
    case array[1]:
        doAnotherThing();
        break;
    case array[2]:
        doAThirdThing();
        break;
    case array[3]:
        doSomethingElse();
        break;
}

这种方法有效,但不够灵活。我会非常感谢任何可能的建议。

英文:

I am have a general question about mapping things in java. I am not quite stuck, but I feel that my approach is not really beautiful and could cause problems if one would imagine my small private project will become bigger.

Imagine I have an array = {1, 2, 3, 4}, it does not have to be numbers, just any sign in general.
Then I get an input from a user, which can only be part of an array (no invalid inputs possible). Now depends on which element they choose, a specific function will be executed. The only thing I came up with is:

switch (input) {
   case array[0]:
      doOneThing();
      break;
   case array[1]:
      doAnotherThing();
     break;
   case array[2]:
      doAThirdThing();
      break;
   case array[3]:
      doSomethingElse();
       break;
}

This method works, but is not beautiful to expand. I take every possible idea with great thanks.

答案1

得分: 1

以下是您提供的内容的翻译部分:

你的 switch 语句中必须有常量,所以你指定的方式是行不通的。但你可以像下面这样做一个示例。你不限于使用 Runnable lambdas。任何函数式接口都可以使用,并在调用时提供适当的参数。

需要注意的是,允许调用 任何 类的 任何 方法并不是一个好主意,因为这可能会导致意想不到的结果或安全问题,具体取决于如何使用它。

public class ThisClass {
	
	public static void main(String[] args) {
		Map<String, Runnable> map = new HashMap<>();
		ThisClass tc = new ThisClass();
		
		map.put("A", () -> tc.doOneThing());
		map.put("B", () -> tc.doAnotherThing());
		map.put("C", () -> tc.doAthirdThing());
		map.put("D", () -> tc.doSomethingElse());
		
		for (String str : new String[] { "A", "B", "Q", "C", "D", "E" }) {
			map.getOrDefault(str, () -> tc.defaultMethod()).run();
		}
	}
	
	public void doOneThing() {
		System.out.println("Doing one thing");
	}
	
	public void defaultMethod() {
		System.out.println("Executing default");
	}
	
	public void doAnotherThing() {
		System.out.println("Doing Another thing");
	}
	
	public void doAthirdThing() {
		System.out.println("Doing a third thing");
	}
	
	public void doSomethingElse() {
		System.out.println("Doing something Else");
	}
}

输出结果:

Doing one thing
Doing Another thing
Executing default
Doing a third thing
Doing something Else
Executing default

你还可以像下面这样做:

Map<String, DoubleBinaryOperator> map = new HashMap<>();

map.put("+", (a, b) -> a + b);
map.put("-", (a, b) -> a - b);
map.put("*", (a, b) -> a * b);
map.put("/", (a, b) -> a / b);

DoubleBinaryOperator error = (a, b) -> {
	throw new IllegalArgumentException();
};

for (String str : new String[] { "+", "-", "L", "/", "*" }) {
	try {
		double result = map.getOrDefault(str, error)
				.applyAsDouble(2.0, 3.0);
		System.out.println("result = " + result);
	} catch (IllegalArgumentException iae) {
		System.out.println("unknown operator \"" + str + "\"");
	}
}

输出结果:

result = 5.0
result = -1.0
unknown operator "L"
result = 0.6666666666666666
result = 6.0
英文:

You must have constants in your switch statement so what you specified won't work. You could do something like this though as an example. You're not limited to using Runnable lambdas. Any functional Interface could be used and the appropriate arguments supplied when called.

Note that it is not a good idea to allow any method of any class to be invoked as it could lead to unexpected results or security issues depending on how it is to be used.

public class ThisClass {
public static void main(String[] args) {
Map&lt;String, Runnable&gt; map = new HashMap&lt;&gt;();
ThisClass tc = new ThisClass();
map.put(&quot;A&quot;, () -&gt; tc.doOneThing());
map.put(&quot;B&quot;, () -&gt; tc.doAnotherThing());
map.put(&quot;C&quot;, () -&gt; tc.doAthirdThing());
map.put(&quot;D&quot;, () -&gt; tc.doSomethingElse());
for (String str : new String[] { &quot;A&quot;, &quot;B&quot;, &quot;Q&quot;, &quot;C&quot;, &quot;D&quot;, &quot;E&quot; }) {
map.getOrDefault(str, () -&gt; tc.defaultMethod()).run();
}
}
public void doOneThing() {
System.out.println(&quot;Doing one thing&quot;);
}
public void defaultMethod() {
System.out.println(&quot;Executing default&quot;);
}
public void doAnotherThing() {
System.out.println(&quot;Doing Another thing&quot;);
}
public void doAthirdThing() {
System.out.println(&quot;Doing a third thing&quot;);
}
public void doSomethingElse() {
System.out.println(&quot;Doing something Else&quot;);
}
}

Prints

Doing one thing
Doing Another thing
Executing default
Doing a third thing
Doing something Else
Executing default

You can also do something like this.

Map&lt;String, DoubleBinaryOperator&gt; map = new HashMap&lt;&gt;();
map.put(&quot;+&quot;, (a, b) -&gt; a + b);
map.put(&quot;-&quot;, (a, b) -&gt; a - b);
map.put(&quot;*&quot;, (a, b) -&gt; a * b);
map.put(&quot;/&quot;, (a, b) -&gt; a / b);
DoubleBinaryOperator error = (a, b) -&gt; {
throw new IllegalArgumentException();
};
for (String str : new String[] { &quot;+&quot;, &quot;-&quot;, &quot;L&quot;, &quot;/&quot;, &quot;*&quot; }) {
try {
double result = map.getOrDefault(str, error)
.applyAsDouble(2.0, 3.0);
System.out.println(&quot;result = &quot; + result);
} catch (IllegalArgumentException iae) {
System.out.println(&quot;unknown operator \&quot;&quot; + str + &quot;\&quot;&quot;);
}
}

Prints

result = 5.0
result = -1.0
unknown operator &quot;L&quot;
result = 0.6666666666666666
result = 6.0
</details>
# 答案2
**得分**: 0
一种可能的方法是,如果您可以使用他们输入的值创建一个函数的名称。例如,如果他们输入1,您将调用"function1",如果输入2,您将调用"function2"。然后,您可以使用反射通过其字符串名称调用该方法。
类似于[这样。][1]
[1]: https://stackoverflow.com/questions/160970/how-do-i-invoke-a-java-method-when-given-the-method-name-as-a-string
<details>
<summary>英文:</summary>
One possible way is if you can create a name of a function using their inputted value. For example, if they input 1, you will call &quot;function1&quot; or if you input 2, you call &quot;function2&quot;. Then you can use reflection to call the method by it&#39;s string name. 
Something like [this.][1] 
[1]: https://stackoverflow.com/questions/160970/how-do-i-invoke-a-java-method-when-given-the-method-name-as-a-string
</details>
# 答案3
**得分**: 0
听起来你想要查看Java反射API。

Class c=Class.forName("xxxx")


这里的 {xxxx} 是你从参数构造的字符串。
你可以类似地调用方法名称。
注意 - 美丽的代码往往伴随着一些代价 - 无论是可读性、性能还是安全性(尤其在反射的情况下)。就个人而言,我不介意一个长的 switch 语句 - 它可能不太优雅,但它永远不会咬到你。
<details>
<summary>英文:</summary>
Sounds like you want to look at Java Reflection Api.

Class c=Class.forName("xxxx")


where {xxxx} is a string you have constructed from parameters. 
you can similarly invoke method names.
Note - beautiful code often comes at some cost - be it readability, performance or security (esp in the case of reflection). Personally i don&#39;t mind a long switch statement - it might not be pretty but it will never bite you.
</details>

huangapple
  • 本文由 发表于 2020年9月5日 04:22:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/63747619.html
匿名

发表评论

匿名网友

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

确定