Как создать список карт из списка объектов в Java без использования метода getKey? - PullRequest
3 голосов
/ 18 июня 2019

Как создать список карт, где каждое имя ключа выводится из имени атрибута класса, а значение должно быть указано методом получения

У меня следующий класс в java

class DTA {
  private String id;
  private String age;

  @Override
  public String toString() {
    return "DTA{" +
            "id='" + id + '\'' +
            ", age='" + age + '\'' +
            '}';
  }

  public DTA(String id, String age) {
    this.id = id;
    this.age = age;
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getAge() {
    return age;
  }

  public void setAge(String age) {
    this.age = age;
  }
}

У меня есть список объектов типа DTA

List<DTA> listA = new ArrayList<>();
listA.add(new DTA("A", "15"));
listA.add(new DTA("B", "25"));

Я хочу создать упорядоченный список карт (что-то вроде scala) со следующим содержанием.

List<? extends Map<String, String>>

List(Map("id"->"A", "age"->"15"), Map("id"->"B", "age"->"25"))

Ответы [ 2 ]

3 голосов
/ 18 июня 2019

По сути, инструмент, используемый для «просмотра» содержимого классов в Java, называется отражением . Например, если ваш объект является POJO (Plain Old Java Object), вы можете перебрать все поля в классе следующим образом:

DTA obj; // some object, I assume it's initialized
Field[] fields = DTA.class.getDeclaredFields();
Map<String, Object> valuesMap = new HashMap<>();
for (field : fields) {
    boolean wasAccessible = field.isAccessible(); // check if class has access control disabled
    field.setAccessible(true); // disable access control (private/protected) to extract value    
    valuesMap.put(field.getName(), field.get(obj));
    field.setAccessible(wasAccessible); // return flag to initial value   
}

Тем не менее, доступ к значениям с помощью рефлексии, как известно, ненормальный. Если у вас нет веских причин сделать это самостоятельно, попробуйте использовать среду, которая автоматизирует подобные задачи, а не писать код с нуля.

Кроме того, отражение медленно . Доступ к Field объектам, подобным этому, для каждого отдельного объекта является неоптимальным, если вы когда-нибудь захотите действительно написать подобный код, вы должны кэшировать Field объекты в Map<String, Field> и выполнять только переопределение setAccessible и Field поиск один раз для каждой коллекции DTA объектов.

3 голосов
/ 18 июня 2019

Без «динамики» прямолинейная вещь может выглядеть так:

List<Map<String, String>> x = listA
            .stream()
            .map(this::toMap)
            .collect(Collectors.toList());

с локальным помощником, таким как:

private Map<String, String> toMap(DTA dta) {
    Map<String, String> rv = new HashMap<>();
    rv.put("id", dta.getId());
    rv.put("age", dta.getAge());
    return rv;
}

Чтобы быть полностью динамическим здесь, вам нужно будет использовать отражение для запроса имен полей. Вы можете найти примеры, как это сделать здесь .

Но я настоятельно рекомендую не сделать это: рефлексия всегда должна быть вашим последним средством. Понятие DTA предполагает, что в любом случае у вас есть данные объекта, поступающие из некоторого «сервиса». Если так, то зачем сначала сериализовать в определенный класс DTA, чтобы затем «сплющить» эту информацию в какую-то общую структуру Map?!

Значение: когда этот сервис предоставляет вам объекты, которые сериализуются как, скажем, JSON или XML ... тогда было бы намного лучше просто использовать библиотеку, такую ​​как gson или jackson, чтобы напрямую десериализовать эти данные в такие общие "плоские" объекты на основе карты. Например, Джексон имеет класс JsonNode . Когда вы десериализуете в такие объекты, вы получаете это отображение имен полей бесплатно! Смотрите здесь больше примеров кода.

Дело в том, что идентификация полей с помощью отражения возможна. Но отражение код всегда утомителен и подвержен ошибкам. Если возможно, избегайте делать это самостоятельно.

...