使用 Java8 流 api 避免长代码行的最简洁方法
Cleanest way to avoid long code lines with Java8 stream api
我应该如何重构这样的行?
return chars.codePoints().mapToObj(cp->((!Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(cp))) && (! Character.isISOControl(cp)))?"'"+String.valueOf(Character.toChars(cp))+"'":"0x"+Integer.toHexString(cp)).collect(Collectors.joining(","));
我应该
- 将流重新分配给局部变量,使其只是 "more vertical",但将 lambda 保留在使用它的地方
创建类似 private String codePointToString(int cp) {...}
的方法将 lambda 缩短为 cp->codePointToString(cp)
创建函数常量而不是方法:
private static final IntFunction<String> codePointToString = cp->{...};
并像 mapToObj(codePointToString)
一样使用它
?
我确实会提取一个方法 codePointToString()
,这将使代码更易于阅读和单元测试。我也会每行一步:
return chars.codePoints()
.mapToObj(this::codePointToString)
.collect(Collectors.joining(","));
为了使提取的方法的代码可读,我还将 space 放在运算符周围,并使用 if
而不是三元运算符
private String codePointToString(int codePoint) {
if (!Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(cp))
&& !Character.isISOControl(cp)) {
return "'" + String.valueOf(Character.toChars(cp)) + "'";
}
else {
return "0x" + Integer.toHexString(cp);
}
}
我要做的第一件事是通过反转条件并删除过时的括号来清理条件。正如你所写的那样,我真的很难理解它,但幸运的是,我的 IDE 让我自动理解它。于是就变成了
return chars.codePoints().mapToObj(cp->
Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(cp))
|| Character.isISOControl(cp)?
"0x"+Integer.toHexString(cp):
"'"+String.valueOf(Character.toChars(cp))+"'")
.collect(Collectors.joining(","));
可读性更高。
关于其他选项,没有通用的规则。您可以将条件或整个转换方法放入以其目的命名的方法中,因为这将对 reader 有更大帮助,并在表达式中引用它,例如
mapToObj(cp->printableCodePoint(cp)?
"0x"+Integer.toHexString(cp): "'"+String.valueOf(Character.toChars(cp))+"'")
或通过 lambda 表达式/方法参考,例如
mapToObj(cp->codePointToString(cp)) or mapToObj(MyClass::codePointToString)
我不建议像第三个项目符号那样将函数存储到变量中。您可以通过 lambda 表达式轻松地从普通方法创建函数,但您不能那么轻松地从函数创建普通方法。在我看来,强制代码通过 codePointToStringFunction.apply(cp);
而不是不涉及任何功能操作的普通 codePointToString(cp);
调用方法看起来像是糟糕的编码风格。因此,在普通方法中保留可重用代码会提高其通用性。
我应该如何重构这样的行?
return chars.codePoints().mapToObj(cp->((!Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(cp))) && (! Character.isISOControl(cp)))?"'"+String.valueOf(Character.toChars(cp))+"'":"0x"+Integer.toHexString(cp)).collect(Collectors.joining(","));
我应该
- 将流重新分配给局部变量,使其只是 "more vertical",但将 lambda 保留在使用它的地方
创建类似
private String codePointToString(int cp) {...}
的方法将 lambda 缩短为cp->codePointToString(cp)
创建函数常量而不是方法:
private static final IntFunction<String> codePointToString = cp->{...};
并像mapToObj(codePointToString)
一样使用它
?
我确实会提取一个方法 codePointToString()
,这将使代码更易于阅读和单元测试。我也会每行一步:
return chars.codePoints()
.mapToObj(this::codePointToString)
.collect(Collectors.joining(","));
为了使提取的方法的代码可读,我还将 space 放在运算符周围,并使用 if
而不是三元运算符
private String codePointToString(int codePoint) {
if (!Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(cp))
&& !Character.isISOControl(cp)) {
return "'" + String.valueOf(Character.toChars(cp)) + "'";
}
else {
return "0x" + Integer.toHexString(cp);
}
}
我要做的第一件事是通过反转条件并删除过时的括号来清理条件。正如你所写的那样,我真的很难理解它,但幸运的是,我的 IDE 让我自动理解它。于是就变成了
return chars.codePoints().mapToObj(cp->
Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(cp))
|| Character.isISOControl(cp)?
"0x"+Integer.toHexString(cp):
"'"+String.valueOf(Character.toChars(cp))+"'")
.collect(Collectors.joining(","));
可读性更高。
关于其他选项,没有通用的规则。您可以将条件或整个转换方法放入以其目的命名的方法中,因为这将对 reader 有更大帮助,并在表达式中引用它,例如
mapToObj(cp->printableCodePoint(cp)?
"0x"+Integer.toHexString(cp): "'"+String.valueOf(Character.toChars(cp))+"'")
或通过 lambda 表达式/方法参考,例如
mapToObj(cp->codePointToString(cp)) or mapToObj(MyClass::codePointToString)
我不建议像第三个项目符号那样将函数存储到变量中。您可以通过 lambda 表达式轻松地从普通方法创建函数,但您不能那么轻松地从函数创建普通方法。在我看来,强制代码通过 codePointToStringFunction.apply(cp);
而不是不涉及任何功能操作的普通 codePointToString(cp);
调用方法看起来像是糟糕的编码风格。因此,在普通方法中保留可重用代码会提高其通用性。