We all know that objects in Java can be modified.
I want to present three options when working with an object and indicate their advantages and disadvantages.
public class SetterApplication {
public static void main(String[] args) {
User john = new User("John", 22);
increaseAge(john, 2);
System.out.println(john); // User{name='John', age=24}
User johnUpper = upperName(john);
System.out.println(johnUpper); // User{name='JOHN', age=24}
System.out.println(john); // User{name='JOHN', age=24}
User johnLower = lowerName(john);
System.out.println(johnLower); // User{name='john', age=24}
System.out.println(johnUpper); // User{name='JOHN', age=24}
}
/**
* Case #1
* change the object passed in and return nothing
* @param user user
* @param inc inc
*/
public static void increaseAge(User user, Integer inc) {
user.setAge(user.getAge() + inc);
}
/**
* Case #2
* change the passed object and return the changed object
* @param user user
* @return User
*/
public static User upperName(User user) {
user.setName(user.getName().toUpperCase());
return user;
}
/**
* Case #3
* do not change the passed object and return a completely new object
* @param user user
* @return User
*/
public static User lowerName(final User user) {
return new User(user.getName().toLowerCase(), user.getAge());
}
}
class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("User{");
sb.append("name='").append(name).append('\'');
sb.append(", age=").append(age);
sb.append('}');
return sb.toString();
}
}
"Case #1" - the most common way, but to contain the corresponding disadvantage, is that the existing object is modified. But this behavior is predictable, since we do not return anything.
"Case #2" - also often found in code. But this case is misleading - because it returns a modified transferred object, which can be misleading that we are returning a new object, but this is not true.
"Case #3" - this method is the most fashionable way. Where we do not modify the transferred object and return a new object. But in this method there is a huge disadvantage that in Java it is not easy to implement (deep) cloning and the second is that it can be very resource-intensive, the object can be very large.
My question is which of the three options is preferable? What do you prefer to use? And which of the options do you consider the worst?