If you wanna create new list, use Stream.map method:

List<Fruit> newList = fruits.stream()
    .map(f -> new Fruit(f.getId(), f.getName() + "s", f.getCountry()))
    .collect(Collectors.toList())

If you wanna modify current list, use Collection.forEach:

fruits.forEach(f -> f.setName(f.getName() + "s"))
Answer from Sergii Lagutin on Stack Overflow
🌐
Medium
medium.com › @javabydhruvkumar › how-to-update-newly-objects-in-list-from-another-list-based-on-condition-using-streams-7d9241d2c0a0
How to update newly Objects in List from another List based on condition Using Streams | by Dhruv kumar | Medium
December 8, 2022 - package org.dt; import java.util.Arrays; import java.util.List; public class Test { public static void main(String[] args) throws Exception{ List<User> users= Arrays.asList(new User("dhruv","agra"),new User("Ankit","agra")); List<User> users1= Arrays.asList(new User("dhruv","hyd"),new User("Ankit","hyd")); //User user=new User("dhruv","agra"); users.forEach(user -> users1.stream() .filter(u-> u.getName().equals(user.getName())) .findFirst().ifPresent(u-> user.setAdd(u.getAdd()))); System.out.println(users); } } Now you folks can see that here i have used java 8 features to update the one list from the another list.
🌐
Baeldung
baeldung.com › home › java › java streams › modifying objects within stream while iterating
Modifying Objects Within Stream While Iterating | Baeldung
June 27, 2025 - The Java Stream API provides various methods that allow modifications of the stream elements. However, the actions inside these methods have to be non-interfering and stateless.
🌐
How to do in Java
howtodoinjava.com › home › java streams › java – remove/update elements from list using stream
Java - Remove/Update Elements From List using Stream
September 20, 2022 - [ Employee [id=1, name=Alex, ... all elements or the matching elements from the Stream, we use the Stream.map() method and return a new Employee instance....
🌐
Baeldung
baeldung.com › home › java › java streams › modify and print list items with java streams
Modify and Print List Items With Java Streams | Baeldung
March 7, 2025 - Consequently, the stream object becomes inaccessible after this method is called. This limitation implies that subsequent stream operations, such as collecting the transformed elements, are no longer feasible. Therefore, we’d like to achieve our goal through a different approach, one that allows us to continue performing operations on the stream. A straightforward idea is to include the printing method call in map(): List<String> theList = List.of("Kai", "Liam", "Eric", "Kevin"); List<String> newList = theList.stream() .map(element -> { String newElement = element.toUpperCase(); log.info(newElement); return newElement; }) .collect(Collectors.toList()); assertEquals(List.of("KAI", "LIAM", "ERIC", "KEVIN"), newList);
Top answer
1 of 10
119

Yes, you can modify state of objects inside your stream, but most often you should avoid modifying state of source of stream. From non-interference section of stream package documentation we can read that:

For most data sources, preventing interference means ensuring that the data source is not modified at all during the execution of the stream pipeline. The notable exception to this are streams whose sources are concurrent collections, which are specifically designed to handle concurrent modification. Concurrent stream sources are those whose Spliterator reports the CONCURRENT characteristic.

So this is OK

  List<User> users = getUsers();
  users.stream().forEach(u -> u.setProperty(value));
//                       ^    ^^^^^^^^^^^^^
//                        \__/

but this in most cases is not

  users.stream().forEach(u -> users.remove(u));
//^^^^^                       ^^^^^^^^^^^^
//     \_____________________/

and may throw ConcurrentModificationException or even other unexpected exceptions like NPE:

List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());

list.stream()
    .filter(i -> i > 5)
    .forEach(i -> list.remove(i));  //throws NullPointerException
2 of 10
5

The functional way would imho be:

import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class PredicateTestRun {

    public static void main(String[] args) {

        List<String> lines = Arrays.asList("a", "b", "c");
        System.out.println(lines); // [a, b, c]
        Predicate<? super String> predicate = value -> "b".equals(value);
        lines = lines.stream().filter(predicate.negate()).collect(toList());

        System.out.println(lines); // [a, c]
    }
}

In this solution the original list is not modified, but should contain your expected result in a new list that is accessible under the same variable as the old one

🌐
Java Code Geeks
javacodegeeks.com › home › core java
Modifying and Printing List Items Using Java Streams - Java Code Geeks
April 16, 2024 - Interested in Java list operations? Then check out our detailed article on how to update and print elements in a list using Java Stream.
Top answer
1 of 5
20

When you create a Stream from the List, you are not allowed to modify the source List from the Stream as specified in the “Non-interference” section of the package documentation. Not obeying this constraint can result in a ConcurrentModificationException or, even worse, a corrupted data structure without getting an exception.

The only solution to directly manipulate the list using a Java Stream, is to create a Stream not iterating over the list itself, i.e. a stream iterating over the indices like

IntStream.range(0, list1.size()).forEach(ix -> list1.set(ix, list1.get(ix)+1));

like in Eran’s answer

But it’s not necessary to use a Stream here. The goal can be achieved as simple as

list1.replaceAll(i -> i + 1);

This is a new List method introduced in Java 8, also allowing to smoothly use a lambda expression. Besides that, there are also the probably well-known Iterable.forEach, the nice Collection.removeIf, and the in-place List.sort method, to name other new Collection operations not involving the Stream API. Also, the Map interface got several new methods worth knowing.

See also “New and Enhanced APIs That Take Advantage of Lambda Expressions and Streams in Java SE 8” from the official documentation.

2 of 5
3

Holger's answer is just about perfect. However, if you're concerned with integer overflow, then you can use another utility method that was released in Java 8: Math#incrementExact. This will throw an ArithmeticException if the result overflows an int. A method reference can be used for this as well, as seen below:

list1.replaceAll(Math::incrementExact);
Find elsewhere
Top answer
1 of 2
3

You should not use Stream APIs to change the state of an Object.

If you still want to modify it then, You can iterate each element from the list of A, filter if dob is null, find dob against the respective name in the list of B.

List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

aList.stream()
        .filter( a  -> a.dob == null)
        .forEach( a -> {
            Predicate<B> nameFilter = b -> b.name.equals(a.name);
            a.dob = findDob(nameFilter, bList);
        });

static String findDob(Predicate<B> nameFilter, List<B> bList) {
    B b = bList.stream()
            .filter(nameFilter)
            .findFirst()
            .orElse(new B());

    return b.dob;
}

Alternate efficient solution: Considering you have a unique name for each object B, you can prepare lookup and find age using that map, this way you do not need to iterate bList for every iteration of aList

List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

Map<String, String> nameDobLookup = bList.stream()
                        .collect(Collectors.toMap(b -> b.name, b -> b.dob));

aList.stream()
        .filter(a -> a.dob == null)
        .forEach(a -> a.dob = nameDobLookup.get(a.name));
2 of 2
1

I'd suggest modifying the list of A objects in a forEach loop:

// define: List<A> aList =

// define: List<B> bList =


aList.forEach(aListElement -> {
            // find the first B object with matching name:
            Optional<B> matchingBElem = bList.stream()
                    .filter(bElem -> Objects.equals(aListElement.getName(), bElem.getName()))
                    .findFirst();

            // and use it to set the dob value in this A list element:
            if (matchingBElem.isPresent()) {
                aListElement.setDob(matchingBElem.get().getDob());
            }

        }
);
Top answer
1 of 3
1

Feature Envy

The LoanAccountService needs to know all fields from LoanAccount that gets updated:

account.get().setCreationDate(loanAccount.getCreationDate());
account.get().setLoanAmount(loanAccount.getLoanAmount());
account.get().setNumberOfInstallments(loanAccount.getNumberOfInstallments());
account.get().setType(loanAccount.getType());

Now imagine LoanAccount would get a few more fields and they are updateable too but you forgot to change LoanAccountService.. This means LoanAccountService depends on LoanAccount..

A solution would be to add a new method to LoanAccount:

public LoanAccount updateBy(LoanAccount other) {
  this.creationDate = other.creationDate();
  this.loanAmount = other.loanAmount();
  this.numberOfInstallments = other.numberOfInstallments();
  this.type = other.type();
  return this;
}

Optional#map

The if-statement

if (account.isPresent()) {

can be replaced by the method map on Optional. With adding the new updateBy method:

public LoanAccount updateBy(LoanAccount other) {
  bank.getLoanAccounts()
      .stream()
      .filter(la -> la.getId().equals(other.getId()))
      .findAny()
      .map(loanAccount -> loanAccount.updateBy(other))
      .orElseThrow(() -> new IllegalArgumentException("The object does not exist."));
  return other;
}

Further Improvement

A second Feature Envy is in the following snipped:

bank.getLoanAccounts()
   .stream()
   .filter(la -> la.getId().equals(loanAccount.getId()))

Not the LoanAccountService should filter the data but the Bank itself should filter it:

// in Bank.java

public Optinal<List<LoanAccount> findBy(int id) {
   return loanAccounts.stream()
                      .filter(la -> la.getId().equals(id))
                      .collect(Collectors.toList())
}

All together

// LoanAccountService.java

public LoanAccount updateBy(LoanAccount other) {
  bank.findBy(other.getId())
      .findAny()
      .map(loanAccount -> loanAccount.updateBy(other))
      .orElseThrow(() -> new IllegalArgumentException("The object does not exist."));
  return other;
}
2 of 3
1

I would suggest following:

  1. Place operations to the objects that contain data for this operation. It will improve encapsulation and allow more flexible code reuse. Also it will be easy to test such implementation because of small methods.
  2. Use more convenient structure. In this case Map<String, LoanAccount> (map id to loanAccount) instead of List<LoanAccount>

As you can see in this case service contains only required logic (how to react on loan absence). It is easy to read, test and understand.

LoanAccountService.java

public class LoanAccountService{

    private Bank bank;

    public LoanAccountService(Bank bank) {
        this.bank = bank;
    }

    public LoanAccount update(LoanAccount loanAccount) {
        if (!bank.updateLoanAccount(loanAccount)) {
            throw new IllegalArgumentException("The object does not exist.");
        }
        return loanAccount;
    }
}

Bank.java

@Getter
@Setter
public class Bank {
    private Map<String, LoanAccount> loanAccounts;

    public boolean updateLoanAccount(LoanAccount loanAccount) {
        LoanAccount loan = loanAccounts.get(loanAccount.getId());
        if (loan != null) {
            loan.update(loanAccount);
            return true;
        }
        return false;
    }
}

LoanAccount.java

@Getter
@Setter
public class LoanAccount {
    private String id;
    private Integer numberOfInstallments;
    private LoanAccountType type;
    private Date creationDate;
    private BigDecimal loanAmount;

    public void update(LoanAccount loanAccount) {
        this.setCreationDate(loanAccount.getCreationDate());
        this.setLoanAmount(loanAccount.getLoanAmount());
        this.setNumberOfInstallments(loanAccount.getNumberOfInstallments());
        this.setType(loanAccount.getType());
    }
}

If you can't use this approach, you could made a small refactoring of the service (less code and "if conditions" are good things):

public LoanAccount update(LoanAccount loanAccount) {
    LoanAccount account = bank.getLoanAccounts()
            .stream()
            .filter(la -> la.getId().equals(loanAccount.getId()))
            .findAny()
            .orElseThrow(() ->  new IllegalArgumentException("The object does not exist."));
    account.setCreationDate(loanAccount.getCreationDate());
    account.setLoanAmount(loanAccount.getLoanAmount());
    account.setNumberOfInstallments(loanAccount.getNumberOfInstallments());
    account.setType(loanAccount.getType());
    return account;
}

Also I think you should return updated loan account.

🌐
Stack Overflow
stackoverflow.com › questions › 62913653 › update-content-of-list-based-of-another-id-list-by-stream
java - Update content of list based of another id list by Stream - Stack Overflow
I'm trying to update the content of objects in the list of A if that object's id found in the list of B. This is my code and all thing works like a charm: listA: list of messages, for example with a length of 100 listB: string list of some messages Id which read by the user, for example with a length of 5 · Stream.of(messageList).filter(message-> { Optional<String> first = Stream.of(readMessageIdList) .filter(readMessageId-> readMessageId.equalsIgnoreCase(message.getId())) .findFirst(); first.ifPresent(readMessageId-> message.setRead(true)); return true;// return true intentionally, because I want don't filter my original messageList }).toList();
🌐
Answers
answers.com › computer-science › How-can-i-update-an-object-in-a-list-using-java-stream-based-on-a-specific-condition
How can I update an object in a list using Java Stream based on a specific condition? - Answers
February 7, 2025 - To update an object in a list based on a specific condition using Java Stream, you can use the map function to update the object if the condition is met, and then collect the stream back into a list.
🌐
Stack Overflow
stackoverflow.com › questions › 67609984 › update-properties-of-elements-in-a-list-to-values-in-another-list-using-only-str
java - Update properties of elements in a list to values in another list using only stream() - Stack Overflow
List<Deposit> deposits = new ArrayList<>(); Deposit deposit = new Deposit("deposito 1"); Deposit deposit2 = new Deposit("deposito 2"); Deposit deposit3 = new Deposit("deposito 3"); deposits.add(deposit); deposits.add(deposit2); deposits.add(deposit3); List<String> status = Arrays.asList("DepositStatus.CANCELED", "DepositStatus.ERROR", "DepositStatus.DONE"); Arrays.stream(st).distinct().forEach(s -> { for(int i = 0; i < deposits.size(); i++){ deposits.get(i).setStatus(st[i]); } }); System.out.println(deposits);
🌐
Mediterraneafrutta
qnwe.mediterraneafrutta.it › java-stream-update-object-in-list-based-on-condition.html
Java stream update object in list based on condition
Stream.forEach() util; Java Example: You need JDK 13 to run below program as point-5 above uses stream() util. void java.util.stream.Stream.forEach(Consumer<? super String> action) p erforms an action for each element of this stream. Technology. WinRT is implemented in the programming language C++ and is object-oriented by design.
Top answer
1 of 3
1
  1. Use Builder for getter and setter

    public class LoanAccount {
        private String id;
        private Integer numberOfInstallments;
    
    // add other properties
    
    public String getId() {
        return id;
    }
    
    public LoanAccount setId(String id) {
        this.id = id;
        return this;
    }
    
    public Integer getNumberOfInstallments() {
        return numberOfInstallments;
    }
    
    public LoanAccount setNumberOfInstallments(Integer numberOfInstallments) {
        this.numberOfInstallments = numberOfInstallments;
        return this;
    }
    
  2. Use this one for update method

    public LoanAccount update(LoanAccount loanAccount) {
        return bank.getLoanAccounts()
                .stream()
                .filter(la -> la.getId().equals(loanAccount.getId()))
                .findFirst().orElseThrow(IllegalArgumentException::new)
                .setCreationDate(loanAccount.getCreationDate())
                .setLoanAmount(loanAccount.getLoanAmount())
                .setNumberOfInstallments(loanAccount.getNumberOfInstallments())
                .setType(loanAccount.getType());
    }
    
2 of 3
0

You could use a HashMap where the TKey is the type of your LoanAccount.id. Then call loanAccounts.put(id, object) This will update the object if there is already an Id and add a new object if not.

This is a cheap, dirty way. Another way of doing it would be to make your LoanAccount class implement Comparable and in the compareTo() method make a id based comparation. Do the same thing overriding your equals() and you should be ready to go.

@Override
public boolean equals(object obj) {
    if (obj == null) return false;

    return ((LoanAccount)obj).getId() == this.getId();
}

something like that. (code wrote by memory, can have errors and lacks validations like the data type)