Slide 1

Slide 1 text

Best Practices Mistakes To Avoid

Slide 2

Slide 2 text

Avoid Resources Leaks The try-with-resources Statement Closeable xyz = open() ...do something... xyz.close() try (Closeable xyz = open()) { ...do something... } Closeable xyz = null; try { xyz = open() ...do something... } finally { if (xyz != null) xyz.close() } use fi nally to make sure close() is always called try-with-resources use OutputStream out; out = new FileOutputStream(“/file“); out.write(65); out.close(); ... stmt = dbConn.preparedStatement(sql); ResultSet rs = stmt.executeQuery(); while (rs.next()) { String v = rs.getString(1); ... } rs.close(); stmt.close() What if it throws exception? What if it throws exception? try (OutputStream out = new FileOutputStream("/file")) { out.write(65); } try (Statement stmt = dbConn.preparedStatement(sql)) { try (ResultSet rs = stmt.executeQuery()) { while (rs.next()) { String v = rs.getString(1); ... } } } What if it throws exception?

Slide 3

Slide 3 text

Avoid Silent Catches Ignoring Your Problems Won't Make Them Go Away try { // ...do something... } catch (Exception e) { // THIS IS WRONG IN 99.999% of the cases Logger.error(e, "meh, something went wrong... ignore it"); } // ...do something more // AGAIN THIS IS WRONG IN 99.999% of the cases // you just ignored what happened above try { // ...do something... } catch (Exception e) { // THIS IS WRONG IN 99.999% of the cases e.printStackTrace(); } try { // ...do something... } catch (Exception e) { throw new MyBetterException("this happened because…”, e); } try { db.execute("INSERT INTO table...") } catch (Exception e) { // THIS IS WRONG! you are hoping // that you get an exception for duplicate key // but you may get something else (e.g. network failure) db.execute("UPDATE table...") } If you don't know what to do with the exception, don't catch it! someone else up in the stack may be able to handle it. try { // ...do something... } catch (Exception e) { http.respond(HTTP_INTERNAL_SERVER_ERROR); return; } Enrich the exception Fail & Let the user know something went wrong

Slide 4

Slide 4 text

Object Scope Reduction Declare Variables near where they are used List myBadFunction() { int a = 0; ArrayList data = new ArrayList<>(); HashMap map = new HashMap<>(); if (...) { // map can be declared inside this block, nobody else use it // here we may know how many elements will be in the map and preallocate for (...) { map.put(key, value); } data.addAll(map.values()); } if (...) { // a is used only inside this block // declaring a variable near where it is used improves code readability for (...) { a += ...; } data.add(a > 10 ? "aaa" : "bbb"); } return data; } List myImprovedFunction() { ArrayList data = new ArrayList<>(); if (...) { HashMap map = new HashMap<>(...); for (...) { map.put(key, value); } data.addAll(map.values()); } if (...) { int a = 0; for (...) { a += ...; } data.add(a > 10 ? "aaa" : "bbb"); } return data; }

Slide 5

Slide 5 text

The “Final” Keyword To Improve Code Comprehension class Foo { private static final float THRESHOLD = 0.5f; private final String key; private int count; public Foo(final String key) { this.key = key; this.count = 0; } public List bar() { final ArrayList data = new ArrayList<>(); int index = 0; for (int i = 0; i < 10; i++) { if (Math.random() > THRESHOLD) { data.add("test-" + index); index++; } else { data.add(this.key); } } for (int i = 0; i < 5; i++) { data.add("test-" + index); index += 2; } this.count++; return data; } } The “key” parameter is not reassigned inside the method “count” will be changed by some methods of the class The “key” member variable Is assigned in the constructor And not changed by anyone else “THRESHOLD” is a constant The “data” variable is not reassigned inside the method. NOTE that the array Is NOT Immutable The “index” variable is reassigned inside the method. Improve Readability By knowing from the declaration If the variable will be reassiged

Slide 6

Slide 6 text

Util Classes Class with Only static Methods public final class MyUtil { private MyUtil() { // no-op } public static void doStuff() { // ... } } a final class can NOT be inherited/extended Block instance creation: new MyUtil() The constructor MyUtil() is not visible MyUtil.doStuff();

Slide 7

Slide 7 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate What is going on Under the hood?

Slide 8

Slide 8 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); size = 0 capacity = 2 private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 9

Slide 9 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); A size = 1 capacity = 2 private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 10

Slide 10 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); A B size = 2 capacity = 2 private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 11

Slide 11 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); A B size = 2 capacity = 2 There is no space for the new item “C” private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 12

Slide 12 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); A B size = 2 capacity = 4 A new Array is created Double the size private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 13

Slide 13 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); A B size = 2 capacity = 4 A B The Current Data Is Copied Over private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 14

Slide 14 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); A B capacity = 4 size = 2 The old Array Is Replaced With the new one private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 15

Slide 15 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); A B size = 3 capacity = 4 C Finally The Item Is Added private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 16

Slide 16 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); data.add(“D”); A B size = 4 capacity = 4 C D private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 17

Slide 17 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); data.add(“D”); data.add(“E”); size = 4 capacity = 8 A B C D A new Array is created Double the size private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 18

Slide 18 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); data.add(“D”); size = 4 capacity = 8 C D A B C D A B The Current Data Is Copied Over private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 19

Slide 19 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); data.add(“D”); data.add(“E”); capacity = 8 size = 4 A B C D The old Array Is Replaced With the new one private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 20

Slide 20 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); data.add(“D”); data.add(“E”); capacity = 8 E size = 5 A B C D private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 21

Slide 21 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); data.add(“D”); data.add(“E”); data.add(“F”); capacity = 8 E F size = 6 A B C D private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 22

Slide 22 text

Avoid Unnecessary Allocations Delay allocations & Preallocate when possible ArrayList data = new ArrayList<>(); data.add(“A"); data.add(“B”); data.add(“C”); data.add(“D”); data.add(“E”); data.add(“F”); capacity = 8 E F size = 6 A B C D new ArrayList<>(6) private List convert(final List input) { if (input == null || input.isEmpty()) { return Collections.emptyList(); } final ArrayList output = new ArrayList<>(input.size()); for (final ModelA model: input) { output.add(convert(model)); } return output; } private List convert(final List input) { final ArrayList output = new ArrayList<>(); if (input != null) { for (final ModelA model: input) { output.add(convert(model)); } } return output; } Preallocate the list With the expected size Use a Preallocated “Empty List” Reduce Allocation, and Preallocate

Slide 23

Slide 23 text

Avoid Unnecessary Map Lookups Use Variables! // SLOW: two lookup on the same key if (myMap.contains("key")) { MyObject v = myMap.get("key"); // ... } final MyObject v = myMap.get("key"); if (v != null) { // equivalent to myMap.contains("key") // ... } Avoid one lookup final HashMap myMap = new HashMap<>(); // ... for (int i = 0; i < N; ++i) { // SLOW: each iteration there are 3 lookups for the same key final String key = "key-" + i; myMap.get(key).doSomething(); myMap.get(key).doMore(myMap.get(key).getData()); } for (int i = 0; i < N; ++i) { final MyObject value = myMap.get("key-" + i); value.doSomething(); value.doMore(value.getData()); } Use Variables, to Avoid Extra Lookups final Map myMap; // ... final MyObject obj; if (myMap.containsKey(key)) { // if present, get the object obj = myMap.get(key); } else { // not present, compute the new object obj = new MyObject(); // add to it the map myMap.put(key, obj); } obj.doStuff() // do something with the object final Map myMap; // ... MyObject obj = myMap.computeIfAbsent(key, k -> new MyObject()); obj.doStuff() // do something with the object Use Compute If Absent

Slide 24

Slide 24 text

How to Iterate a Map Avoid the extra lookup for (final String key: map.keySet()) { // SLOW: each iteration does a lookup MyObject value = map.get(key); // ... } for (final Map.Entry entry: map.entrySet()) { final String key = entry.getKey(); final MyObject value = entry.getValue(); // ... } for (final String key: map.keySet()) { // ... } final Iterator> it = map.entrySet().iterator(); while (it.hasNext()) { final Map.Entry entry = it.next(); if (entry.getValue().points() < 500) { it.remove(); } } // find the keys to remove and add them to the 'toDelete' list final ArrayList toDelete = new ArrayList<>(); for (final Map.Entry entry : map.entrySet()) { if (entry.getValue().points() < 500) { toDelete.add(entry.getKey()); } } // remove entries from the map for (final String key : toDelete) { map.remove(key); } for (final Map.Entry entry : map.entrySet()) { if (entry.getValue().points() < 500) { map.remove(entry.getKey());! } } ConcurrentModi fi cationException for (final MyObject value: map.values()) { // ... } Iterate & Remove Iterate Keys Only Iterate each Entry (Key/Value) Iterate Values Only Use Iterator and .remove() Use .entrySet() to avoid the extra lookup

Slide 25

Slide 25 text

Singleton Pattern Let the JVM Handle The Concurrency Problem // Singleton.getInstance().doStuff() public final class Singleton { private static class HoldInstance { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return HoldInstance.INSTANCE; } private Singleton() {} public void doStuff() { /* do stuff... */ } } Lazy initialization // Singleton.INSTANCE.doStuff() private final class Singleton { public static final Singleton INSTANCE = new Singleton(); private Singleton() {} public void doStuff() { /* do stuff... */ } } Eager initialization public class BadSingleton { private static BadSingleton instance = null; public static BadSingleton getInstance() { if (instance == null) { // The caller thread may be paused here, // if another thread calls getInstance() // you end up with 2 instances instance = new BadSingleton(); } return instance; } } Lack of Thread Safety Multiple threads can create multiple instances simultaneously. No guarantee of a single instance being created. // Singleton.INSTANCE.doStuff() public enum Singleton { INSTANCE; private Singleton() {} public void doStuff() { /* do stuff... */ } } Enum initialization