Session 2502More Effective Programming With Java™ TechnologyJoshua BlochSenior Staff EngineerSun Microsystems, Java SoftwareSession 25022Presentation GoalLearn to use the Java™ programming language and its libraries more effectively.Session 25023View From 10,000 feet•This talk consists of–Patterns and idioms to emulate –Pitfalls to avoid•Excerpted from Effective Java™ Programming Language Guide–(Addison-Wesley, June 2001)Session 25024Speaker’s Qualifications•Author, Effective Java Programming Language Guide (Addison-Wesley, June 2001)•Architect –Java™ Collections Framework–java.math–java.util.prefs–the assert construct–Chained exceptions, StackTraceElement–ThreadLocal, Timer, etc.Session 25025Topics Covered in the Book•The language•Libraries: java.lang, java.util, (java.io)•Not covered:GUI Programming, Enterprise APIs•Ten chapters, fifty-seven itemsSession 25026Topics Covered in the Talk I. Duplicate Object Creation (Item 4) II. Defensive Copying (Item 24)III. Immutable Classes (Item 13)Session 25027I. Avoid Duplicate Object Creation•Reuse existing object instead•Simplest example String s = new String("DON’T DO THIS!"); String s = "Do this instead";•In loops, savings can be substantialSession 25028Another Examplepublic class Person { private final Date birthDate; // Other fields omitted public Person(Date birthDate){ this.birthDate = birthDate; } // UNNECESSARY OBJECT CREATION - DON'T DO THIS! public boolean isBabyBoomer(){ // Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); Date boomStart = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); Date boomEnd = gmtCal.getTime(); return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0; }}Session 25029Another Example (Cont.)// Do This Instead - Clearer and fasterprivate static final Date BOOM_START;private static final Date BOOM_END;static { Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); BOOM_START = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); BOOM_END = gmtCal.getTime();}public boolean isBabyBoomer(){ // ~100 times faster! return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;}Session 250210Summary•Don’t create unnecessary duplicate objects–Reuse improves clarity and performance•But don’t be afraid to create objects–Object creation is cheap on modern Vms–Can enhance simplicity, power, robustnessSession 250211II. Defensive Copying•Unlike C/C++, Java programming language safe–Immune to buffer overruns, wild pointers, etc.•Makes it possible to write robust classes–Correctness doesn’t depend on other modules–Even in safe language, requires effortSession 250212Defensive Programming•Assume clients will try to destroy invariants– May actually be true– More likely: honest mistakes•Ensure class invariants survive any inputsSession 250213This Class Is Not Robust!public final class Period { private final Date start, end; // Invariant: start <= end /** * @throws IllegalArgumentException if start > end * @throws NullPointerException if start or end is null */ public Period(Date start, Date end) { if (start.compareTo(end) > 0) throw new IllegalArgumentException(start + ">" + end); this.start = start; this.end = end; } public Date start() { return start; } public Date end() { return end; } ... // Remainder omitted}Session 250214The Problem: Date Is Mutable// Attack the internals of a Period instanceDate start = new Date(); // (The current time)Date end = new Date(); // " " "Period p = new Period(start, end);end.setYear(78); // Modifies internals of p!Session 250215The Solution: Defensive Copying// Repaired constructor - defensively copies parameterspublic Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date( end.getTime()); if (this.start.compareTo(this.end) > 0) throw new IllegalArgumentException(start + ">" + end);}Session 250216An Important Detail•Copies made before checking parameters•Validity check performed on copies•Eliminate window of vulnerability between parameter check and copy•Thwarts multithreaded attack// BROKEN - Permits multithreaded attack!public Period(Date start, Date end) {if (start.compareTo(end) > 0)throw new IllegalArgumentException(start + ">" + end);// Window of vulnerabilitythis.start = new Date(start.getTime());this.end = new Date( end.getTime());}Session 250217Another Important Detail•Used constructor, not clone, to make copies•Necessary because Date class is nonfinal•Attacker could implement malicious subclass–Records reference to each instance in list–Provides attacker with access to instance listSession 250218Unfortunately, Constructors Are Only Half the Battle// Accessor attack on internals of PeriodDate start = new Date();Date end = new Date();Period p = new Period(start, end);p.end.setYear(78); // Modifies internals of p!Session 250219The Solution: More Defensive Copying// Repaired accessors - defensively copy fieldspublic Date start() { return (Date) start.clone(); // (clone OK)}public Date end() { return (Date) end.clone(); // " "}Now Period class is robust!Session 250220Summary•Don’t incorporate mutable parameters into object; make defensive copies–Constructors, static factories, pseudo-constructors, mutators•Return defensive copies of mutable fields– Accessors•Real lesson—use immutable components– Eliminates the need for defensive copyingSession 250221III. Immutable Classes•Class whose instances cannot be modified•Examples: String, Integer, BigInteger•How, why, and when to use themSession 250222How to Write an Immutable Class•Don’t provide any mutators•Ensure that no methods may be overridden•Make all fields final•Make all fields private•Ensure exclusive access to any mutable componentsSession 250223Examplepublic final class Complex { private final float re, im; public Complex(float re, float im) { this.re = re; this.im = im; } // Accessors without corresponding mutators public float realPart() { return re; } public
View Full Document