我在Java 8中有一个列表,并且有一些过滤函数,如果列表中的项满足该函数的条件,则返回布尔结果。我想根据条件将列表拆分成几个列表。目前我的代码看起来像 -
public void classifyItems(List<SomeType> mylist) {
//declare and initialize list1, list2, list3
//these lists will store items as per filtering conditions
mylist.forEach(item -> {
if (filteringFunction1(item) {
list1.add(item);
}
else if (filteringFunction2(item) {
list2.add(item);
}
else if (filteringFunction3(item) {
list3.add(item)
}
});
//other operations on filtered lists
}
是否有更清晰/更好的方法在Java 8中使用流或其他构造编写上述逻辑?我对长期的if-else梯子不太满意。我需要单独的列表来满足不同条件的项目。
答案 0 :(得分:2)
接受谓词列表(或使用 varargs 方法)将允许可扩展的解决方案,如
public void classifyItems(List<SomeType> mylist, List<Predicate<SomeType>> filterFuncs) {
int ffSize = filterFuncs.size();
Map<Integer,List<SomeType>> classified = mylist.stream()
.collect(Collectors.groupingBy(item ->
IntStream.range(0, ffSize)
.filter(ix -> filterFuncs.get(ix).test(item))
.findFirst().orElse(ffSize)));
//other operations on filtered lists
}
地图键对应filterFuncs
列表中的谓词位置,因此classified.get(0)
会让您“list1
”,classified.get(1)
会让您“list2
” ,依此类推,classified.get(ffSize)
将为您提供与任何谓词不匹配的所有项目的列表。
它保留原始代码的逻辑,匹配列表中较早的谓词优先于后续谓词。
答案 1 :(得分:1)
您当前的代码实际上非常易读,而且我认为它可以改进很多,但您可以考虑使用groupingBy
收集器:
Map<String, List<SomeType>> grouped = mylist.stream().collect(
Collectors.groupingBy(it -> {
if (filteringFunction1(item))
return "CASE 1";
if (filteringFunction2(item))
return "CASE 2";
if (filteringFunction3(item))
return "CASE 3";
return "DEFAULT";
}));
这为您提供了Map
个List
个实例,其中关键是每个值被归类为的情况。
您的程序可能包含比包含案例名称的字符串更好的地图键的候选者,也许像OldCurmudgeon的回答中的enum
一样?
答案 2 :(得分:0)
为了便于使用,您可以使用带过滤器的基本流。这很容易理解,并且保持代码大小不变,但确实有三次迭代列表的缺点。
public void classifyItems(List<String> mylist) {
List<String> filter1 = mylist.stream().filter(i -> filteringFunction1(i)).collect(Collectors.toList());
List<String> filter2 = mylist.stream().filter(i -> filteringFunction2(i)).collect(Collectors.toList());
List<String> filter3 = mylist.stream().filter(i -> filteringFunction3(i)).collect(Collectors.toList());
}
答案 3 :(得分:0)
使用流时,您应该尝试在使用流和编码逻辑之间找到平衡点。我可能会这样做。
enum Types {
Type1(list1) {
@Override
boolean filter(SomeType it) {
return false;
}
},
Type2(list2) {
@Override
boolean filter(SomeType it) {
return true;
}
},
Type3(list3) {
@Override
boolean filter(SomeType it) {
return false;
}
};
final List<SomeType> theList;
Types(List<SomeType> theList) {
this.theList = theList;
}
List<SomeType> getList() {
return theList;
}
abstract boolean filter (SomeType it);
}
public void classifyItems(List<SomeType> mylist) {
mylist.stream().forEach(
// walk all types.
i -> Arrays.stream(Types.values())
// Choose only applicable types.
.filter(t -> t.filter(i))
// Add it to the list.
.forEach(t -> t.getList().add(i))
);
}
这会对SomeType
列表的属性进行编码,方法是提供filter
来检测此SomeType
是否适用以及与之相关的list
。
然后我只使用stream
来表达它的意图,使用每个元素来处理流和做事。