Java List removing items without any action

Viewed 38

I'm facing a weird behavior in my Java code using List.

The code is very simple, I have a List of Object called AccessRequest which comes from a database and I'm using this first List to create a new one but with a filter to select only a few objects.

Here is the code :

private void updateCommentIfNeeded() {
    List<AccessRequest> accessRequestList = getAllRequest();
    List<AccessRequest> commentsList = getCommentsListProcessedManually(accessRequestList);
}

public List<AccessRequest> getCommentsListProcessedManually(List<AccessRequest> accessRequests) {

    accessRequests.removeIf(ar -> !ar.getComment().equals("To be processed manually"));

    if (accessRequests.size() != 0) {
        SQLServerConnection sqlServerConnection = new SQLServerConnection(sqlServerUrl);
        accessRequests.removeIf(ar -> !sqlServerConnection.emailExists(ar.getEmail()));
    }
    return accessRequests;
}

I'm supposed to get a second List only containing the objects that has their comments to To be processed manually, which I do. But the weird part is that the first List also takes the value of the second as if I wrote accessRequestList = commentsList but there is no such thing and I'm using local variable.

Ex :

  • I have 3 objects in my first List, but only one containing the required comment
  • Both list ends with containing the only objects containing the comment

I'm kind of lost here if anyone has an idea !

2 Answers

Your method getCommentsListProcessedManually modifies the list you're passing. I believe you're operating under the assumption that passing the list as a parameter somehow creates a copy of the list, whereas what is actually happening is that a reference to the list is passed by value.

There are several ways to solve this, but the easiest is to simply create a copy of your input list at the start of your method:

public List<AccessRequest> getCommentsListProcessedManually(List<AccessRequest> input) {
    List<AccessRequest> accessRequests = new ArrayList<>(input);

    accessRequests.removeIf(ar -> !ar.getComment().equals("To be processed manually"));

    if (accessRequests.size() != 0) {
        SQLServerConnection sqlServerConnection = new SQLServerConnection(sqlServerUrl);
        accessRequests.removeIf(ar -> !sqlServerConnection.emailExists(ar.getEmail()));
    }
    return accessRequests;
}

You could also use the Stream API for this (using the filter operation), but that's quite a bit trickier in this situation.

You are passing a reference of the list to the method getCommentsListProcessedManually.

So accessRequestList and the one passed as a parameter are the same, hence any operation done to the list is done to the same list.

You can create a copy of the list before passing it as a parameter:

List<AccessRequest> newList = new ArrayList<AccessRequest>(accessRequestList);
Related