如果Person存在,则更新Set <person>;如果不存在,则添加它们

时间:2018-10-24 16:55:12

标签: java set java-stream

假设我有一个非常简单的类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 :(得分:4)

除非您需要单线,否则您可以简单地利用Optional的优势:

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)
        );

这当然假定名称是唯一的(因为您希望更新一个条目)。

答案 1 :(得分:1)

您可以通过使用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()));

答案 2 :(得分:0)

有几种简单的方法可以做到这一点(我假设名称唯一地标识一个Person,并且两个具有相同名称的Person对象被视为相等)

  1. 实施equalshashcode,并在流之前进行contains调用-如果返回false,则不在集合中
  2. 使用Map代替Set,在这里可以轻松地通过属性(例如名称,在这里似乎是您的主键)使用该键来查找人。

旁注-无论如何都应实现equalshashcode-尤其是将这些对象放入SetMap中时。通过实现equalshashcode仅考虑名称,您将保证名称在集合中的唯一性(目前无法保证)

答案 3 :(得分:0)

假设(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));
}

答案 4 :(得分:0)

您可以使用person.contains(person)。但是,您将不得不重写hashcode()和equals()方法