Does it follow java conventions to only provide a getter for collections? -


i encountered code following:

public list<item> getitems() {     if (items == null) {         items = new arraylist<item>();     }     return this.items; } 

and crucially, no setter method.

so if wanted add arraylist, have do

foo.getitems().add(...)   

rather

foo.setitems(myarraylist) 

i've not seen idiom before, , can't it, when generated mapping code using mapstruct.org (great tool way), mapstruct handles fine , correctly generates code uses getter setter well.

i'm wondering - common idiom i've somehow missed? seems pointless me, perhaps there wisdom behind i'm not seeing?

it common not recommended.

the problem isn't lazy initialisation (that part fine) exposure of should implementation detail. once expose actual, mutable(!) list object store in field, caller of code can list, things don't expect.

they example remove objects when want allow add(). modify different threads, making code break in interesting , frustrating ways. cast raw list , fill entirely different types of objects, making code throw classcastexceptions.

in other words, makes impossible enforce class invariants.

note there 2 things work cause problem:

  1. the exposure of object stored in field.
  2. and fact object mutable.

if of 2 aren't true, there's no problem. fine:

public string getfoo() {    return this.foo; } 

because string immutable. , fine too:

public list<string> getfoolist() {    return new arraylist<>( this.foolist ); } 

because you're returning defensive copy , not actual object. (however, if elements of lists mutable, you'd in trouble again.)


there more subtle variation problem...

imagine scenario:

public class foo {     private list<string> list;    public foo( list<string> list ) {      this.list = list; // don't    }    ... } 

this looks harmless, , see in many places. there hidden catch here too: not making copy before storing list, you're in same situation. can't stop doing this:

list<string> list = new arraylist<>(); list.add( "nice item" ); foo foo = new foo( list ); list.add( "hahahaha" ); list.add( "i've added more items list , don't know it." ); list.add( "i'm evil genius" ); 

so should making defensive copies both before assigning mutable object field , when returning it.


if it's dangerous expose mutable fields of class, why don't people make defensive copies time then?

apart not knowing why isn't idea, there 2 broad categories of excuses given.

  1. performance. making copy of object every time call getter expensive. of course true it's not expensive you'd think. , if find paying high cost defensive copies, there ways out: example designing classes immutable. if classes immutable, won't need defensive copies, ever.
  2. only call code , won't abuse it. promise. again valid depending on situation. if you're writing small standalone application on own, it's true won't abuse it. or if you're writing small library expose details of classes aren't part of public api. in other cases though can't sure somewhere won't abuse it. , when happens, code won't break bang. starts doing slightly...odd things occasionally. , that's worst kind of bug try find.

Comments

Popular posts from this blog

jquery - How do you format the date used in the popover widget title of FullCalendar? -

asp.net mvc - SSO between MVCForum and Umbraco7 -

Python Tkinter keyboard using bind -