Your SlideShare is downloading. ×
Java Pitfalls and Good-to-Knows
Upcoming SlideShare
Loading in...5

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Java Pitfalls and Good-to-Knows


Published on

This slide set covers some Java tidbits you might not encounter on your day-to-day java development. …

This slide set covers some Java tidbits you might not encounter on your day-to-day java development.
Perhaps some of them will improve your coding and save you some debugging!

Published in: Technology, News & Politics

  • Be the first to comment

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

No notes for slide


  • 1. Java Pitfalls and Good-to-KnowsMiquel Martin – contact@miquelmartin.orgBenjamin Hebgen –
  • 2. What’s this? This slide set covers some Java tidbits you might not encounter on your day-to-day java development. Perhaps some of them will improve your coding and save you some debugging!Photo credits:The splashing coffe cup at the title by 96dpi on flicker: beans on the watermark by wiedmaier on flicker: on the ReadWriteLock slide by darwinbell on flicker: 2Tree in the dune by suburbanbloke on flickr:
  • 3. PermGen and Strings The Java Garbage Collector works on generations. The permanent one hosts internalized Strings and classes. Permanent Generation: When the compiler finds a literal Class objects, Strings. Won’t String in your code, it allocates it be Garbage Collected (if not yet there) in the string pool Tenured Generation: at the PermGen heap. All instances Multi Garbage Collection of the same String will point to the survivors same PermGen instance. Young Generation: New objects Too many literal Strings (bad design) or thinks like classloader leaks ( can lead to “Out of MemoryError: PermGen space”. 3
  • 4. StringBuilders and StringBuffers Strings are immutable. String numberList = ""; for(int i = 0; i < 1000; i++){ The example on the right will: numberList+= i + ", "; 1. Create the numberList String } 2. Create a newNumberList with the numberList, I and a “, “ 3. Assign newNumberList to numberList 4. Repeat 1000 times 2 & 3 This is slow, fills up your heap and therefore forces more costly garbage collections Use instead a mutable StringBuilder. If StringBuilder builder= new StringBuilder(); you have multiple threads accessing for(int i = 0; i < 1000; i++){ it, use the synchronized version, builder.append(i+", "); } StringBuffer. String numberList = builder.toString(); 4
  • 5. From numbers to Strings How do you quickly convert a number to a String? int i = 42; String str = i; //Error, i not a String Case 1: easy but slow, a new String is created that concatenates the literal “” and i. // Case1: All time favorite (and slowest) Case 2: a new String is directly created for the String str = "" + i; number. This is 2x faster than Case 1 String str = i + ""; Case 3: it internally calls Case 2, and has roughly the same performance. // Case2: the fastest one String str = Integer.toString(myNumber); Exception: in “The number is “ + i, all three cases are similar since String concatenation must happen anyway, but Case 2 and 3 need to explicitly create // Case3: Also fast (calls Case 2) an additional String. String str = String.valueOf(myNumber); This also works on: short, float, double, long, etc.. Take home lesson: ignore this and do whatever’s more readable, unless performance is really critical 5
  • 6. Comparing floating point numbers Floating point numbers are encoded float f = 25 In Hexadecimal: using IEEE754-2008. Not all real 0100 0001 1100 1000 0000 0000 0000 00002 numbers can be represented (e.g. 0.2) Significand: bit ?: 1x1/1 = 1x1 = 1 Extra caution is needed when bit 9: 1x1/2 = 1x0.5 = 0.5 bit 10: 0x1/4 = 0x0.25 = 0 comparing floats (see examples) bit 11: 0x1/8 = 0x0.125 = 0 bit 11: 1x1/16 = 0x0.0625 = 0.0625 Also, portability issues due to . . evolution: Total = 1 + 0.5 + 0.0625 = 1.5625  Java ≤ 1.2: intermediate Bits 1 to 8: Exponent: 1000 00112 is 13110 calculation steps done using and then: 131-127 = 4 single or double precision Bit 0: the sign, 0 is positive Result: + 1.5625 x 24 = 25  Java > 1.2: to decrease rounding //This is true (uses floats) errors the highest platform boolean floatResult = supported precision is used for 0.1f + 0.1f + 0.1f == 0.3f; //This is false (uses doubles) intermediate results. boolean doubleResult = 0.1 + 0.1 + 0.1 == 0.3; Note: the strictfp keyword forces Java //Also false (also doubles) boolean doubleResult = 1.2 behavior 0.1d + 0.1d + 0.1d == 0.3d; 6
  • 7. Volatile variables Depending on the JVM, threads package operators; may work on copies of variables class Test extends Thread { boolean done = false; and never re-check the original public void run() { 1 reference. while (!done) { This does not happen if the } variable is marked volatile, or the System.out.println("Thread terminated."); variable access is synchronized. } Both tell the JVM that multi- thread access is likely and to check public static void main(String[] args) throws InterruptedException { the original reference. Test t = new Test(); The code on the right will never t.start(); finish unless (1) is volatile. The Thread.sleep(1000); behavior can change between t.done = true; JVMs. Also, volatile does not solve System.out.println("done"); concurrent modification issues. } } Don’t rely on volatile unless you know exactly what you’re doing. 7
  • 8. Breaking out of the right loop The break keyword takes a label as a mytag: for(int i =0; i < 10; i++){ parameter and breaks out of the for(j =0; j < 10; j++){ if(done) { scope tagged for it break mytag; } } } This works also on switch, for, while and do-while both for continue and break 8
  • 9. Preventing inheritance, overriding andinstantiating Controlling how your class is used // A Utility class has only static methods comes in handy: singletons, factories, public class UtilityClass { utility classes, etc… // Private constructor prevents // external class instantiation private TestClass() { The final keyword applied to a: }  Class: prevents extending public static int getInstance() {  method: prevents overriding return new TestClass();  primitive field: prevents changing } } the value  Object field: prevents changing // Final class cannot be extended the reference (you can still public final class FinalClass { change the object) // Final primitive cannot be modified final boolean something = false; A private default constructor will // Reference to final object cannot additionally prevent external //be modified final StringBuilder builder= new StringBuilder(); instantiation A final Class with only one private // Final method cannot be overriden constructor cannot be extended or public final void someMethod() { } overridden: it will never be externally } instantiated 9
  • 10. Static code blocks Static blocks let you execute public class StaticBlocks { private static int number = 1; static { something at class loading time System.out.println(number); } (e.g. assign a value to a static static { number = 2; field) } Static blocks and static field static { System.out.println(number); } assignment is done once at static { class loading } number = increaseNumber(number); The execution order is the same static { System.out.println(number); as the order in the code } public static int increaseNumber(int i) { return i + 1; } public static void main(String[] args) { System.out.println(number); //Aggregatted output: 1, 2, 3, 3 } } 10
  • 11. Finally we finalize the final. final is already covered try { System.out.println("In try"); throw new Exception(); finalize will be called on an instance } catch (Exception e) { when (if!) it is garbage collected. System.out.println("In catch");  You have no real control of when } finally { the GC will pass. Plus it’s bad System.out.println("In finally"); practice and often ignored by JVMs }  Do not use it to free resources. // Outputs: In try, In catch, In finally  It’s not the C++ destructor, finally goes after a try…catch block: BufferedWriter writer = null;  First, run the code in the try try {  If an exception is thrown, run the writer = Files.newBufferedWriter(file, appropriate code in catch charset);  Then, no matter what, run the code writer.write(s, 0, s.length()); in finally. Even after a return in } catch (IOException x) { catch or try. System.err.println("Error happened"); It’s worth using finally even if no } finally { exceptions are expected. They might be if (writer != null) writer.close(); thrown in a future code change. } 11
  • 12. Keywords you don’t see so often• assert: evaluate a boolean expression and throw an AssertionException if false. Useful to write your assumptions in the code, and get notified if you were wrong• continue: skip to the next iteration of a loop• strictfp: ensures consistent floating point operations on different platforms• transient: keep the field from being serialized when using standard java serialization mechanisms• volatile: prevents threads from working with a thread local copy of a variable when not using synchronized access• native: denotes that the method is provided by an external non-java library using JNI• goto: it’s a reserved keyword but a valid keyword. The compiler will throw a syntax error• const: same as goto 12
  • 13. Protective copies In this code, some internal logic class Test { occurs on adding/removing private List<String> internalStuff = new ArrayList<String>(); stuff. public void addStuff(String stuff) { //Do internal logic If getAllStuff returns internalStuff.add(stuff); internalStuff, the caller can } public void removeStuff(String stuff) { add/remove items without //Do internal logic going through removeStuff internalStuff.remove(stuff); } If this is (or could be) an issue, public List<String> getAllStuff(){ //Dangerous: return internalStuff; create a protective copy of //Better: internalStuff first return new ArrayList<String>(internalStuff); } } 13
  • 14. Shallow comparison and Arrays Comparison types: String[] a1 = new String[] { "0", "1", "2" }; String[] a2 = new String[] { "0", "1", "2" };  Shallow: uses == and System.out.println(a1 == a2); // false compares object System.out.println(a1.equals(a2)); // false 1 System.out.println(Arrays.equals(a1, a2)); // true references  Deep: uses equals and is List<String> list1 = new ArrayList<String>(3); List<String> list2 = new ArrayList<String>(3); as good as your equals list1.add("0"); implementation list2.add("0"); list1.add("1"); list2.add("1"); list1.add("2"); list2.add("2"); Notable exception: equals is System.out.println(list1 == list2); // false odd for arrays (1) and will System.out.println(list1.equals(list2)); perform a shallow // true if the elements in the list properly implement equals comparison. Use Arrays.equals instead 14
  • 15. Checked VS Unchecked exceptions Unlike Unchecked exceptions, Throwable Checked exceptions need to be caught or declared Pros of unchecked exceptions: Exception Error  Clearer code  You can still treat them like ? extends Runtime ? extends Exception checked exceptions if you Exception Error want ? extends Runtime Cons: Easy to miss Exception Unchecked Exceptions  JsonParseException in Gson  NumberFormatException from new Integer(“3,4”) in some locales 15
  • 16. Testing with Hamcrest Matchers In JUnit, assertTrue, public class RegexMatcher extends BaseMatcher<String> { assertEquals, etc… perform private final String regex; specific assertions public RegexMatcher(String regex) { this.regex = regex; } For arbitrary assertions, you @Override can use a Hamcrest Matcher public boolean matches(Object s) { return ((String) s).matches(regex); and run it with assertThat } @Override public void describeTo(Description description) { description.appendText("matches " + regex); } public static RegexMatcher matches(String regex) { return new RegexMatcher(regex); } } //Allows you to do: assertThat(actual, matches(regex)); 16
  • 17. Type erasure The Java generics implementation public void doSomething(List<String> does not change the compiler list) {} much, instead, it pre-processes public void doSomething(List<Integer> away the generics list) { } At compile time, type parameters // Compiler error: both methods can’t are replaced with their bounds be in the same class, since they have the same type erasure Types are “erased” in the compiled bytecode Famous pitfall: after type erasure, List<String> is the same as List<Integer> There’s plenty more interesting gotchas in generics, check: 17
  • 18. Read/Write Locks Case: you don’t care how many threads read your object, as long as no one is modifying it, and then, only one at a time. Solution: replace your synchronized methods with ReadWriteLocks Beware of the details:  in balanced read/write scenarios, the overhead of a ReadWriteLock will likely degrade performance.  Thread starvation and fairness are an issue. Check ReentrantLocks A good discussionL 18
  • 19. Synchronized Collections You’ll still find online that: List<String> unsynchronizedList = new  A Hashtable is like a HashMap but ArrayList<String>(); synchronized (there’s more to it, List<String> synchronizedList = like null values) Collections.synchronizedList(unsynchro  A Vector is like an ArrayList but nizedList); synchronized (it isn’t) This hasn’t been true since Java Map<String, String> unsynchronizedMap = 1.3 introduced the Synchronized new LinkedHashMap<String, String>(); Collections Map<String, String> synchronizedMap = Note that Read/Write locks are Collections.synchronizedMap(unsynchron Java >=1.5 so there’s plenty room izedMap); for optimizing if you need to. Notable exception: ConcurrentHashMap is (probably) your high-performance map for multi-threaded access 19
  • 20. Legacy ClassesLegacy classes are not (yet) deprecated but their use isdiscouraged. They still pop up in plenty of tutorials andsnippets. Vector and Dictionary/Hashtable should not be used as synchronized List and Map. Use Collections.synchronizedList and Collections.synchronizedMap instead. Also consider ConcurrentHashMap. Properties extends Hashtable with file writing capabilities, but there’s no replacement. Stack is a revamp of Vector to work like a LinkedList. Use that instead. StringTokenizer is better implemented by String.split and also handles encoding better Enumeration is very close to an Iterator but does less (e.g. remove) Most discouraged classes are parallel implementations of existing classes with a minor (often mis- implemented) delta. 20
  • 21. equals, hashCode and Comparable // HashMap put  Different collections use public V put(K key, V value) { if (key == null) different mechanisms to sort return putForNullKey(value); int hash = hash(key.hashCode()); out objects, for example: // Locate the bucket by hashCode  HashMap uses hashCode int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e =  TreeSet uses Comparable { Object k;  If hashCode and Comparable // Check for equality only in the bucket if (e.hash == hash && ((k = e.key) == key || are not consistent with equals, key.equals(k))) { V oldValue = e.value; expect inconsistencies! Check e.value = value; e.recordAccess(this); the contract. } return oldValue; } modCount++; addEntry(hash, key, value, i); return null; } 21
  • 22. Java 7’s NIO.2Java 7’s new file I/O makes file system Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);interactions much easier WatchService Implemented in java.nio.file.Files and watchService = new WatchService() { ... java.nio.file.Path }; path.register(watchService, ENTRY_CREATE, It provides common file operations ENTRY_DELETE, ENTRY_MODIFY); like copy or readAllLines Files.getPosixFilePermissions(path, You can get notifications on Path LinkOption.NOFOLLOW_LINKS); modifications Files.isExecutable(path); Files.isReadable(path); Support for permission and owner Files.isWritable(path); handling and links Files.readAllLines(path, Charset.forName("utf-8")); Fine grained exception handling Files.write(path, "mytext".getBytes(Charset. forName("utf-8")), StandardOpenOption.CREATE); 22
  • 23. Where to store resources Best practice for user specific String winPath = System.getProperty(" user.home") + File.separator + configuration options per OS: "Application Data" + File.separator + "myApp"; String linuxPath = System.getProperty ("user.home") + File.separator + ".myApp"; Storing in your classpath (e.g. in your TestClass.class.getResourceAsStream(" myresource.xml") jar) using Class.getResourceAsStream If you really really want, there is a way //This will find your class to find the path to your class, allowing MyClass.class.getProtectionDomain().g etCodeSource().getLocation().getP for storage relative to the installation ath(); folder 23
  • 24. (Avoid) Reinventing the wheel There are a lot of 3rd party libraries for Java. Avoid reinventing the wheel! Also beware of very alpha libraries! You will only use stuff you know exists. Consider browsing through the documentation of libraries like:  Apache Commons: for anything from logging to collections and much more  Google’s Guava: for a ton of convenience classes and very interesting containers  OPS4J: for all sort of OSGi related helpers 24
  • 25. Thanks and Happy Coding! 25