按给定顺序从pojo填充列表

时间:2017-08-27 13:30:39

标签: java oop design-patterns java-8

我有一个POJO对象,字段很少,字符串列表。我们必须使用pojo的字段值创建一个对象列表,其顺序与字符串列表的顺序完全相同。现在我在使用pojo getters调用list.add时循环使用String -

列表
public class ResultSet {
    private String field1;
    private String field2;
    private String field3;
    private String field4;


    public List<Object> populateResultList(List<String> list) {
        List<Object> resultSet = new ArrayList<>();
        for (String filedName : list) {
            if ("Field1".equalsIgnoreCase(filedName)) {
                resultSet.add(getField1());
            } else if ("Field2".equalsIgnoreCase(filedName)) {
                resultSet.add(getField2());
            } else if ("Field3".equalsIgnoreCase(filedName)) {
                resultSet.add(getField3());
            } else if ("Field4".equalsIgnoreCase(filedName)) {
                resultSet.add(getField4());
            }
        }
        return resultSet;
    }


    public String getField1() {
        return field1;
    }

    public String getField2() {
        return field2;
    }

    public String getField3() {
        return field3;
    }

    public String getField4() {
        return field4;
    }
}

有没有更好的方法来实现它作为很多样板代码。

3 个答案:

答案 0 :(得分:4)

您可以使用普通Java 8 Stream API执行此操作。您可以在fieldName字符串和Function<ResultSet, Object>之间定义返回与fieldName关联的值的映射。使用函数具有以下优势:您可以将其简化为method reference,如ResultSet::getField1等效于以下lambda表达式:

Function<ResultSet, Object> f = resultSet -> resultSet.getField1();

通过这种方式,您可以像这样定义映射映射:

private static final Map<String, Function<ResultSet, Object>> mappings = new HashMap<String, Function<ResultSet, Object>>() {{
    put("field1", ResultSet::getField1);
    put("field2", ResultSet::getField2);
    put("field3", ResultSet::getField3);
    put("field4", ResultSet::getField4);
}};

然后您的populateResultList方法可能如下所示:

public List<Object> populateResultList(List<String> list) {
    return list.stream()
            .map(fieldName -> mappings.getOrDefault(fieldName.toLowerCase(), it -> null).apply(this))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
}

这里发生的事情是输入fieldName中的每个List<String>我们采用mappings地图中定义的映射器,或者如果给定{的映射器,我们会返回it -> null的映射器{1}}未定义。调用fieldName会过滤掉结果列表中的所有空元素。

演示

在这里你可以找到 Demo

.filter(Objects::nonNull)

我希望它有所帮助。

答案 1 :(得分:1)

您可以使用java库vavr并将代码缩减为:

public List<String> populateResultList(List<String> list) {
    return list.stream()
            .map(v -> Match(v).of(
                    Case($("Field1"), getField1()),
                    Case($("Field2"), getField2()),
                    Case($("Field3"), getField3()),
                    Case($("Field4"), getField4())))
            .collect(toList());
}

您可以将Match表达式视为返回结果的Switch语句。返回的结果就是我们将列表的值映射到。

答案 2 :(得分:1)

如果您不介意一点反思技巧,并且不想将字段名称硬编码为方法参考,则以下方法有效,如果您向ResultSet添加更多字段,则可以更加维护未来。

public class Main {
    private static Map<String, Method> getterMap;

    static {
        try {
            getterMap = Arrays.stream(Introspector.getBeanInfo(ResultSet.class).getPropertyDescriptors())
                    .filter(pd -> pd.getReadMethod() != null && !"class".equals(pd.getName()))
                    .collect(Collectors.toMap(pd -> pd.getName().toLowerCase(), PropertyDescriptor::getReadMethod));
        } catch (IntrospectionException e) {
            getterMap = Collections.emptyMap();
        }
    }

    public static void main(String[] args) {
        ResultSet resultSet = new ResultSet("lorem", "ipsum", "dolor", "sit amet");
        List<String> list = Arrays.asList("field1", "Field4", "Field3", "Field2", "field9");

        List<String> list1 = list.stream()
                .map(String::toLowerCase)
                .filter(getterMap::containsKey)
                .map(getterMap::get)
                .map(getter -> invokeGetter(getter, resultSet))
                .collect(Collectors.toList());

        System.out.println(list1);
    }

    private static String invokeGetter(Method getter, ResultSet rs) {
        try {
            return getter.invoke(rs).toString();
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }
}