有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

枚举构造函数中的java非静态方法引用作为参数

我试图将一些值映射到应该应用于这些值的函数。 如果简化,我想这样做:

import java.util.function.Supplier;

public enum SomeEnum {
    CASE1 ("val1", this::doAction1),
    CASE2 ("val2", this::doAction1),
    CASE3 ("val3", this::doAction2),
    CASE4 ("val4", this::doAction2);

    String value;
    Supplier<String> action;

    SomeEnum(String value, Supplier<String> action) {
        this.value = value;
        this.action = action;
    }

    private String doAction1() {
        return this.value + "-> action1";
    }

    private String doAction2() {
        return this.value + "-> action2";
    }
}

它无法编译,因为无法从静态上下文引用SomeEnum.this。 我做不到doAction1&doAction2静态,因为我需要来自实例的值

以下是基于if-else/switch的解决方案:

import java.util.function.Supplier;

public enum SomeEnum {
    CASE1 ("val1", SomeEnum.ACTION1),
    CASE2 ("val2", SomeEnum.ACTION1),
    CASE3 ("val3", SomeEnum.ACTION2),
    CASE4 ("val4", SomeEnum.ACTION2);

    final static boolean ACTION1 = true;
    final static boolean ACTION2 = false;

    String value;
    Supplier<String> action;

    SomeEnum(String value, boolean flag) {
        this.value = value;
        this.action = flag ? this::doAction1 : this::doAction2;
    }

    private String doAction1() {
        return this.value + "-> action1";
    }

    private String doAction2() {
        return this.value + "-> action2";
    }
}

此外,我有两个以上的方法,我需要额外的枚举,而不是布尔标志和构造函数中的开关块来映射到函数。 创建此枚举是为了避免在我的遗留世界中出现疯狂的开关块。 如果它再次出现在构造器中,我将一无所获

我的主要问题是: 如果可以在构造函数中使用非静态方法引用,为什么不能将其作为参数传递? 你能解释一下为什么这是不允许的吗

enum SomeEnum {
    CASE1 (this::doAction);
    Supplier<String> action;
    SomeEnum(Supplier<String> action) {
        this.action = action;
    }
private String doAction() {
            return "action";
        }
}

什么时候可以

enum SomeEnum {
    CASE1;
    Supplier<String> action;
    SomeEnum() {
        this.action = this::doAction;
    }
    private String doAction() {
        return "action";
    }
}

我找到的唯一解决方案是:

import java.util.function.Supplier;

public enum SomeEnum {
    CASE1 ("val1", () -> SomeEnum.doAction1("val1")),
    CASE2 ("val2", () -> SomeEnum.doAction1("val2")),
    CASE3 ("val3", () -> SomeEnum.doAction2("val3")),
    CASE4 ("val4", () -> SomeEnum.doAction2("val4"));

    String value;
    Supplier<String> action;

    SomeEnum(String value, Supplier<String> action) {
        this.value = value;
        this.action = action;
    }

    private static String doAction1(String value) {
        return value + "-> action1";
    }

    private static String doAction2(String value) {
        return value + "-> action2";
    }
}

你能评估一下它是否好吗。如果不是,为什么呢


共 (2) 个答案

  1. # 1 楼答案

    还有一个提示,我喜欢你的问题

    如果enum的所有元素都有相同的供应商逻辑,那么您更愿意只实现一次供应商的功能,而不是抽象声明

    为什么不试试

    public enum SomeEnum {
    CASE1("val1"),
    CASE2("val2");
    
    private String value;
    
    private SomeEnum(String value) {
        this.value = value;
    }
    
    public Supplier<String> doAction() {
        return () -> {
            // Do here anything you need to do...
            return value;
        };
    }
    

    }

  2. # 2 楼答案

    你在试图实施一些在我看来根本错误的事情。你知道你可以在枚举中使用抽象方法,并为每个常量提供它们的实现吗

    enum的接口很清楚:一个String doAction()方法,本质上就是作为字段的Supplier<String>

    不管怎样,你都会用一个getter来提供这个字段,那么为什么不提供一个方法呢

    enum SomeEnum {
        CASE1("val1") {
            @Override
            public String doAction() {
                return this.value + "-> action1";
            }
        },
        CASE2("val2") {
            @Override
            public String doAction() {
                return this.value + "-> action2";
            }
        };
    
        String value;
    
        SomeEnum(String value) {
            this.value = value;
        }
    
        public abstract String doAction();
    }