我在java-7中有一个for语句,它的工作正常:
Character cha = new Character(',');
String ncourseIds = null;
String pastCourseIds = null;
for (EquivalentCourse equivalentCourse : equivalentCourses) {
if(equivalentCourse.getNcourse() != null){
ncourseIds += equivalentCourse.getNcourse().getId()+ ",";
} else if(equivalentCourse.getPastCourse() != null) {
pastCourseIds +=equivalentCourse.getPastCourse().getId()+",";
}
}
if(!ncourseIds.isEmpty() &&cha.equals(ncourseIds.charAt(ncourseIds.length()-1))) {
ncourseIds = ncourseIds.substring(0, ncourseIds.length()-1);
}
if(!pastCourseIds.isEmpty()&& cha.equals(pastCourseIds.charAt(pastCourseIds.length()-1))) {
pastCourseIds = pastCourseIds.substring(0,pastCourseIds.length()-1);
}
现在我想将我的代码转换为Stream
& java-8中的collect
,我实现了一半关于过滤器的业务,而不是Ncourse
:
equivalentCourses.stream().filter(obj -> obj.getNcourse() != null )
.map(obj -> obj.getNcourse().getId()).collect(Collectors.joining(","));
但我不知道要实现它else-statement
。有什么帮助吗?
答案 0 :(得分:4)
由于流调用链很复杂,需要两个流 - 避免条件分支。
String ncourseIds = equivalentCourses.stream()
.filter(equivalentCourse -> equivalentCourse.getNcourse() != null)
.map(EquivalentCourse::getNcourse)
.map(x -> String.valueOf(x.getId()))
.collect(Collectors.joining(", "));
String pastCourseIds = equivalentCourses.stream()
.filter(equivalentCourse -> equivalentCourse.getNcourse() == null
&& equivalentCourse.getPastCourse() != null)
.map(EquivalentCourse::getPastCourse)
.map(x -> String.valueOf(x.getId()))
.collect(Collectors.joining(", "));
这也是专注于生成两个字符串的代码,具有高效的连接。
顺便说一句,如果这是一个SQL字符串,您可以使用带有Array的PreparedStatement。
@Holger评论的点缀:
String ncourseIds = equivalentCourses.stream()
.map(EquivalentCourse::getNcourse)
.filter(Objects::nonNull)
.map(NCourse::getId)
.map(String::valueOf)
.collect(Collectors.joining(", "));
String pastCourseIds = equivalentCourses.stream()
.filter(equivalentCourse -> equivalentCourse.getNcourse() == null)
.map(EquivalentCourse::getPastCourse)
.filter(Objects::nonNull)
.map(EquivalentCourse::getPastCourse)
.map(PastCourse::getId)
.map(String::valueOf)
.collect(Collectors.joining(", "));
答案 1 :(得分:1)
您可以按条件进行分组,然后重新映射:
public void booleanGrouping() throws Exception {
List<String> strings = new ArrayList<>();
strings.add("ala");
strings.add("ela");
strings.add("jan");
strings.stream()
.collect(
Collectors.groupingBy(s -> s.endsWith("a")) // using function Obj -> Bool not predicate
).entrySet()
.stream()
.collect(
Collectors.toMap(
e -> e.getKey() ? "Present" : "Past",
e -> e.getValue().stream().collect(Collectors.joining(""))
)
);
}
首先按条件分组,你应该使用equivalentCourse.getNcourse() != null
第二个重映射集合,从值到字符串。你可以介绍一下:
enum PresentPast{
Present, Past
PresentPast is(boolean v){
return v ? Present : Past
}
}
并将e -> e.getKey() ? "Present" : "Past"
更改为基于枚举的解决方案。
编辑:
else if
的解决方案:
public Map<Classifier, String> booleanGrouping() throws Exception {
List<String> strings = new ArrayList<>();
strings.add("ala");
strings.add("ela");
strings.add("jan");
// our ifs:
/*
if(!string.endsWith("n")){
}else if(string.startsWith("e")){}
final map should contains two elements
endsWithN -> ["jan"]
startsWithE -> ["ela"]
NOT_MATCH -> ["ala"]
*/
return strings.stream()
.collect(
Collectors.groupingBy(Classifier::apply) // using function Obj -> Bool not predicate
).entrySet()
.stream()
.collect(
Collectors.toMap(
e -> e.getKey(),
e -> e.getValue().stream().collect(Collectors.joining(""))
)
);
}
enum Classifier implements Predicate<String> {
ENDS_WITH_N {
@Override
public boolean test(String s) {
return s.endsWith("n");
}
},
STARTS_WITH_E {
@Override
public boolean test(String s) {
return s.startsWith("e");
}
}, NOT_MATCH {
@Override
public boolean test(String s) {
return false;
}
};
public static Classifier apply(String s) {
return Arrays.stream(Classifier.values())
.filter(c -> c.test(s))
.findFirst().orElse(NOT_MATCH);
}
}
答案 2 :(得分:0)
<强>更新强>
要添加替代方案,以下是使用两个filter()
操作执行代码的代码。请注意,这会影响第二次迭代整个集合,如果这是一个大集合,可能会对性能产生影响。
我还继续简化了关于字符串连接的一些逻辑。如果我错过了任何东西,请纠正我。
final List<String> courseIdList = new ArrayList<>();
final List<String> pastCourseIdList = new ArrayList<>();
equivalentCourses.stream().filter((current) -> current.getNcourse() != null)
.forEach((current) -> courseIdList.add(current.getNcourse().getId()));
equivalentCourses.stream().filter((current) -> current.getNcourse() != null && current.getPastCourse() != null)
.forEach((current) -> pastCourseIdList.add(current.getPastCourse().getId()));
String ncourseIds = String.join(",", courseIdList);
String pastCourseIds = String.join(",", pastCourseIdList);
原始回答
对于您的用例,使用forEach()
lambda最有意义。这将是最简单的翻译方式。
java.lang.Character cha = new java.lang.Character(',');
final StringBuilder ncourseIdBuilder = new StringBuilder();
final StringBuilder pastCourseIdBuilder = new StringBuilder();
equivalentCourses.stream().forEach((equivalentCourse) -> {
if (equivalentCourse.getNcourse() != null) {
ncourseIdBuilder.append(equivalentCourse.getNcourse().getId()).append(",");
} else if (equivalentCourse.getPastCourse() != null) {
pastCourseIdBuilder.append(equivalentCourse.getPastCourse().getId()).append(",");
}
});
String ncourseIds = ncourseIdBuilder.toString();
String pastCourseIds = pastCourseIdBuilder.toString();
if (!ncourseIds.isEmpty() && cha.equals(ncourseIds.charAt(ncourseIds.length() - 1))) {
ncourseIds = ncourseIds.substring(0, ncourseIds.length() - 1);
}
if (!pastCourseIds.isEmpty() && cha.equals(pastCourseIds.charAt(pastCourseIds.length() - 1))) {
pastCourseIds = pastCourseIds.substring(0, pastCourseIds.length() - 1);
}
您可以使用filter()
表达式重写代码,但它需要在条件语句中更大程度地重新处理逻辑,如果不是这样,则会引入您可能会破坏某些内容的风险测试得很好。逻辑上的变化正是@Holger和@Ole V.V.在对原始问题的评论中提及。
无论您使用forEach()
还是过滤器,lambdas都无法访问表达式中的非最终变量,因此我将final StringBuilder
变量添加到循环范围之外。