Java - Modify object's internal data, or create new object with modified data

Jake Lawrence :

The Question

In Java, according to standard code style and design principles, when is it more appropriate to modify an object's internal data, and when is it more appropriate to create a new object using the modified data?

For example, let's say I have some class, Vector2D, which holds an x component and a y component, and I want to rotate that vector:

Approach A

public class Vector2D{
    private int x;
    private int y;
    public Vector2D(int x, int y){
        this.x = x;
        this.y = y;
    }
    public void rotate(double angle){
        //code for finding rotated vector
        x = rotated_x;
        y = rotated_y;
    }
}

A Vector2D object could then be rotated with vector1.rotate(angle)

Approach B

public class Vector2D{
    private final int x;
    private final int y;
    public Vector2D(int x, int y){
        this.x = x;
        this.y = y;
    }
    public Vector2D rotate(double angle){
        //code for finding rotated vector
        Vector2D rotated = new Vector2D(rotated_x, rotated_y);
        return(rotated);
    }
}

A Vector2D object could then be rotated with vector1 = vector1.rotate(angle)

Findings so far

My research into the issue so far has led me to believe that approach B is useful for allowing method chaining, e.g. vector1 = vector1.rotate(angle).scale(scalar), which has it's own benefits, more on the readability side of things.

It has also led me to realise that approach B allows you to make an object immutable, so I suppose by extension my question is also:

When is it appropriate to make an object immutable, especially in this example case? (and in general, for Points, Vectors, Polygons, etc. Should all these types be immutable?)

Edit:

The project I had in mind while creating this post is a game, in which entities are represented by Polygons, and are manipulated using vectors.

I believe that because of intended application, making sure the classes are thread-safe should not be an issue, as Vector and Polygon data should only ever be altered by the logic thread anyway.

This also means that these operations could potentially be being done 60 times per second (every game tick), for every single entity. Does this mean that any overheads from instantiating new objects each time could quickly add up?

Enno Shioji :

In general, you should prefer making objects immutable. Reasons you might want to opt for mutable objects are:

  1. The objects have a lot of state and are thus expensive to create. E.g. imagine a massive matrix. If you don't allow mutation you'll have to duplicate the matrix every time, which could be prohibitively expensive (see pandas for example - it offers both options).
  2. Making it immutable makes the API very unintuitive. This also depends a bit on the history of the language. For example, most sorting libraries in e.g. Java mutate the collection rather than returning a copy. If you are going to implement shuffle,it might be better to mutate the list even if you are not worried about (1), just because it would be surprising if you return a copy.

Some languages and libraries came up with a third way, in which mutation returns a new "version" of an object while sharing the previous state (see this). This solves (1), thereby allowing you to benefit from immutability without the cost of copying a lot. Some argue this means you should practically always opt for immutability because with (1) gone, there is no longer any reason to opt for mutability other than familiarity. In reality, some algorithms are very hard to express without mutable states (e.g. see this). so we'll probably continue to have mutable states.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=73902&siteId=1