Обновите набор <Person>, если Person существует, или добавьте его, если его нет - PullRequest
0 голосов
/ 24 октября 2018

Допустим, у меня есть очень простой класс Person, который содержит имя и адрес:

public class Person {
    String name;
    String address;

    public Person(final String name,
                  final String address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(final String newName) {
        this.name = newName;
    }

    public String address() {
        return address;
    }

    public void setAddress(final String newAddress) {
        this.address = newAddress;
    }
}

Теперь у меня есть Set, содержащий все известные объекты Person, и я хочу обновить адресодного из лиц на основании только их имени.Для этого у меня есть следующее:

persons.stream()
       .filter(person -> personToUpdate.getName().equalsIgnoreCase(person.getName()))
       .forEach(person -> {
                person.setAddress(personToUpdate.getAddress());
        });

Однако моя проблема в том, что у меня вообще есть новый человек, которого нет в Сете.Как проверить комплект, чтобы узнать, существует ли этот человек, и если да, обновить его адрес.Но если они не существуют, добавьте их в список.Я знаю, что это просто, но по какой-то причине я просто не могу думать, как добиться этого прямо сейчас.Я не хочу идти по пути создания списка всех имен, сравнения нового имени, если они есть в списке и т. Д. И т. Д. И т. Д. Я бы предпочел сделать его максимально сжатым.

РЕДАКТИРОВАТЬ: имена будут уникальными!

Ответы [ 5 ]

0 голосов
/ 24 октября 2018

Вы можете использовать лиц.содержит (человек).Однако вам придется переопределить методы hashcode () и equals ()

0 голосов
/ 24 октября 2018

Вы можете сделать это, используя Map.

Map<String, Person> personMap = persons.stream()
    .collect(Collectors.toMap(Person::getName, Function.identity()));
personMap.merge(personToUpdate.getName(), personToUpdate, 
    (p1, p2) -> new Person(p1.getName(), p2.address()));
0 голосов
/ 24 октября 2018

Предполагая, что (1) ваши Person объекты предназначены для сравнения только с использованием ссылочного равенства (и, следовательно, идентичность объекта должна быть сохранена), и (2) несколько Person объектов могут соответствовать данному имени, выВам нужно будет обработать эти случаи вручную:

public static void updatePersonAddress(String name, String address, Set<Person> persons) {
    // Find all the matching persons, if any.
    List<Person> matched = new ArrayList<>();
    for (Person person : persons) {
        if (person.getName().equalsIgnoreCase(name)) {
            matched.append(person);
        }
    }

    // If zero persons matched, create a new Person to match,
    // and add the new person to the set. Then we're done!
    if (matched.isEmpty()) {
        persons.add(new Person(name, address));
        return;
    }

    // Otherwise, update the Person objects (which are still in the
    // persons Set) to include the new address.
    for (Person person : matched) {
        person.setAddress(address);
    }
}

Если имена уникальны, это упрощается до:

public static void updatePersonAddress(String name, String address, Set<Person> persons) {
    for (Person person : persons) {
        if (person.getName().equalsIgnoreCase(name)) {
            person.setAddress(address);
            // If we've found one that matches, then we know there
            // won't be any more, so we can be done now.
            return;
        }
    }
    // If we made it through the loop without returning, then it means
    // that no Person in the Set matched. So add one that does.
    persons.add(new Person(name, address));
}
0 голосов
/ 24 октября 2018

Если вам не нужен однострочник, вы можете просто воспользоваться Optional s:

Optional<Person> person = persons.stream()
        .filter(p -> personToUpdate.getName().equalsIgnoreCase(p.getName()))
        .findFirst();

if (person.isPresent()) {
    person.get().setAddress(personToUpdate.getAddress());
} else {
    persons.add(personToUpdate);
}

Если вы используете Java 9+, это может выглядеть еще лучше:

persons.stream()
        .filter(p -> personToUpdate.getName().equalsIgnoreCase(p.getName()))
        .findFirst()
        .ifPresentOrElse(
            p -> p.setAddress(personToUpdate.getAddress()),
            () -> persons.add(personToUpdate)
        );

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

0 голосов
/ 24 октября 2018

Есть несколько простых способов сделать это (я предполагаю, что имя однозначно идентифицирует Person, и два объекта Person с одинаковым именем считаются равными)

  1. Реализация equals иhashcode и выполните contains вызов перед вашим потоком - если он возвращает false, он не входит в набор
  2. Используйте Map вместо Set, где ключ может быть легко использованискать человека по атрибуту (например, по имени, которое, по-видимому, является вашим основным ключом).

Примечание: вы должны в любом случае реализовать equals и hashcode - особенно если выположить эти объекты в Set или Map.Реализуя equals и hashcode только для учета имени, вы гарантируете уникальность имени в наборе (сейчас это не гарантируется)

...