在一行中声明消费者和操作

Declare Consumer and action with it in one line

试验我的代码我想知道有什么方法可以 "compress" 它更多(单行是最终目标)。

原版 java:

public void setUsingSwitch(Field field, String value) {
    switch (field) {
        case FIRST_NAME:
            setFirstName(value);
            break;
        case LAST_NAME:
            setLastName(value);
            break;
        default:
            throw new IndexOutOfBoundsException("Unknow field " + field);
    }
}

"compressed":

public void setUsingConsumer(Field field, String value) {
    Consumer<String> setter = field == FIRST_NAME ? this::setFirstName : field == LAST_NAME ? this::setLastName : v -> {
        throw new IndexOutOfBoundsException("Unknow field " + field);
    };
    setter.accept(value);
}

两者都用过:

public static enum Field { FIRST_NAME, LAST_NAME }

void setFirstName(String value) { }

void setLastName(String value) { }

当然这对我来说只是科学兴趣,但是有什么方法可以编写更小的代码吗?

这是一种替代方法,它并不短,但有时更可取:

import java.util.function.BiConsumer;

public class MyObj {
    public static enum Field {
        FIRST_NAME(MyObj::setFirstName),
        LAST_NAME(MyObj::setLastName);

        Field(BiConsumer<MyObj, String> setter) {
            this.setter = setter;
        }

        final BiConsumer<MyObj, String> setter;
    }

    public void set(Field field, String value) {
        field.setter.accept(this, value);
    }

    public void setFirstName(String s) {...}
    public void setLastName(String s) {...}
}

既然你透露你实际上没有enum,一个更通用的解决方案可能是这样的:

class Person {
    public void setFirstName(String value) {
        // …
    }
    public void setLastName(String value) {
        // …
    }
    static final Map<String,BiConsumer<Person,String>> FIELDS;
    static {
        Map<String,BiConsumer<Person,String>> m=new HashMap<>();
        m.put("FirstName", Person::setFirstName);
        m.put("LastName", Person::setLastName);
        FIELDS=Collections.unmodifiableMap(m);
    }
    public void setField(String field, String value) {
        FIELDS.getOrDefault(field, (k,v)->{ throw new NoSuchElementException(); })
              .accept(this, value);
    }
}

顺便说一句,既然你说的是“业务逻辑”,我建议阅读以下内容:“Falsehoods Programmers Believe About Names

鉴于您的初始设计,我猜您想为 枚举所有可能的 setter。此外,它看起来好像您想收集要设置的 Fieldvalue,然后调用适当的 setter。这是我保留您的设计目标的解决方案:

public enum Field {

    FIRST_NAME {
        public void setValue(String value, Person person) {
            person.setFirstName(value);
        }},

    LAST_NAME {
        public void setValue(String value, Person person) {
            person.setLastName(value);
        }};

    public abstract void setValue(String value, Person person);
}

public class Person {

    private String firstName;
    private String lastName;

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void clearUsingConsumer(Field field, String value) {
        field.setValue(value, this);
    }
}

这是我最后的 Optional:

Field field = FIRST_NAME;

Optional.<Consumer<String>>ofNullable(
        field == FIRST_NAME
                ? this::setFirstName
                : field == LAST_NAME
                        ? this::setLastName
                        : null).orElseThrow(IndexOutOfBoundsException::new)
        .accept("John");

虽然我不确定写成一行是不是一件好事。甚至使用它来代替简单的 switch