0

I am trying to understand a issue I found on mutation and references in Java.

I am trying to point the reference of my list of messages to a new sublist of messages created by the function getMessageSublist.

I would expect that after the updateMessage, my list of messages would contain only one message(0), which was selected by the getMessageSublist.

What I am doing wrong? How could I modify my code so that my code only print the message(0) (selected by the getMessageSublist), considering that my getMessageSublist always provide me a new list with copies of the messages.

class Message {
    private String message;

    public Message(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    public Message getCopy() {
        return new Message(getMessage());
    }

    @Override
    public String toString() {
        return "Message{" + "message='" + message + '\'' + '}';
    }
}

public class Test {
    public static void main(String[] args){
        List<Message> messages = new ArrayList<>();
        for (int i=0;i<5;i++){
            messages.add(new Message(Integer.valueOf(i).toString()));
        }
        updateMessages(messages);
        for(Message msg: messages){
            System.out.println(msg);//Actual: Prints 0 till 5, Expected print
            // only 0, (selected in getMessageSublist).
        }
    }

    private static void updateMessages(List<Message> messages) {
        List<Message> sublistMessages=getMessageSublist(messages);
        messages=sublistMessages;//Unsuccessfully tried to set the
        // sublistMessages as my messages
    }

    private static List<Message> getMessageSublist(List<Message> messages) {
        List<Message> sublist=new ArrayList<>();
        sublist.add(messages.get(0).getCopy());
        return sublist;
    }
}
khelwood
  • 55,782
  • 14
  • 81
  • 108
DTK
  • 95
  • 1
  • 9
  • 2
    Each of your methods has a *local variable* called `messages`. Even though they all call their variables the same name, they are *different* variables and exist *only* in the scope of their respective methods. Re-assigning a local variable only re-assigns that local variable, it does nothing to a variable in the calling method by the same name. If you want to modify the object referenced by that variable, you need to mutate the object itself (call methods or set values on it), not re-assign the variable to a new object. – David Nov 04 '21 at 14:02
  • @OHGODSPIDERS Thanks! Great resource, but I guess that in the resource shared the solution would be messages=sublistMessages that did not solve my issue. – DTK Nov 04 '21 at 14:10
  • 1
    No, that is not correct. And nowhere does it claim that. The linked duplicate explains that because java is always pass-by-value reassigning method parameters will **never** have an effect outside of those methods. The solution is to work with return values instead and use those return values to reassign your variables at the places where you call those methods. – OH GOD SPIDERS Nov 04 '21 at 14:12
  • Thanks @David you pointed a thing I had not thought of. Would you say that in this case, my option would be to return a List from updateMessages? I would need to update my interface, but I guess that this would be a best practice right in this context right? – DTK Nov 04 '21 at 14:13
  • 1
    @DTK: In general I personally recommend returning a new object instead of mutating a passed object, yes. There are exceptions of course. But overall I find it unintuitive for a method to mutate an object passed to it and can lead to bugs. Returning the same type passed in can also make for very expressive fluent interfaces. – David Nov 04 '21 at 14:15
  • Thanks @OHGODSPIDERS I see, now it is cristal clear! Indeed that is the root cause of my issue. – DTK Nov 04 '21 at 14:16
  • @David Many Thanks! Now that you mentioned I cannot agree more! – DTK Nov 04 '21 at 14:19

0 Answers0