[java] Is it bad practice to make a setter return “this”?


12 Answers

It's not bad practice. It's an increasingly common practice. Most languages don't require you to deal with the returned object if you don't want to so it doesn't change "normal" setter usage syntax but allows you to chain setters together.

This is commonly called a builder pattern or a fluent interface.

It's also common in the Java API:

String s = new StringBuilder().append("testing ").append(1)
  .append(" 2 ").append(3).toString();
Question

Is it a good or bad idea to make setters in java return "this"?

public Employee setName(String name){
   this.name = name;
   return this;
}

This pattern can be useful because then you can chain setters like this:

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

instead of this:

Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);

...but it sort of goes against standard convention. I suppose it might be worthwhile just because it can make that setter do something else useful. I've seen this pattern used some places (e.g. JMock, JPA), but it seems uncommon, and only generally used for very well defined APIs where this pattern is used everywhere.

Update:

What I've described is obviously valid, but what I am really looking for is some thoughts on whether this is generally acceptable, and if there are any pitfalls or related best practices. I know about the Builder pattern but it is a little more involved then what I am describing - as Josh Bloch describes it there is an associated static Builder class for object creation.




Paulo Abrantes offers another way to make JavaBean setters fluent: define an inner builder class for each JavaBean. If you're using tools that get flummoxed by setters that return values, Paulo's pattern could help.




I don't know Java but I've done this in C++. Other people have said it makes the lines really long and really hard to read, but I've done it like this lots of times:

list.add(new Employee()
    .setName("Jack Sparrow")
    .setId(1)
    .setFoo("bacon!"));

This is even better:

list.add(
    new Employee("Jack Sparrow")
    .Id(1)
    .foo("bacon!"));

at least, I think. But you're welcome to downvote me and call me an awful programmer if you wish. And I don't know if you're allowed to even do this in Java.




Because it doesn't return void, it's no longer a valid JavaBean property setter. That might matter if you're one of the seven people in the world using visual "Bean Builder" tools, or one of the 17 using JSP-bean-setProperty elements.




This scheme (pun intended), called a 'fluent interface', is becoming quite popular now. It's acceptable, but it's not really my cup of tea.




Bad habit: a setter set a getter get

what about explicitly declaring a method, that does it for U

setPropertyFromParams(array $hashParamList) { ... }



I have been making my setters for quite a while and the only real issue is with libraries that stick with the strict getPropertyDescriptors to get the bean reader/writer bean accessors. In those cases, your java "bean" will not have the writters that you would expect.

For example, I have not tested it for sure, but I would not be surprised that Jackson won't recognizes those as setters when creating you java objects from json/maps. I hope I am wrong on this one (I will test it soon).

In fact, I am developing a lightweight SQL centric ORM and I have to add some code beyong getPropertyDescriptors to recognized setters that returns this.




I prefer using 'with' methods for this:

public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
public Employee withFoo(String foo) {
  setFoo(foo);
  return this;
}

Thus:

list.add(new Employee().withName("Jack Sparrow")
                       .withId(1)
                       .withFoo("bacon!"));



It is better to use other language constructs if available. For example, in Kotlin, you would use with, apply, or let. If using this approach, you won't really need to return an instance from your setter.

This approach allows your client code to be:

  • Indifferent to the return type
  • Easier to maintain
  • Avoid compiler side effects

Here are some examples.

val employee = Employee().apply {
   name = "Jack Sparrow"
   id = 1
   foo = "bacon"
}


val employee = Employee()
with(employee) {
   name = "Jack Sparrow"
   id = 1
   foo = "bacon"
}


val employee = Employee()
employee.let {
   it.name = "Jack Sparrow"
   it.id = 1
   it.foo = "bacon"
}



I'm in favor of setters having "this" returns. I don't care if it's not beans compliant. To me, if it's okay to have the "=" expression/statement, then setters that return values is fine.




Yes, I think it's a good Idea.

If I could add something, what about this problem :

class People
{
    private String name;
    public People setName(String name)
    {
        this.name = name;
        return this;
    }
}

class Friend extends People
{
    private String nickName;
    public Friend setNickName(String nickName)
    {
        this.nickName = nickName;
        return this;
    }
}

This will work :

new Friend().setNickName("Bart").setName("Barthelemy");

This will not be accepted by Eclipse ! :

new Friend().setName("Barthelemy").setNickName("Bart");

This is because setName() returns a People and not a Friend, and there is no PeoplesetNickName.

How could we write setters to return SELF class instead of the name of the class ?

Something like this would be fine (if the SELF keyword would exist). Does this exist anyway ?

class People
{
    private String name;
    public SELF setName(String name)
    {
        this.name = name;
        return this;
    }
}



This particular pattern is called Method Chaining. Wikipedia link, this has more explanation and examples of how it's done in various programming languages.

P.S: Just thought of leaving it here, since I was looking for the specific name.




From the statement

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

i am seeing two things

1) Meaningless statement. 2) Lack of readability.




Related