用一行代表消费者和行动

时间:2015-06-23 06:15:15

标签: java lambda java-8 consumer

试验我的代码我想知道是否有任何方法可以“压缩”它(单线是最终目标)。

vanilla 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);
    }
}

“压缩”:

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) { }

当然这对我来说只是科学上的兴趣,但有没有办法写出更小的代码?

4 个答案:

答案 0 :(得分:4)

由于您发现实际上没有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

答案 1 :(得分:3)

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

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) {...}
}

答案 2 :(得分:1)

鉴于您的初始设计,我想您想要为 Person 枚举所有可能的设置器。此外,它接收就好像你要收集 Field 来设置和,然后调用正确的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);
    }
}

答案 3 :(得分:0)

以下是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