在一行中声明消费者和操作
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。此外,它看起来好像您想收集要设置的 Field 和 value,然后调用适当的 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
。
试验我的代码我想知道有什么方法可以 "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。此外,它看起来好像您想收集要设置的 Field 和 value,然后调用适当的 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
。