如何解决Java 9将具有可为空字段的对象列表处理为另一个列表
我有一个像
这样的对象列表@Getter
@Setter
public class Person {
private String name;
private boolean value_bool;
private String value_string;
private Integer value_integer;
private String value_text;
}
问题是,这些字段中只有一个(名称除外)实际上是为一个 Person 启动的(例如非空),其他每个字段都是空的,因此对于这些值中的 4 个,有 4 个 Person 实例,每个实例都有一个名称和值之一。如何将此 Person 对象列表转换为值对象列表,最好使用 streamAPI?
解决方法
boolean value_bool
不能是 null
。
要合并此数据,首先您需要按 name
分组,然后将 List<Person>
(代表具有相同名称的单独 Person 对象)折叠为单个合并的 Person .
分组:
Map<String,List<Person>> grouped = persons.stream()
.collect(Collectors.groupingBy(Person::getName));
将 List<Person>
合并为单个 Person 不是特别适合基于流的代码。我只想做一个方法,它有点复杂,因为你有很多不明显的选择要做。例如,假设您有 2 个 value_bool
为假,而 1 个 true
。并且 2 Person 对象都有一个非空的 value_string
,并且它们不是同一个字符串;哪一个获胜,还是应该抛出异常,还是应该将字符串连接起来?
此类问题存在且没有明显答案这一事实应强烈表明没有简单的单行代码可以做到这一点。
因此,类似于:
public class Person {
// ....
public static Person merge(@NonNull Collection<? extends Person> persons) {
if (persons.isEmpty()) throw new IllegalArgumentException(
"Cannot merge an empty list of persons");
if (persons.size() == 1) return persons.iterator().next();
Person out = null;
for (Person person : persons) {
if (out == null) {
out = person;
continue;
}
// If any part-person is 'valueBool',the output is also.
if (person.isValueBool()) out.setValueBool(true);
// For the rest,the 'last' non-null value 'wins':
if (person.getValueString() != null) out.setValueString(person.getValueString());
// etc
}
return out;
}
}
采用这种方法:
persons.stream()
.collect(Collectors.groupingBy(Person::getName))
.values()
.stream()
.map(Person::merge)
.collect(Collectors.toList());
如果您有 JDK16,最后一行可以是 toList();
。