title: Making Bloch's builder pattern thread-safe: Rechecking necessary in enclosing constructor if NEVER invalid?
body: <p>I have recently learned <a href="http://www.informit.com/articles/article.aspx?p=1216151&amp;seqNum=2" rel="noreferrer" title="Joshua Bloch's builder pattern">Joshua Bloch's builder pattern</a> for creating objects with many optional fields. I've been using something like it for years, but never used an inner-class until Bloch's book suggested it to me. I love it.</p>
  
  <p>I understand that another thread may alter the bulider's configuration, before it's actually built (with <code>build()</code>), such that it may be necessary to re-validate all values in the constructor of the enclosing class. Below is an example of a builder class that optionally reverifies its data.</p>
  
  <p>So my question is this: Assuming this is a robust enough design, when there are defaults for all values--knowing this class is a poor choice for using defaults--and when every set-attempt is validated, is this re-check necessary? Although it may be <em>different</em>, it would never be <em>invalid</em>. Is that correct?</p>
  
  <p>(Although this design is manageable, it is certainly complicated by the potential need for re-verification. And, honestly, I never multi-thread, but I don't want to make my library unusable by people that do.)</p>
  
  <p>Thank you for any advice.</p>
  
  <pre><code>/**
     &lt;P&gt;&lt;CODE&gt;java ReverifyBuilderInEnclosingCnstrXmpl&lt;/CODE&gt;&lt;/P&gt;
   **/
  public class ReverifyBuilderInEnclosingCnstrXmpl  {
     public static final void main(String[] igno_red)  {
  
        //Don't reverify
        ReverifyBuilderInEnclosingCnstrXmpl rvbdx = new ReverifyBuilderInEnclosingCnstrXmpl.Cfg().
           name("Big Bird").age(6).build();
  
        System.out.println(rvbdx.sName);
        System.out.println(rvbdx.iAge);
  
        //Do reverify
        rvbdx = new ReverifyBuilderInEnclosingCnstrXmpl.Cfg().
           reverifyInEnclosing().
           name("Big Bird").age(6).build();
     }
  
     public final String sName;
     public final int    iAge;
     /**
        &lt;P&gt;Create a new &lt;CODE&gt;ReverifyBuilderInEnclosingCnstrXmpl&lt;/CODE&gt; with defaults.&lt;/P&gt;
     **/
     public ReverifyBuilderInEnclosingCnstrXmpl()  {
        //Does not reverify. No need.
        this(new ReverifyBuilderInEnclosingCnstrXmpl.Cfg());
     }
     private ReverifyBuilderInEnclosingCnstrXmpl(ReverifyBuilderInEnclosingCnstrXmpl.Cfg rbdx_c)  {
        sName = rbdx_c.sName;
        iAge = rbdx_c.iAge;
        ReverifyBuilderInEnclosingCnstrXmpl.Cfg.zcibValues(rbdx_c, sName, iAge, "constructor");
     }
     public static class Cfg  {
        private String  sName   = null;
        private int     iAge    = -1;
        private boolean bReVrfy = false;
        public Cfg()  {
           //Defaults
           bReVrfy = false;
           name("Broom Hilda");
           age(127);
        }
        //Self-returning configuration...START
           //No way to unset.
           public Cfg reverifyInEnclosing()  {
              bReVrfy = true;
              return  this;
           }
           public Cfg name(String s_name)  {
              zcib_name(s_name, "name");
              sName = s_name;
              return  this;
           }
           public Cfg age(int i_age)  {
              zcib_age(i_age, "age");
              iAge = i_age;
              return  this;
           }
        //Self-returning configuration...END
        //Validate config...START
           public static final void zcibValues(ReverifyBuilderInEnclosingCnstrXmpl.Cfg rbdx_c, String s_name, int i_age, String s_clgFunc)  {
              try  {
                 if(!rbdx_c.bReVrfy)  {
                    return;
                 }
              }  catch(NullPointerException npx)  {
                 throw  new NullPointerException("zcibValues: rbdx_c");
              }
              zcib_name(s_name, s_clgFunc);
              zcib_age(i_age, s_clgFunc);
           }
           public static final void zcib_name(String s_name, String s_clgFunc)  {
              if(s_name == null  ||  s_name.length() == 0)  {
                 throw  new IllegalArgumentException(s_clgFunc + ": s_name (" + s_name + ") is null or empty.");
              }
           }
           public static final void zcib_age(int i_age, String s_clgFunc)  {
              if(i_age &lt; 0)  {
                 throw  new IllegalArgumentException(s_clgFunc + ": i_age (" + i_age + ") is negative.");
              }
           }
        //Validate config...END
        public ReverifyBuilderInEnclosingCnstrXmpl build()  {
           return  (new ReverifyBuilderInEnclosingCnstrXmpl(this));
        }
     }
  }
  </code></pre>