将参数传递给 lambda 表达式 - Java
Pass parameter to lambda expression - Java
我的程序要求我接受用户输入,并根据这个输入执行一个方法。以下question/answer很好地描述了我的基本想法:
How to call a method stored in a HashMap? (Java)
为此,我创建了一个 lambda 表达式数组:
public final Runnable[] userCommandMethods = {
() -> userCommand1(),
() -> userCommand2(),
};
还有一组键:
public final String[] userCommandKeys = {
commandKey1,
commandKey2,
};
使用以下方法连接创建HashMap:
public Map<String, Runnable> mapArrays (String[] array1, Runnable[] array2) {
Map<String, Runnable> mappedArrays = new HashMap<String, Runnable>();
for (int i = 0; i < array1.length; i ++) {
mappedArrays.put(array1[i], array2[i]);
}
return mappedArrays;
}
当我尝试使用 myHashMap.get(userInput).run();
运行 一个方法时,它完美地工作,前提是 userCommandMethods
中的 none 方法需要输入参数。
我的问题:
如何将输入参数(特别是哈希映射)传递到 userCommandMethods
中包含的方法?
当 userCommand1()
方法接受输入参数,但 lambda 表达式不接受时,出现以下错误:
The method userCommand1(Map<String, String>) in the type ProgramCommands is not applicable for the arguments ()
但是,当我将参数传递给该方法时,它指出无法将其解析为变量。
编辑:详述:
当 userCommand1()
方法不带参数时:
public void userCommand1 () {
// Do some stuff
}
它工作得很好。但是,如果该方法确实采用输入参数,我不确定如何使用 lambda 表达式:
public void userCommand1 (Map<String, String> myMap) {
// Do some stuff
}
这是你的想法吗?
interface Command<T> {
public void run(T arg);
}
class SayHelloCommand implements Command<String>{
public void run(String name){
System.out.println("hello " + name);
}
}
class CountCommand implements Command<Integer>{
public void run(Integer limit){
for(int i=0; i<=limit; i++)
System.out.println(i);
}
}
public class Main{
public static void main(String[] args) {
Command[] commands = new Command[3];
commands[0] = new SayHelloCommand();
commands[1] = new CountCommand();
commands[0].run("Joe");
commands[1].run(5);
}
}
您只需要选择另一个功能界面(不是Runnable
)。
例如,如果您的方法都采用 String
参数,则您应该使用 Consumer<String>
. If they take a String
and an int
, then you should use BiConsumer<String, Integer>
. If your methods need more than 2 parameters, you need to create your own functional interface. For an example, see my answer .
// use a list instead of an array, because arrays don't work well with generic types
public final List<Consumer<String>> userCommandMethods = List.of(
x -> userCommand1(x),
x -> userCommand2() // it's fine if the method takes fewer parameters
);
而不是 run
,你会调用 accept
,这就是 Consumer
和 BiConsumer
的单一抽象方法的调用。
请注意,您还可以使用方法引用语法。如果 userCommand1
是静态的,x -> userCommand1(x)
可以重写为 SomeClass::userCommand1
,其中 SomeClass
是 userCommand1
的封闭 class。如果 userCommand1
是非静态的,可以改写为 this::userCommand1
.
您不需要从两个数组构建地图。您可以使用 ofEntries
and entry
内联写入条目。
private final Map<String, Consumer<String>> someMap = Map.ofEntries(
Map.entry("foo", SomeClass::userCommand1),
Map.entry("bar", SomeClass::userCommand2),
Map.entry("baz", SomeClass::userCommand3),
// and so on
)
您正在使用不接受输入参数的 Runnable 接口:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
相反,您可以定义自定义界面并使用它。
举个简单的例子:
@FunctionalInterface
public interface RunnableWithArg {
void apply(String t) throws RuntimeException;
}
实现可能如下所示:
public class RunnableTest {
//also fine:
//public final RunnableWithArg[] userCommandMethods = { t -> this.userCommand1(t), t -> this.userCommand2(t) };
public final RunnableWithArg[] userCommandMethods = { this::userCommand1, this::userCommand2 };
public String commandKey1 = "commandKey1";
public String commandKey2 = "commandKey2";
public final String[] userCommandKeys = { commandKey1, commandKey2, };
public Map<String, RunnableWithArg> mapArrays(String[] array1, RunnableWithArg[] array2) {
Map<String, RunnableWithArg> mappedArrays = new HashMap<>();
for (int i = 0; i < array1.length; i++) {
mappedArrays.put(array1[i], array2[i]);
}
return mappedArrays;
}
public void userCommand1(String data) {
System.out.println("userCommand1 called with " + data);
}
public void userCommand2(String data) {
System.out.println("userCommand2 called with " + data);
}
public void test()
{
var fncMap = mapArrays(userCommandKeys, userCommandMethods);
for(String key: fncMap.keySet())
{
var fnc = fncMap.get(key);
fnc.apply(key);
}
}
}
当然你也可以像这样定义一些通用类型的“@FunctionalInterface”,这样你就可以用它来获取输入和返回一些通用类型的输出:
@FunctionalInterface
public interface AbcFunction<T, R> {
R apply(T t) throws AbcException;
static <T> Function<T, T> identity() {
return t -> t;
}
}
我的程序要求我接受用户输入,并根据这个输入执行一个方法。以下question/answer很好地描述了我的基本想法:
How to call a method stored in a HashMap? (Java)
为此,我创建了一个 lambda 表达式数组:
public final Runnable[] userCommandMethods = {
() -> userCommand1(),
() -> userCommand2(),
};
还有一组键:
public final String[] userCommandKeys = {
commandKey1,
commandKey2,
};
使用以下方法连接创建HashMap:
public Map<String, Runnable> mapArrays (String[] array1, Runnable[] array2) {
Map<String, Runnable> mappedArrays = new HashMap<String, Runnable>();
for (int i = 0; i < array1.length; i ++) {
mappedArrays.put(array1[i], array2[i]);
}
return mappedArrays;
}
当我尝试使用 myHashMap.get(userInput).run();
运行 一个方法时,它完美地工作,前提是 userCommandMethods
中的 none 方法需要输入参数。
我的问题:
如何将输入参数(特别是哈希映射)传递到 userCommandMethods
中包含的方法?
当 userCommand1()
方法接受输入参数,但 lambda 表达式不接受时,出现以下错误:
The method userCommand1(Map<String, String>) in the type ProgramCommands is not applicable for the arguments ()
但是,当我将参数传递给该方法时,它指出无法将其解析为变量。
编辑:详述:
当 userCommand1()
方法不带参数时:
public void userCommand1 () {
// Do some stuff
}
它工作得很好。但是,如果该方法确实采用输入参数,我不确定如何使用 lambda 表达式:
public void userCommand1 (Map<String, String> myMap) {
// Do some stuff
}
这是你的想法吗?
interface Command<T> {
public void run(T arg);
}
class SayHelloCommand implements Command<String>{
public void run(String name){
System.out.println("hello " + name);
}
}
class CountCommand implements Command<Integer>{
public void run(Integer limit){
for(int i=0; i<=limit; i++)
System.out.println(i);
}
}
public class Main{
public static void main(String[] args) {
Command[] commands = new Command[3];
commands[0] = new SayHelloCommand();
commands[1] = new CountCommand();
commands[0].run("Joe");
commands[1].run(5);
}
}
您只需要选择另一个功能界面(不是Runnable
)。
例如,如果您的方法都采用 String
参数,则您应该使用 Consumer<String>
. If they take a String
and an int
, then you should use BiConsumer<String, Integer>
. If your methods need more than 2 parameters, you need to create your own functional interface. For an example, see my answer
// use a list instead of an array, because arrays don't work well with generic types
public final List<Consumer<String>> userCommandMethods = List.of(
x -> userCommand1(x),
x -> userCommand2() // it's fine if the method takes fewer parameters
);
而不是 run
,你会调用 accept
,这就是 Consumer
和 BiConsumer
的单一抽象方法的调用。
请注意,您还可以使用方法引用语法。如果 userCommand1
是静态的,x -> userCommand1(x)
可以重写为 SomeClass::userCommand1
,其中 SomeClass
是 userCommand1
的封闭 class。如果 userCommand1
是非静态的,可以改写为 this::userCommand1
.
您不需要从两个数组构建地图。您可以使用 ofEntries
and entry
内联写入条目。
private final Map<String, Consumer<String>> someMap = Map.ofEntries(
Map.entry("foo", SomeClass::userCommand1),
Map.entry("bar", SomeClass::userCommand2),
Map.entry("baz", SomeClass::userCommand3),
// and so on
)
您正在使用不接受输入参数的 Runnable 接口:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
相反,您可以定义自定义界面并使用它。
举个简单的例子:
@FunctionalInterface
public interface RunnableWithArg {
void apply(String t) throws RuntimeException;
}
实现可能如下所示:
public class RunnableTest {
//also fine:
//public final RunnableWithArg[] userCommandMethods = { t -> this.userCommand1(t), t -> this.userCommand2(t) };
public final RunnableWithArg[] userCommandMethods = { this::userCommand1, this::userCommand2 };
public String commandKey1 = "commandKey1";
public String commandKey2 = "commandKey2";
public final String[] userCommandKeys = { commandKey1, commandKey2, };
public Map<String, RunnableWithArg> mapArrays(String[] array1, RunnableWithArg[] array2) {
Map<String, RunnableWithArg> mappedArrays = new HashMap<>();
for (int i = 0; i < array1.length; i++) {
mappedArrays.put(array1[i], array2[i]);
}
return mappedArrays;
}
public void userCommand1(String data) {
System.out.println("userCommand1 called with " + data);
}
public void userCommand2(String data) {
System.out.println("userCommand2 called with " + data);
}
public void test()
{
var fncMap = mapArrays(userCommandKeys, userCommandMethods);
for(String key: fncMap.keySet())
{
var fnc = fncMap.get(key);
fnc.apply(key);
}
}
}
当然你也可以像这样定义一些通用类型的“@FunctionalInterface”,这样你就可以用它来获取输入和返回一些通用类型的输出:
@FunctionalInterface
public interface AbcFunction<T, R> {
R apply(T t) throws AbcException;
static <T> Function<T, T> identity() {
return t -> t;
}
}