192 |
193 |
194 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item1/Item1.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | import java.util.Date;
4 |
5 | public class Item1
6 | {
7 | public static void main(String[] args) {
8 | Worker worker = Worker.getInstance("Recep", 22, new Date(), false);
9 | System.out.println(worker);
10 | worker = Worker.getInstance("Inanc", 23, new Date(), true);
11 | System.out.println(worker);
12 |
13 | // Output:
14 | // { Worker = name = Recep, age = 22, dateOfBirth = Thu Jun 20 08:58:07 EET 2019, isMarried = false }
15 | // { Worker = name = Recep, age = 22, dateOfBirth = Thu Jun 20 08:58:07 EET 2019, isMarried = false }
16 | }
17 | }
18 |
19 | class Worker {
20 |
21 | private static Worker workerInstance;
22 |
23 | private String name;
24 | private int age;
25 | private Date dateOfBirth;
26 | private boolean isMarried;
27 |
28 | // Static Factory Methods gives us the control over the instances that are created.
29 | // They also let's us use better names for instance creation.
30 | public static Worker getInstance(String name, int age, Date dateOfBirth, boolean isMarried) {
31 | Worker worker = new Worker();
32 | if (workerInstance != null) {
33 | worker = workerInstance;
34 | } else {
35 | worker.name = name;
36 | worker.age = age;
37 | worker.dateOfBirth = dateOfBirth;
38 | worker.isMarried = isMarried;
39 | workerInstance = worker;
40 | }
41 | return worker;
42 | }
43 |
44 | @Override
45 | public String toString()
46 | {
47 | StringBuilder stringBuilder = new StringBuilder();
48 | stringBuilder.append("{ Worker = ");
49 | stringBuilder.append("name = " + name);
50 | stringBuilder.append(", age = " + age);
51 | stringBuilder.append(", dateOfBirth = " + dateOfBirth);
52 | stringBuilder.append(", isMarried = " + isMarried);
53 | stringBuilder.append(" }");
54 | return stringBuilder.toString();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item1/Item1.md:
--------------------------------------------------------------------------------
1 | # Item 1: Consider Static Factory Methods Instead of Constructors
2 | *Keywords: Constructors, Static Factory Methods, Flyweight Pattern*
3 |
4 | **Pros:**
5 |
6 | 1- Unlike constructors, they have names. This increases the readability of the code.
7 | 2- They are not required to create a new instance each time they are invoked. This technique can greatly increase performance if object that are expensive to create are requested often. Similar to Flyweight pattern. This allows classes to maintain control over what instances exists at any time, making them called instance-controlled.
8 | 3- Unlike constructors, they can return an object of any subtype of their return type.
9 |
10 | **Cons:**
11 |
12 | 1- Hard for programmers to find in the source code. Unlike constructors they do not stand out in the code. To solve this some naming conventions are listed below:
13 | * from — Type-conversion method that takes a single type and creates instance of another type ‘Date d = Date.from(instant)’
14 | * to — Aggregation method that takes multiple parameters and returns an instance of the type that incorporates them ’Set cards = EnumSet.of(‘JACK’, ‘QUEEN')'
15 | * valueOf — A more verbose alternative to from and of ‘BigInteger.valueOf(Integer.MAX_VALUE)'
16 | * getInstance — Get a previously created instance of the object, or create a new one if none exist.
17 | * newInstance — Guaranteed to return new instance at each call
18 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item2/Item2.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | import java.math.BigDecimal;
4 | import java.math.MathContext;
5 | import java.util.Date;
6 | import java.util.List;
7 |
8 | public class Item2
9 | {
10 | public static void main(String[] args)
11 | {
12 | HardWorker hardWorker1 = new HardWorker.HardWorkerBuilder("Jon Doe", 22, new Date(), false).build();
13 | HardWorker hardWorker2 = new HardWorker.HardWorkerBuilder("Jon Doe", 22, new Date(), false)
14 | .hoursWorked(5)
15 | .build();
16 | HardWorker hardWorker3 = new HardWorker.HardWorkerBuilder("Jon Doe", 22, new Date(), false)
17 | .hoursWorked(12)
18 | .numberOfMedals(2)
19 | .salary(new BigDecimal(999.12).round(MathContext.DECIMAL32))
20 | .build();
21 |
22 | System.out.println(hardWorker1);
23 | System.out.println(hardWorker2);
24 | System.out.println(hardWorker3);
25 |
26 | // Output:
27 | // { HardWorker = name = Jon Doe, age = 22, dateOfBirth = Thu Jun 20 09:20:02 EET 2019, isMarried = false,
28 | // hoursWorked = 0, numberOfMedals = 0, salary = null, holidays = null }
29 | //{ HardWorker = name = Jon Doe, age = 22, dateOfBirth = Thu Jun 20 09:20:02 EET 2019, isMarried = false,
30 | // hoursWorked = 5, numberOfMedals = 0, salary = null, holidays = null }
31 | //{ HardWorker = name = Jon Doe, age = 22, dateOfBirth = Thu Jun 20 09:20:02 EET 2019, isMarried = false,
32 | // hoursWorked = 12, numberOfMedals = 2, salary = 999.1200, holidays = null }
33 | }
34 | }
35 |
36 | class HardWorker
37 | {
38 |
39 | private final String name;
40 | private final int age;
41 | private final Date dateOfBirth;
42 | private final boolean isMarried;
43 | private final long hoursWorked;
44 | private final int numberOfMedals;
45 | private final BigDecimal salary;
46 | private final List holidays;
47 |
48 | public HardWorker(HardWorkerBuilder builder)
49 | {
50 | this.name = builder.name;
51 | this.age = builder.age;
52 | this.dateOfBirth = builder.dateOfBirth;
53 | this.isMarried = builder.isMarried;
54 | this.hoursWorked = builder.hoursWorked;
55 | this.numberOfMedals = builder.numberOfMedals;
56 | this.salary = builder.salary;
57 | this.holidays = builder.holidays;
58 | }
59 |
60 | public static class HardWorkerBuilder
61 | {
62 | // Required Parameters
63 | private String name;
64 | private int age;
65 | private Date dateOfBirth;
66 | private boolean isMarried;
67 |
68 | // Optional Parameters
69 | private long hoursWorked;
70 | private int numberOfMedals;
71 | private BigDecimal salary;
72 | private List holidays;
73 |
74 | public HardWorkerBuilder(String name, int age, Date dateOfBirth, boolean isMarried)
75 | {
76 | this.name = name;
77 | this.age = age;
78 | this.dateOfBirth = dateOfBirth;
79 | this.isMarried = isMarried;
80 | }
81 |
82 | // Builder optional parameter building methods
83 | public HardWorkerBuilder hoursWorked(int hours)
84 | {
85 | hoursWorked = hours;
86 | return this;
87 | }
88 |
89 | public HardWorkerBuilder numberOfMedals(int medals)
90 | {
91 | numberOfMedals = medals;
92 | return this;
93 | }
94 |
95 | public HardWorkerBuilder salary(BigDecimal val)
96 | {
97 | salary = val;
98 | return this;
99 | }
100 |
101 | public HardWorkerBuilder holidays(List val)
102 | {
103 | holidays = val;
104 | return this;
105 | }
106 |
107 | // Build method that binds all together
108 | public HardWorker build()
109 | {
110 | return new HardWorker(this);
111 | }
112 | }
113 |
114 | @Override
115 | public String toString()
116 | {
117 | StringBuilder stringBuilder = new StringBuilder();
118 | stringBuilder.append("{ HardWorker = ");
119 | stringBuilder.append("name = " + name);
120 | stringBuilder.append(", age = " + age);
121 | stringBuilder.append(", dateOfBirth = " + dateOfBirth);
122 | stringBuilder.append(", isMarried = " + isMarried);
123 | stringBuilder.append(", hoursWorked = " + hoursWorked);
124 | stringBuilder.append(", numberOfMedals = " + numberOfMedals);
125 | stringBuilder.append(", salary = " + salary);
126 | stringBuilder.append(", holidays = " + holidays);
127 | stringBuilder.append(" }");
128 | return stringBuilder.toString();
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item2/Item2.md:
--------------------------------------------------------------------------------
1 | # Item 2: Consider a Builder When Faced with Many Parameters
2 | *Keywords: Builder Pattern, Immutable class, Thread safety*
3 |
4 | Static factories and constructors do not scale well when there are many optional parameters. Usually "telescoping constructor” method is used to overcome this issue, where you have many constructors starting from the most basic one and call the one with the parameter set you need. But this is not so easy to write, read and maintain.
5 |
6 | Another alternative to this problem is to use JavaBeans pattern, where you create a parameterless constructor and set all parameters using setters. The main disadvantage with this approach is creating the instance you want is done in multiple calls and a JavaBean may be in an inconsistent state partway through its construction. And this patterns precludes the possibility of making a class immutable and requires added effort on the part of the programmers to ensure thread safety.
7 |
8 | Builder Pattern combines the safety of Telescoping Constructor and readability of JavaBeans Pattern.
9 | A single Builder can be used to build multiple objects.
10 |
11 | **Pros:**
12 |
13 | 1- More Readable
14 | 2- Safer
15 | 3- Allow classes to be immutable
16 |
17 | **Cons:**
18 |
19 | 1- Creating a builder before creating an object might be a problem for performance critical situations.
20 |
21 | It is best to use a Builder when a constructor needs more then 4-5 parameters, especially these parameters are optional or of identical type.
22 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item3/Item3.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | public class Item3
4 | {
5 | public static void main(String[] args)
6 | {
7 | int result = EnumSingleton.getInstance().getCounter();
8 | System.out.println(result);
9 | }
10 | }
11 |
12 | enum EnumSingleton
13 | {
14 | INSTANCE;
15 |
16 | // This constructor can be omitted completely
17 | // since enum constructors are implicitly private
18 | private EnumSingleton()
19 | {
20 |
21 | }
22 |
23 | public int counter = 9;
24 |
25 | public int getCounter()
26 | {
27 | return counter;
28 | }
29 |
30 | // You can also omit this method, but it
31 | // gives a better singleton feeling for the
32 | // users of this class. Instead of accessing
33 | // like: EnumSingleton.INSTANCE;
34 | public static EnumSingleton getInstance()
35 | {
36 | return INSTANCE;
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item3/Item3.md:
--------------------------------------------------------------------------------
1 | # Item 3: Enforce the Singleton Property with a Private Constructor or an Enum Type
2 | *Keywords: Singleton, Private Constructor, Transient, Supplier, Serialization, Single-Element Enum*
3 |
4 | A singleton is a class that is instantiated exactly once. Represents stateless objects, such as functions or a unique system component.
5 |
6 | One approach when creating a singleton class is to use final member field with a private constructor. This ensures that constructor is called exactly once and no more modifications can be made to that instance. To protect against privileged access to constructors you can throw an exception when the constructor asked to create a second instance.
7 |
8 | ```java
9 | public static final Elvis INSTANCE = new Elvis();
10 | private Elvis() {…}
11 | ```
12 |
13 | Another approach is to have a public static factory method “getInstance" which returns the same final member field with a private constructor.
14 |
15 | **Pros of First approach:**
16 | 1- API makes it clear that the class is a singleton: public static final field is final, so it will always serve the same instance.
17 | 2- It’s simpler.
18 |
19 | **Cons of First approach:**
20 | 1- For safe serialization operations you need to declare all instance fields “transient” and provide a readResolve method. Otherwise, each time a serialized instance is deserialized a new instance will be created.
21 |
22 | **Pros of Second approach:**
23 |
24 | 1- Flexibility to change implementation of the static factory method (getInstance) to make the class singleton or not without changing the API. You may change the getInstance method to return new instance for every new thread, or keep it as a singleton and this won’t cause any change in the API.
25 | 2- You can write generic singleton factory if needed.
26 | 3- A method reference can be used as a supplier. Elvis::instance is a Supplier
27 |
28 | Unless any of the 3 advantaged of second approach is needed, often the first approach is the way to go.
29 |
30 | A third way to create a singleton is to use a single-element enum.
31 |
32 | **Pros of Single-Element Enum approach:**
33 | 1- More concise.
34 | 2- Handles serialization for free.
35 | 3- Provides strong guarantee against multiple instantiation.
36 |
37 | **Cons of Single-Element Enum approach:**
38 | 1- You cannot use this approach if your singleton must extend a superclass other than Enum.
39 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item4/Item4.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | public class Item4
4 | {
5 | // Below line cannot be compiled since the constructor is private.
6 | // UtilityClass utilityClass = new UtilityClass();
7 | }
8 |
9 | class UtilityClass
10 | {
11 | // Constructor with a Private access modifier is used to disable instantiation
12 | private UtilityClass()
13 | {
14 | throw new AssertionError();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item4/Item4.md:
--------------------------------------------------------------------------------
1 | # Item 4: Enforce Non-instantiability with a Private Constructor
2 | ------
3 | *Keywords: -*
4 |
5 | Including a private constructor enables us to make a class non instantiable.
6 | We may want this to happen when we need to group a set of static fields and methods, like in `java.lang.Maths` or `java.util.Arrays`.
7 |
8 | Attempting to achieve this by making the class abstract does not work, because the class can be subclassed and the subclass is instantiated. As a side effect using a single private constructor also prevents this class to be subclassed. Because the subclass would have no accessible superclass constructor to invoke.
9 |
10 | **TL;DR**
11 |
12 | * When you need a class to be Non-instantiability, make its constructor private.
13 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item5/Item5.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | public class Item5
4 | {
5 |
6 | public static void main(String[] args)
7 | {
8 | // You as a Coffee Drinker can chose what type of coffee, with or without a milk
9 | // You do not need to manage coffee machine yourself you just tell what you want
10 | // to the Barista and he/she cooks it for you the way you want using the instructions you gave.
11 | Barista barista = new Barista(new CoffeeOrder(false, "Espresso"));
12 | barista.makeCoffee();
13 | }
14 |
15 | }
16 |
17 | class Barista
18 | {
19 | private final CoffeeOrder order;
20 |
21 | Barista(CoffeeOrder order)
22 | {
23 | this.order = order;
24 | }
25 |
26 | void makeCoffee()
27 | {
28 | order.startMachine();
29 | }
30 | }
31 |
32 | class CoffeeOrder
33 | {
34 |
35 | private boolean wantMilk;
36 | private String coffeeType;
37 |
38 | CoffeeOrder(boolean wantMilk, String coffeeType)
39 | {
40 | this.wantMilk = wantMilk;
41 | this.coffeeType = coffeeType;
42 | }
43 |
44 | private void plugIn()
45 | {
46 | System.out.println("Coffee machine plugged in.");
47 | }
48 |
49 | private void prepareIngredients()
50 | {
51 | System.out.println("Adding coffee");
52 | if (wantMilk)
53 | {
54 | System.out.println("Adding milk");
55 | }
56 | System.out.println("Adding whatever you want to add...");
57 | }
58 |
59 | void startMachine()
60 | {
61 | System.out.println("Coffee started...");
62 | plugIn();
63 | prepareIngredients();
64 | System.out.println("Coffee Type: " + coffeeType);
65 | System.out.println("Coffee Ready!");
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item5/Item5.md:
--------------------------------------------------------------------------------
1 | # Item 5: Prefer Dependency Injection to Hardwiring Resources
2 | ----
3 | *Keywords: Dependency Injection, Static Utility Class, Dagger, Guice, Spring*
4 |
5 | A SpellChecker class depends on an Dictionary class. So we can say, "SpellChecker depends on a Dictionary”. To provide this Dictionary dependency to our SpellChecker class, defining a static final Dictionary field in our SpellChecker, and creating it inside the class will cause some problems. assuming each language has its own dictionary and special dictionaries are used for special vocabularies, using a single dictionary (as in: `static final Dictionary dict = …;`) would not work.
6 |
7 | One form of Dependency Injection is to pass the resource into constructor when creating a new instance. Having a final field for the resources that are passed to constructor in order to inject them into our class preserves immutability. Dependency Injection is also applicable to static factories and builders.
8 |
9 | **Pros:**
10 | 1- Improves flexibility of the class
11 | 2- Improves testability: It is easier to mock classes that are being injected.
12 | 3- Improves reusability
13 |
14 | **Cons:**
15 | 1- It can clutter up large projects which typically contain thousands of dependencies. - Solution: This clutter can be handled using one of the frameworks for dependency injection: such as Dagger, Guice or Spring.
16 |
17 | **TL;DR**
18 | * Do not use a singleton or static utility class to implement a class that depends on one or more underlying resources, and do not have the class to create these resources directly. Instead pass the resources into to constructor (or static factory or builder) as a parameter.
19 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item6/Item6.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | public class Item6
4 | {
5 | public static void main(String args[])
6 | {
7 | long startTime = System.nanoTime();
8 | slowSum();
9 | long endTime = System.nanoTime();
10 | long duration = (endTime - startTime);
11 | System.out.println(duration);
12 |
13 | startTime = System.nanoTime();
14 | sum();
15 | endTime = System.nanoTime();
16 | duration = (endTime - startTime);
17 | System.out.println(duration);
18 | }
19 |
20 | private static long slowSum()
21 | {
22 | // Creating the sum variable as a Long object - not a primitive long.
23 | Long sum = 0L;
24 |
25 | for (long i = 0; i <= 10; i++)
26 | {
27 | // New "Long" object is created when sum += i is executed.
28 | sum += i;
29 | // System.out.println(System.identityHashCode(sum));
30 | }
31 |
32 | return sum;
33 | }
34 |
35 | private static long sum()
36 | {
37 | // Creating the sum variable as a primitive long.
38 | long sum = 0;
39 |
40 | for (long i = 0; i <= 10; i++)
41 | {
42 | // Operation is done on the same object when sum += i is executed.
43 | sum += i;
44 | // System.out.println(System.identityHashCode(sum));
45 | }
46 |
47 | return sum;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item6/Item6.md:
--------------------------------------------------------------------------------
1 | # Item 6: Avoid Creating Unnecessary Objects
2 | ---
3 | *Keywords: Lazy Loading, Autoboxing(Boxed Primitives and Long Creation)*
4 |
5 | Reusing an object instead of creating a new one is both faster and more stylish. An object can always be reused if it is immutable.
6 | You can often avoid creating new instances by using a static factory method instead of using constructors. For example using Boolean.valueOf(String) is preferable to constructor Boolean(String) - which was deprecated in Java 9. The constructor must create a new object every time it's called, whereas static factory method is never required to do so and won’t in practice.
7 |
8 | When there’s a String matching operation, using String.matches is very expensive because under the hood it creates a Pattern object every time we call it. It takes the regular expression we pass and turns it into a finite state machine. We can avoid this by compiling the pattern in a static final field of type Pattern, and reuse the same compiled instance. It is measured to be 6.5x faster this way. The problem with this approach is even if we do not call the method that uses the final field we created it would still be created already. This can be handled by using lazy loading, but the burden we get into to implement lazy loading for this case does not worth the performance improvement we get.
9 |
10 | Auto-boxing is another reason for creating unnecessary objects. Using a “Long" where you could use a “long” dramatically decreases the performance. Prefer primitives to boxed primitives, and watch out for unintentional auto-boxing.
11 |
12 | Although it is important to avoid unnecessary object creation, it is not that expensive to create and manage objects thanks to modern JVM implementations. Creating a copy of an object when needed “defensive copying” is far more important than avoiding creating unnecessary objects, since the first may cause security issues and bugs whereas the second one merely effects performance and style.
13 |
14 |
15 | **TL;DR**
16 |
17 | * Static Factory Methods such as Boolean.valueOf(String) can be used instead of new Boolean(String)
18 | * When using methods beware the underlying processes and avoid expensive object creations as much as possible. Like in String.matches(), compile the pattern in a final field instead.
19 | * Prefer primitives to boxed primitives, and watch out for unintentional auto-boxing.
20 | * Do not put yourself into trouble of managing your object pool, JVMs already help you with that.
21 | * Defensively Copy your objects when needed, don’t clutter up your codebase for a little bit of performance improvement.
22 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item7/Item7.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | import java.util.Arrays;
4 | import java.util.EmptyStackException;
5 |
6 | public class Item7
7 | {
8 | public static void main(String[] args)
9 | {
10 | MyStack stack = new MyStack();
11 | stack.push(new Integer("1111"));
12 | stack.push(new Integer("2222"));
13 | stack.push(new Integer("3333"));
14 |
15 | stack.pop();
16 | System.out.println("Non-Obsolete stack processed.");
17 |
18 | MyStack stackObsolete = new MyStack();
19 | stackObsolete.push(new Integer("1111"));
20 | stackObsolete.push(new Integer("2222"));
21 | stackObsolete.push(new Integer("3333"));
22 |
23 | stackObsolete.popWithObsolete();
24 | System.out.println("Obsolete stack processed.");
25 | }
26 | }
27 |
28 | class MyStack
29 | {
30 | private Object[] elements;
31 | private int size = 0;
32 | private static final int DEFAULT_CAPACITY = 16;
33 |
34 | public MyStack()
35 | {
36 | elements = new Object[DEFAULT_CAPACITY];
37 | }
38 |
39 | void push(Object e)
40 | {
41 | checkCapacity();
42 | elements[size++] = e;
43 | }
44 |
45 | Object pop()
46 | {
47 | if (size == 0)
48 | {
49 | throw new EmptyStackException();
50 | }
51 |
52 | // Below, popping out the latest element and reducing the size by 1 will cause
53 | // obsolete reference to be kept in memory
54 | // return elements[--size];
55 |
56 | // Here, however, we null out the reference so that it will be removed by the garbage-collector
57 | Object poppedObject = elements[--size];
58 | elements[size] = null; // Eliminate obsolete reference
59 | return poppedObject;
60 |
61 | }
62 |
63 | Object popWithObsolete()
64 | {
65 | if (size == 0)
66 | {
67 | throw new EmptyStackException();
68 | }
69 |
70 | // Below, popping out the latest element and reducing the size by 1 will cause
71 | // obsolete reference to be kept in memory
72 | return elements[--size];
73 |
74 | }
75 |
76 | private void checkCapacity()
77 | {
78 | if (elements.length == size)
79 | {
80 | elements = Arrays.copyOf(elements, 2 * size + 1);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item7/Item7.md:
--------------------------------------------------------------------------------
1 | # Item 7: Eliminate Obsolete Object References
2 | *Keywords: Memory leak*
3 |
4 | When garbage-collector does the removal of unused variables for you and help you manage the memory usage with that, it is easier to look over some things that may cause memory leaks.
5 |
6 | An example to this is, when a stack grows and then shrinks , the objects that were popped off the stack will not be garbage collected, even if the program has no more references to them. This is because the stack implementation maintains obsolete references to these objects.
7 |
8 | If an object reference is unintentionally retained, any objects referenced by that object are also retained too. Even if only a few object references are unintentionally retained, many other objects may be prevented from being garbage-collected, and this may cause potentially large effects on performance.
9 |
10 | For the stack example, the solution is to null out references once they become obsolete, this way garbage-collector will remove that object reference. But keep in mind that "Nulling Out Object References” should be an exception, it should not be the normal behavior. Instead the best way to eliminate an obsolete reference is to let the variable that contained the reference fall out of scope by defining each variable in its narrowest possible scope.
11 |
12 | After putting an object reference into a cache and then forgetting it there and leave it in cache long after it becomes irrelevant. WeakHashMap can be used as a solution to that.
13 |
14 | **TL;DR**
15 |
16 | 1. Whenever a class manages its own memory the programmer should be alert for memory leaks.
17 | 2. Define variables in their narrowest scope.
18 | 3. Caches are a common source of memory leaks.
19 | 4. Listeners and other callbacks may also be a source for memory leaks.
20 | 5. Heap profiler can be used to identify memory leaks. https://blog.jetbrains.com/idea/2016/08/jvm-debugger-memory-view-for-intellij-idea/
21 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item9/Item9.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.OutputStream;
8 |
9 | public class Item9
10 | {
11 | public static void main(String[] args)
12 | {
13 | //copy("a", "b");
14 | }
15 |
16 | static void copy(String src, String dest) throws IOException
17 | {
18 | InputStream inputStream = new FileInputStream(src);
19 | OutputStream outputStream = new FileOutputStream(dest);
20 | byte[] buf = new byte[122];
21 | int n;
22 | while ((n = inputStream.read(buf)) >= 0) {
23 | outputStream.write(buf, 0, n);
24 | }
25 | outputStream.close();
26 | inputStream.close();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Item9/Item9.md:
--------------------------------------------------------------------------------
1 | # Item 9: Prefer try-with-resources to try-finally
2 | **Keywords: -**
3 |
4 | In java we often use try-finally for cases where we need to manually close a resource (i.e. InputStream, OutputStream etc.). The main problem with this approach is that if you get an error while in the try section of your open InputStream, and you get an error rather than opening the stream, like you get an error because you tried to run .readLines(), and because of the same reason the code in your finally section, .close(), fails and throws an Exception, you will not be able to view the first exception giving you a hard time when debugging is required.
5 |
6 | When Java 7 introduced try(withResources) that solves this problem. Your resource need to implement AutoClosable interface, and then the latter exceptions are suppressed and the first one is thrown. It also allows you to still access to all of the suppressed exceptions, even programmatically using getSuppressed().
7 |
8 | **TL;DR**
9 |
10 | Always use try-with-resources statement instead of try-finally when working with resources that needs to be closed, for a cleaner, shorter, better code and better exception management.
11 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Keywords/EnumSingleton.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava;
2 |
3 | public enum EnumSingleton
4 | {
5 | INSTANCE;
6 |
7 | // This constructor can be omitted completely
8 | // since enum constructors are implicitly private
9 | private EnumSingleton() {
10 |
11 | }
12 |
13 | public int counter = 9;
14 |
15 | public int getCounter()
16 | {
17 | return counter;
18 | }
19 |
20 | // You can also omit this method, but it
21 | // gives a better singleton feeling for the
22 | // users of this class. Instead of accessing
23 | // like: EnumSingleton.INSTANCE;
24 | public static EnumSingleton getInstance() {
25 | return INSTANCE;
26 | }
27 |
28 | static class Test {
29 | public static void main(String[] args) {
30 | int result = EnumSingleton.getInstance().getCounter();
31 | System.out.println(result);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Keywords/FlyweightPattern.java:
--------------------------------------------------------------------------------
1 | // Rewritten an *almost* ready to run Flyweight Pattern sample code in java
2 | // The original source code https://refactoring.guru/design-patterns/flyweight
3 |
4 | class Tree
5 | {
6 | private int x, y;
7 | private TreeType treeType;
8 |
9 | public Tree(int x, int y, TreeType treeType)
10 | {
11 | this.x = x;
12 | this.y = y;
13 | this.treeType = treeType;
14 | }
15 | }
16 |
17 | class TreeType
18 | {
19 | private int numberOfBranches;
20 | private String color;
21 | private boolean isExported;
22 |
23 | public TreeType(int numberOfBranches, String color, boolean isExported)
24 | {
25 | this.numberOfBranches = numberOfBranches;
26 | this.color = color;
27 | this.isExported = isExported;
28 | }
29 |
30 | public void loseLeaves()
31 | {
32 | System.out.println("Dropping my leaves as " + this.toString());
33 | }
34 |
35 | public int getNumberOfBranches()
36 | {
37 | return numberOfBranches;
38 | }
39 |
40 | public String getColor()
41 | {
42 | return color;
43 | }
44 |
45 | public boolean isExported()
46 | {
47 | return isExported;
48 | }
49 | }
50 |
51 | class TreeFactory {
52 | public static ArrayList treeTypes = new ArrayList<>();
53 | public static TreeType getTreeType(int numberOfBranches, String color, boolean isExported) {
54 | TreeType treeType = treeTypes.find(numberOfBranches, color, isExported);
55 |
56 | if (treeType == null) {
57 | treeType = new TreeType(numberOfBranches, color, isExported);
58 | treeTypes.add(treeType);
59 | }
60 |
61 | return treeType;
62 | }
63 |
64 | private TreeType find(int numberOfBranches, String color, boolean isExported) {
65 | for (TreeType treeType : treeTypes) {
66 | if (treeType.getNumberOfBranches() == numberOfBranches && treeType.getColor().equals(color) && treeType.isExported() == isExported)
67 | return treeType;
68 | }
69 | return null;
70 | }
71 |
72 | }
73 |
74 | class Forest
75 | {
76 | private ArrayList trees;
77 |
78 | public void plantTree(int x, int y, int numberOfBranches, String color, boolean isExported) {
79 | TreeType treeType = TreeFactory.getTreeType(numberOfBranches, color, isExported);
80 | Tree tree = new Tree(x, y, treeType);
81 | trees.add(tree);
82 | System.out.println("Number of trees in the forest: " + trees.size());
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Keywords/ImmutableClass.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava;
2 |
3 | public class ImmutableClass
4 | {
5 | public static void main(String[] args) {
6 | ImmutableKlass immutable = new ImmutableKlass("Recep", 22);
7 | immutable.getName();
8 | immutable.getAge();
9 |
10 | // Calls listed below are not possible, we cannot mutate this class.
11 | // immutable.setName("Inanc");
12 | // immutable.setAge(23);
13 | // immutable.name = "Inanc";
14 | // immutable.age = 23;
15 | }
16 | }
17 |
18 | final class ImmutableKlass // final - so that child class
19 | {
20 | // fields declared as final so that they cannot be changed once they are initialized
21 | private final String name;
22 | private final int age;
23 |
24 | public ImmutableKlass(String name, int age)
25 | {
26 | this.name = name;
27 | this.age = age;
28 | }
29 |
30 | public String getName()
31 | {
32 | return name;
33 | }
34 |
35 | public int getAge()
36 | {
37 | return age;
38 | }
39 |
40 | // No setters so that fields cannot be changed
41 | }
42 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Keywords/Keywords.md:
--------------------------------------------------------------------------------
1 | # Keywords
2 |
3 | *Flyweight Pattern* - This pattern suggests that you stop storing the unique state inside the object. Instead, you should pass this state to specific methods which rely on it. Only the identical state stays within the object, letting you reuse it in different contexts. As a result, you’d need fewer of these objects since they only differ in the intrinsic state, which has much fewer variations than the extrinsic. Sample code at [FlyweightPattern.java](https://github.com/recepinanc/effective-java-notes/blob/master/Creating%20and%20Destroying%20Objects/Keywords/FlyweightPattern.java)
4 |
5 | *Immutable class* - Once an object is created, we cannot change its content. In Java, all the wrapper classes (like String, Boolean, Byte, Short) and String class is immutable. The easiest way to create an immutable class in **Java** is by declaring all the fields private and final and not providing setters.
6 |
7 | *Thread safety* - Thread safety implies multiple threads can write/read data in same object without memory inconsistency errors. This means that different threads can access the same resources without exposing erroneous behavior or producing unpredictable results.
8 |
9 | *Transient* - By definition it means “lasting for a short time”. When an object is transferred through the network, the object needs to be 'serialized'. Serialization converts the object state to serial bytes. Those bytes are sent over the network and the object is recreated from those bytes. Member variables marked by the java transient keyword are not transferred, they are lost intentionally. In Java, transient keyword is used for the variables which we do not want to be serialized. Those variables will have their default value as the result. It is good habit to use transient keyword with private confidential fields of a class during serialization.
10 |
11 | *Single-Element Enum* - It is told in Effective Java this is the preferred way of creating a singleton class.
12 |
13 | *Dependency Injection* - https://medium.com/@atarikguney/dependency-injection-nedir-1124c15249ad Last principle in SOLI(D). The goal is to inject the classes you depend in your class so that it works properly without you needing it to manage.
14 |
15 | *Static Utility Class* - These are Helper classes that contains only static methods, it is stateless and it cannot be instantiated. Goal is to increase reusability, but as a down side it increases coupling between classes, creating external dependency and make it harder to test. Utility classes should be avoided as much as possible because of this down sides http://ralin.io/blog/oop-anti-patterns-utility-or-helper-classes.html.
16 |
17 | *Dagger, Guice, Spring* - These are dependency injection frameworks.
18 |
19 | *Lazy Loading* - It is an optimization technique that works by loading only the content that is needed by the user. It reduces time and memory consumption.
20 |
21 | *Autoboxing* - Converting a primitive value into an object of the corresponding wrapper class. boolean -> Boolean, int -> Integer, long -> Long …
22 |
23 | *Memory Leak* - A memory heap is a portion memory that is dynamically allocated memory resides. A memory heap is a location in memory where memory may be allocated at random access.
24 | Unlike the stack where memory is allocated and released in a very defined order, individual data elements allocated on the heap are typically released in ways which is asynchronous from one another. Memory leak occurs when programmers create a memory in heap and forget to delete it. Memory leaks are particularly serious issues for programs like daemons and servers which by definition never terminate.
25 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Keywords/ThreadSafety.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava;
2 |
3 | import java.util.concurrent.locks.Lock;
4 | import java.util.concurrent.locks.ReentrantReadWriteLock;
5 |
6 | public class ThreadSafety
7 | {
8 |
9 | public static void main(String[] args)
10 | {
11 |
12 | }
13 |
14 | }
15 |
16 | // Main problem with the below code is that count is a field
17 | // in the NonThreadSafe class.
18 | // This is the "state" of the class, each time countTo10() is
19 | // called the state changes.
20 | // Calling countTo10() in a single thread would work OK but
21 | // using more threads may cause issues since before (count == 10) could be checked
22 | // other threads could run the "count = count + 1" part and cause count to be 11
23 | // which then fails the check count == 10 and keeps incrementing the count.
24 |
25 | class NonThreadSafe {
26 | private int count = 0;
27 |
28 | public boolean countTo10() {
29 | count = count + 1;
30 | return (count == 10);
31 | }
32 | }
33 |
34 | // One way to achieve thread safety is to
35 | // have a stateless implementation; such as a function
36 | // A stateless implementation is the one that
37 | // always give the same output for the same input
38 |
39 | class ThreadSafe1 {
40 |
41 | // For same input values this method
42 | // guaranteed to give the same output
43 | public boolean countTo10(int count) {
44 | count = count + 1;
45 | return (count == 10);
46 | }
47 | }
48 |
49 | // Another way to achieve thread safety is to
50 | // Making classes immutable.
51 | // If we need to share state between different threads,
52 | // we can create thread-safe classes by making them immutable.
53 | // After our object is constructed from an immutable class,
54 | // no other thread can change/mutate it, making it thread-safe.
55 | // BUT, we do not want to have this in a case where we use the same Bean
56 | // to create different instances, on multiple threads since it would cause
57 | // bigger problems such as cannot using the instances we intended to but
58 | // instead keep using the one we created previously.
59 |
60 |
61 | // Read/Write Locks are another way, we lock the object when writing and reading
62 | // and unlock it when the operation is done so that both cannot happen at the same time.
63 |
64 | class ThreadSafe2 {
65 |
66 | private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
67 | private final Lock readLock = rwLock.readLock();
68 | private final Lock writeLock = rwLock.writeLock();
69 |
70 | private int count = 0;
71 |
72 | public void incrementCount() {
73 | writeLock.lock();
74 | try {
75 | count += 1;
76 | } finally {
77 | writeLock.unlock();
78 | }
79 | }
80 |
81 | public boolean checkCount() {
82 | readLock.lock();
83 | try {
84 | return (count == 10);
85 | } finally {
86 | readLock.unlock();
87 | }
88 | }
89 | }
90 |
91 | // We can make use of "synchronized" methods and statements.
92 | // Only one thread can access a synchronized method at a time
93 | // while blocking access to this method from other threads.
94 | // P.S. Synchronized Collections can be used for thread-safe Collections
95 |
96 | // synchronized method
97 | class ThreadSafe3 {
98 | private int count = 0;
99 |
100 | public synchronized boolean countTo10() {
101 | count = count + 1;
102 | return (count == 10);
103 | }
104 | }
105 |
106 | // synchronized statement
107 | // Synchronization is expensive, so with this option, we are able to only synchronize the relevant parts of a method.
108 | class ThreadSafe4 {
109 | private int count = 0;
110 |
111 | public boolean countTo10() {
112 | synchronized(this) {
113 | count = count + 1;
114 | }
115 | return (count == 10);
116 | }
117 | }
118 |
119 | // Thread-Local Fields
120 | // If we actually need to maintain state, we can create thread-safe
121 | // classes that don’t share state between threads by making their
122 | // fields thread-local.
123 |
124 |
--------------------------------------------------------------------------------
/Chapter 2 - Creating and Destroying Objects/Keywords/TransientKeyword.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.ObjectInputStream;
7 | import java.io.ObjectOutputStream;
8 | import java.io.Serializable;
9 |
10 | // Original source code is at : https://www.geeksforgeeks.org/transient-keyword-java/
11 |
12 | public class TransientKeyword implements Serializable
13 | {
14 |
15 | private transient int x = 1;
16 | private int y = 2;
17 |
18 |
19 | public static void main(String[] args) throws IOException, ClassNotFoundException
20 | {
21 | TransientKeyword input = new TransientKeyword();
22 | FileOutputStream fos = null;
23 | fos = new FileOutputStream("abc.txt");
24 | ObjectOutputStream oos = null;
25 | oos = new ObjectOutputStream(fos);
26 | oos.writeObject(input);
27 | FileInputStream fis = new FileInputStream("abc.txt");
28 | ObjectInputStream ois = new ObjectInputStream(fis);
29 | TransientKeyword output = (TransientKeyword) ois.readObject();
30 | System.out.println("i = " + output.x);
31 | System.out.println("j = " + output.y);
32 | }
33 |
34 | // Result
35 |
36 | // i = 0
37 | // j = 2
38 | }
39 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item10/Item10.java:
--------------------------------------------------------------------------------
1 | package com.recepinanc.effectivejava.chapter2;
2 |
3 | public class Item10
4 | {
5 | public static void main(String[] args)
6 | {
7 | Person recep = new Person(22, "Recep", "44411122234");
8 | Person emre = new Person(22, "Emre", "55511122235");
9 |
10 | Person recepFromPast = new Person(15, "Recep", "44411122234");
11 | Person recepFromFuture = new Person(25, "Recep", "44411122234");
12 |
13 | // Reflexive
14 | System.out.println(recep.equals(recep)); // => true
15 |
16 | // Symmetric
17 | System.out.println(recep.equals(emre)); // => false
18 | System.out.println(emre.equals(recep)); // => false
19 |
20 | // Transitive
21 | System.out.println(recepFromPast.equals(recep)); // => true
22 | System.out.println(recep.equals(recepFromFuture)); // => true
23 | System.out.println(recepFromPast.equals(recepFromFuture)); // => true
24 |
25 | // Consistent
26 | for (int i = 0; i< 10; i++)
27 | {
28 | System.out.println(recep.equals(emre)); // => false
29 | }
30 |
31 | // Non-nullity
32 | System.out.println(recep.equals(null)); // => false
33 | }
34 | }
35 |
36 |
37 | class Person
38 | {
39 | int age;
40 | String name;
41 | String id;
42 |
43 | public Person(int age, String name, String id)
44 | {
45 | this.age = age;
46 | this.name = name;
47 | this.id = id;
48 | }
49 |
50 |
51 | // Sample equals method that obeys the general contract of equals methods
52 | @Override
53 | public boolean equals(Object obj)
54 | {
55 | if (obj == this) // to ensure x.equals(x) is always true
56 | return true;
57 | if (!(obj instanceof Person))
58 | return false;
59 | Person that = (Person) obj;
60 |
61 | return that.id == this.id;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item10/Item10.md:
--------------------------------------------------------------------------------
1 | # Item 10: Obey the general contract when overriding equals
2 | *Keywords: -*
3 |
4 | It is appropriate to override equals when a class has a notion of logical equality that differs from mere object identity and a superclass has not already overridden equals. This is generally the case for value classes. A value class is simply a class that represents a value, such as Integer or String.
5 |
6 | An equals method must adhere to its general contract:
7 | * Reflexive: x.equals(x)
8 | * Symmetric: x.equals(y) = y.equals(x)
9 | * Transitive: x.equals(y) & y.equals(z) => x.equals(z)
10 | * Consistent: x.equals(y) gives exactly the same result for N number of executions.
11 | * Non-nullity: x.equals(null) is always false.
12 |
13 | Do not write an equals method that depends on unreliable resources, for example resource that may change their values in time.
14 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item11/Item11.md:
--------------------------------------------------------------------------------
1 | # Item 11: Always override hashCode when you override equals
2 | *Keywords: Lazy Initialization*
3 |
4 | You must override hashCode in every class that overrides equals, in order not to break hashCode contract. Otherwise it will prevent it from functioning properly in collections such as HashMap and HashSet.
5 |
6 | * Consistent: hashCode gives exactly the same result for N number of executions.
7 | * x.equals(y) => x.hashCode() = y.hashCode()
8 | * It is not required to have distinct hashCode's for objects that are not “equal” but having distinct values will improve the performance of hash tables.
9 |
10 | ```java
11 | Map m = new HashMap<>();
12 | m.put(new PhoneNumber(123,123,111), “Recep”);
13 | m.get(new PhoneNumber(123,123,111)) // expected => “Recep”
14 | ```
15 |
16 | But if PhoneNumber class is failed to obey the hashCode contract and implemented in a way that it is according to logical equivalence, these two different PhoneNumber objects (but logically equal) did not generated the same integer thus there’s no record in the HashMap.
17 |
18 | Setting a constant integer for the hashCode? NO! Worst legal implementation possible… Because it kills all the benefits of using “hash..." data structures.
19 |
20 | Recipe to implement a good hashCode function can be found in the sample code cases.
21 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item12/Item12.java:
--------------------------------------------------------------------------------
1 | public class Item12 {
2 | public static void main(String[] args) {
3 | Person p = new Person("Recep Inanc", 22);
4 | PersonOverridden p2 = new PersonOverridden("Recep Inanc", 22);
5 |
6 | System.out.println(p); // looks confusing
7 |
8 | System.out.println(p2); // more informative.
9 | }
10 | }
11 |
12 | class Person {
13 | private String name;
14 | private int age;
15 |
16 | Person(String name, int age) {
17 | this.name = name;
18 | this.age = age;
19 | }
20 | }
21 |
22 | class PersonOverridden {
23 | private String name;
24 | private int age;
25 |
26 | PersonOverridden(String name, int age) {
27 | this.name = name;
28 | this.age = age;
29 | }
30 |
31 | @Override
32 | public String toString() {
33 | StringBuilder sb = new StringBuilder();
34 | sb.append("Person = {");
35 | sb.append("{ 'name' = ").append(name);
36 | sb.append(" },");
37 | sb.append("{ 'age' = ").append(age);
38 | sb.append(" }}");
39 | return sb.toString();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item12/Item12.md:
--------------------------------------------------------------------------------
1 | # Item 12: Always override toString
2 | *Keywords: -*
3 |
4 | In the toString contract it says “It is recommended that all subclasses override this method.”
5 |
6 | **Why?**
7 | * Overriding toString and providing a more informative result makes it easier for systems to debug and much more pleasant.
8 |
9 | As an example writing a debug log would get better if we override the PhoneNumber class’ toString method to return {Recep=123-422-656} instead of letting it return its original PhoneNumber@75ad21
10 |
11 | The returned string should be self-explanatory. It is better to give all the interesting information in that string if it is practical, otherwise returning a string that describes that object is also good (for example: "List of Recep’s phoneNumbers [455 records]” is a lot better than PhoneBook@185x1a).
12 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item13/Item13.java:
--------------------------------------------------------------------------------
1 | public class Item13 {
2 | public static void main(String[] args) {
3 | PersonC p = new PersonC("Recep Inanc", 22);
4 | // p.clone(); calling this before adding a public clone method inside PersonC class
5 | // will not compile and warn us : .clone() method has protected access in java.lang.Object
6 | // because we add "implements Cloneable".
7 |
8 | try {
9 | PersonC pCloned = (PersonC) p.clone();
10 | System.out.println(pCloned);
11 | System.out.println(pCloned == p); // not the exact same objects so, false
12 | System.out.println(pCloned.equals(p)); // logically the same objects acc. to our equals() implementation so, true
13 | System.out.println(pCloned.getClass() == p.getClass()); // one of the requirements of clone contract.
14 | } catch (CloneNotSupportedException e) {
15 | e.printStackTrace();
16 | }
17 |
18 | PersonC pCloned2 = new PersonC(p); // no need to handle exception
19 | System.out.println(pCloned2 == p); // not the exact same objects so, false
20 | System.out.println(pCloned2.equals(p)); // logically the same objects acc. to our equals() implementation so, true
21 | System.out.println(pCloned2.getClass() == p.getClass()); // one of the requirements of clone contract.
22 |
23 | }
24 | }
25 |
26 | class PersonC implements Cloneable {
27 | private String name;
28 | private int age;
29 |
30 | PersonC(String name, int age) {
31 | this.name = name;
32 | this.age = age;
33 | }
34 |
35 | // Copy constructors are a better alternative to the fragile and complex clone methods.
36 | PersonC(PersonC objectToCopy) {
37 | this.name = objectToCopy.getName();
38 | this.age = objectToCopy.getAge();
39 | }
40 |
41 | public void setName(String name) {
42 | this.name = name;
43 | }
44 |
45 | public String getName() {
46 | return name;
47 | }
48 |
49 | public void setAge(int age) {
50 | this.age = age;
51 | }
52 |
53 | public int getAge() {
54 | return age;
55 | }
56 |
57 | @Override
58 | public boolean equals(Object obj) {
59 | if (obj == this) // to ensure x.equals(x) is always true
60 | return true;
61 | if (!(obj instanceof PersonC))
62 | return false;
63 | PersonC that = (PersonC) obj;
64 |
65 | return that.age == this.age && that.name.equals(this.name);
66 | }
67 |
68 | @Override
69 | public String toString() {
70 | StringBuilder sb = new StringBuilder();
71 | sb.append("Person = {");
72 | sb.append("{ 'name' = ").append(name);
73 | sb.append(" },");
74 | sb.append("{ 'age' = ").append(age);
75 | sb.append(" }}");
76 | return sb.toString();
77 | }
78 |
79 | @Override
80 | public Object clone() throws CloneNotSupportedException {
81 | return super.clone();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item13/Item13.md:
--------------------------------------------------------------------------------
1 | # Item 13: Override clone judiciously
2 |
3 | *Keywords: Reflection, "Native" keyword, Copy Constructor*
4 |
5 | Cloneable interface indicates that the class is cloneable, and it is legal to make a field-by-field copy of the object by overriding the protected clone() method, java.lang.Object#clone() with a public clone() method. An CloneNotSupportedException is thrown when .clone() is called on an object whose class does not implement Cloneable interface. Normally, interfaces are used to say something about what a class can do, but in this case it modifies the behavior of a protected method on a superclass.
6 |
7 | The general contract for clone method is weak;
8 |
9 | * x.clone() != x must be true
10 | * x.clone().getClass() == x.getClass() must be true
11 | * x.clone().equals(x) expected to be true depending on the definition of your equals method - but not an absolute requirement.
12 |
13 | Never provide a clone method for immutable classes, to prevent wasteful copying.
14 |
15 | For PhoneNumber example, assume we made the class implement Cloneable interface, in the clone method of PhoneNumber class we’d call super.clone() and this will result in returning an object with the class of “Object” having the same fields and values as our original PhoneNumber, than we’d have to cast it to PhoneNumber class, and this casting is guaranteed to succeed.
16 |
17 | If an object contains fields that refer to mutable objects, the simple clone implementation can be disastrous. Suppose we have a Stack class that implements clone method, with the field "Object[] elements;” cloning the Stack will result in a new Stack object that has all same fields and values but the new object’s “elements” will be pointing to the original elements in original Stack instance that we call .clone() on. To fix that we need to implement .clone() in a way that it calls clone on the mutable fields of the instance.
18 |
19 | Sometimes it is required to do a deepCopy for a field, such as when there’s an array of linkedLists in a field called Entry[] buckets, even though you call .clone on buckets, as it is suggested earlier, the linkedLists inside the new buckets field will still point to the original linkedList references.
20 |
21 | **TL;DR:**
22 |
23 | * All classes that implement Cloneable interface should override clone() method with a public one whose return type is the class itself
24 | * Clone method first calls super.clone() then fix any fields that needs to be fixed
25 | * If the class only has primitive fields or references to immutable objects, no fixing is needed. - Exception: if there’s an ID that needs to be unique for every object, after cloning the original, the ID field needs to be fixed/changed.
26 | * As an alternative to this complex copying method (clone) we could provide a copy constructor - a constructor that takes a single parameter whose type is the class that contains the constructor. As a rule, copy functionality is best provided by constructors or factories. A notable exception to his rule is arrays, which are best copied with the clone method.
27 |
--------------------------------------------------------------------------------
/Chapter 3 - Methods Common to All Objects/Item14/Item14.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item15/Item15.md:
--------------------------------------------------------------------------------
1 | # Item 15: Minimize the accessibility of classes and members
2 | *Keywords: -*
3 |
4 | *Information hiding* (a.k.a encapsulation) is fundamental when it comes to designing components.
5 | Encapsulation;
6 | * Increases reusability by decoupling components
7 | * Increases testability
8 |
9 | Rule of thumb: “Make each class or member as inaccessible as possible!”
10 |
11 | Access modifier levels:
12 | * **private:** Accessible only from the top-level class where it is declared
13 | * **package-private (default level when you don’t declare any):** Accessible from any class in the package where it is declared.
14 | * **protected:** Accessible from subclasses of the class where it is declared and from any class in the package where it is declared.
15 | * **public:** Accessible from anywhere.
16 |
17 | Your default reflex should be to make all members private, if you find yourself setting package-private modifiers often, you should reconsider your design and try to see if another decomposition might yield classes that are better decoupled from one another.
18 |
19 | Instance fields of public classes should rarely be public.
20 |
21 | Since nonzero-length arrays are always mutable, it is wrong for a class to have public static final array field, or an accessor that returns such a field. If a class has such a field, they will be able to modify the contents of the array, and this is a frequent source of security holes. You can fix this by having a public static final List that is initialized with the private static final array using the Arrays.asList(array) method. Alternatively, a static method that returns an private static final array’s .clone()
22 |
23 | **TL;DR**
24 |
25 | * Keep accessibility of components at minimum
26 | * Do your best to design a minimal public API.
27 | * Public classes should have no public fields - except public static final fields that serve as a constant.
28 | * Ensure the objects referenced by public static final fields are immutable.
29 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item16/Item16.md:
--------------------------------------------------------------------------------
1 | # Item 16: In Public classes, use accessor methods, not public fields
2 | *Keywords: Degenerate class*
3 |
4 | Using accessor methods on a class that is accessible outside of its package helps preserving flexibility to change the class’s internal representation.
5 | If a class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields.
6 |
7 | **TL;DR:**
8 | Use getter/setters.
9 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item17/Item17.md:
--------------------------------------------------------------------------------
1 | # Item 17: Minimize Mutability
2 | *Keywords: -*
3 |
4 | - Immutable class: Class whose instances cannot be modified. All of the information contained in the instances is fixed for the lifetime of that instance.
5 |
6 | - Immutable classes are less prone to errors.
7 |
8 | Make a class immutable following these *5 rules*:
9 | 1. Don’t provide methods that modify the object’s state (a.k.a. mutators)
10 | 2. Ensure that the class cannot be extended. Prevent subclassing on this class.
11 | 3. Make all fields final.
12 | 4. Make all fields private. - prevent clients to mutate object’s fields. It is sometimes OK to have public final fields but it precludes that changing the internal representation in a later release.
13 | 5. Ensure exclusive access to any mutable components.
14 |
15 | In functional approach, methods do not modify the state of the instance that its being called on, rather it creates a new instance of the same type and assigns the calculated results and returns it.
16 | In imperative or procedural approach, we mutate the object by changing its state when we set the calculated values.
17 |
18 | * Immutable objects are inherently thread-safe, they require no synchronization.
19 | * Since a copy of an immutable object would never be the equivalent of the original, you should not provide a clone() method for an immutable class.
20 |
21 | Major disadvantage of immutable classes is that they require a separate object for each distinct value and creating that object can be costly. A solution to this problem is to use a mutable companion (like StringBuilder for the immutable String class).
22 |
23 | To make a class Immutable we need to permit it from being subclassed. Making a class final would solve this, but a nicer approach is to make all of its constructors private and adding a public static factory method.
24 |
25 | When implementing Serializable on an immutable class, you must provide an explicit readObject() or readResolve() method, or use the ObjectOutputStream.writeUnshared and ObjectOutputStream.readUnshared methods, otherwise an attacker could create a mutable instance of your class.
26 |
27 | **TL;DR:**
28 |
29 | * Immutable classes has many advantages and thread-safety is one of them.
30 | * Classes should be immutable unless there’s a very good reason to make them mutable.
31 | * Always make small value objects immutable.
32 | * If performance is an issue you should provide a mutable companion for your immutable class.
33 | * If a class cannot be made immutable, limit its mutability as much as possible.
34 | * Declare every field private final unless there’s a good reason to do otherwise.
35 | * Constructors should create fully initialized objects with all of their invariants established.
36 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item19/Item19.md:
--------------------------------------------------------------------------------
1 | # Item 19: Design and Document for inheritance or else prohibit it
2 | *Keywords: Serializable interface*
3 |
4 | The class must document its self-use of overridable methods. For each non-final public or protected method, the documentation must indicate which overridable methods the method invokes, in what sequence and how the results of each invocation affect subsequent processing. A class must document any circumstances under which it might invoke an overridable method.
5 |
6 | Writing what a method does and how does it do it in a comment violates the dictum that a good API doc. should describe *“what a given method does”* and not *“how it does”* it. This is an unfortunate consequence of the fact that inheritance violates encapsulation. However, to document a class so that it can safely be subclassed, you must describe implementation details that should otherwise be left unspecified.
7 |
8 | The only way to test a class designed for inheritance is to write subclasses. Three subclasses are usually sufficient to test an extendable class, one or more of these subclasses should be written by someone other than the superclass author. You must test your class by writing subclasses before you release it.
9 |
10 | Constructors must not invoke overridable methods, directly or indirectly. The superclass’ constructor runs before the subclass’ constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run and if the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.
11 |
12 | If `Cloneable` and `Serializable` is implemented in a class that is designed for inheritance you should be aware that similar reaction applies for clone and readObject methods since they both behave like constructor.
13 |
14 | You need to prohibit concrete classes that are not planned to be extended from being extended by declare classes final or make all the constructors private and add public static factories in place of constructors.
15 |
16 | **TL;DR**
17 |
18 | * If designing a class for inheritance, document all of its self-use patterns (invoking of all public/protected non-final overridable methods).
19 | * The documentation must indicate which overridable methods the method invokes, in what sequence and how the results of each invocation affect subsequent processing.
20 | * Constructors, `clone()`, `readObject()` methods must not invoke overridable methods directly or indirectly to prevent failures.
21 | * You should try to write **at least 3** subclasses to test your superclass for inheritance - one or more of them should be written by anyone but you.
22 | * Unless you know there is a real need for subclasses, prohibit inheritance by declaring yor class final or ensure there are no accessible constructors.
23 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item20/Item20.md:
--------------------------------------------------------------------------------
1 | # Item 20: Prefer Interfaces to Abstract Classes
2 | *Keywords: Default methods in Interfaces, Template Method Pattern*
3 |
4 | Abstract classes and interfaces are two mechanisms to define a type that permits multiple implementations.
5 |
6 | A major difference is that to implement the type defined by an abstract class, a class must be a subclass of the abstract class. However, a class can implement any interface it requires, no matter where it stands in the hierarchy.
7 |
8 | Interfaces are ideal for mixins. A mixin is a type that a class can implement in addition to its “primary type” to declare that it provides some optional behavior. For example, Comparable is a mixin interface that allows a class to declare that its instances are ordered.
9 |
10 | Interfaces allow for the construction of nonhierarchical type frameworks. Let’s say `Singer` and `Songwriter` interfaces adds (mixins) some functionality to `Person` class. But a `Person` can also be a Singer and a Songwriter right? Interfaces permits us to do this by adding `implements Singer, Songwriter`. If we used abstract classes we would not be able to achieve this kind of flexibility.
11 |
12 | Combine the advantages of interfaces and abstract classes by providing an `abstract skeletal implementation class` to go with an interface. The interface defines the type, provides some default methods, while the skeletal implementation class implements the remaining non-primitive interface methods atop the primitive interface methods. Extending a skeletal implementation takes most of the work out of implementing an interface. This is called the Template Method pattern.
13 |
14 | Skeletal Implementation classes are called `AbstractInterface` where interface is the name of the interface they implement: AbstractCollection (implements Collection interface).
15 |
16 | **TL;DR**
17 |
18 | * An interface is generally the best way to define a type that permits multiple implementations.
19 | * Interfaces, on the other hand, does not require a hierarchical organization that restricts the programmers that uses it.
20 | * You can combine abstract classes and interfaces (with some default methods) by defining Skeletal Implementation classes.
21 | * You should consider providing a good documentation with your Skeletal classes.
22 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item21/Item21.md:
--------------------------------------------------------------------------------
1 | # Item 21: Design interfaces for Posterity
2 | *Keywords: -*
3 |
4 | Prior to Java 8, when you add a new method to an interface, you would break existing implementations since they do not have that method. In Java 8, the default method construct allowed us to do that with some risk.
5 |
6 | Java 8’s default method includes a default implementation for all classes that uses it, risk here is that these methods are injected into existing implementation without their owners/authors knowing that.
7 |
8 | Keep in mind that, it is not always possible to write a default method that maintains all variants of every conceivable implementation. (removeIf method fails for Apache’s SynchronizedCollection)
9 |
10 | Using default methods to add new methods to existing interfaces should be avoided unless the need is critical.
11 |
12 | Also keep in mind that, default methods are not designed to support removing methods from interfaces or changing the signature of existing methods. Neither of these changes are possible without breaking the existing clients.
13 |
14 | Before Java 8 interfaces were designed in such a way that there was no expectance of adding a new method later on.
15 |
16 | Before releasing a new interface, multiple programmers should implement it and you should try to implement it at least in 3 different ways.
17 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item22/Item22.md:
--------------------------------------------------------------------------------
1 | # Item 22: Use Interfaces only to Define Types
2 | *Keywords: -*
3 |
4 | Interfaces should be defined to say something about the class that implements it, what the clients can do with its instances.
5 | When a class implements an interface it serves as a type that can be used to refer to instances of that class.
6 |
7 | Constant interface pattern is a poor use of interfaces, where you declar `static final` constants to use across your code. Instead you could create a class, that is not instantiable and export your `static final`s from there.
8 |
9 | Note: In **Java 7**, underscore (_) is introduced for numeric literals, that has no effect on the number itself and allows to have a better readability (suggested if the literal has 5 or more digits).
10 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item23/Item23.md:
--------------------------------------------------------------------------------
1 | # Item 23: Prefer class hierarchies to tagged classes
2 | *Keywords: -*
3 |
4 | A class whose instances come in two or more flavors based on a (tag) field is a vastly inferior implementation against class hierarchy.
5 |
6 | A `Figure` class, for example, may have a field `shape` in it that can get one of the two enum values `RECTANGLE, CIRCLE`.
7 |
8 | Shortcomings of tagged classes;
9 | * Cluttered with enum/tag fields, switch cases.
10 | * Readability is down, since multiple implementations are in the same class.
11 | * Memory footprint is increased because instances are burdened with irrelevant fields belonging to other flavors.
12 | * Constructors must set the tag field and initialize the right data fields without the help of the compiler.
13 | * Fields can not be made `final` unless constructors initialize irrelevant fields - which is even more boilerplate.
14 | * Adding a new flavor will result in adding a new `case` to every `switch` statement.
15 |
16 | So, yes, tagged classes are verbose, error-prone and inefficient.
17 |
18 | “A tagged class is just a pallid imitation of a class hierarchy.”
19 |
20 | To transform a tagged class into a class hierarchy we could make the `Figure` an abstract class with all the mutual methods for both flavors are declared inside as `abstract` and then create a concrete class for each of these flavors `Rectangle` and `Circle` which extends `Figure`. Inside these concrete classes we could then declare and use only the required fields and implement the abstract methods that Figure requires.
21 |
22 | Advantages of class hierarchies:
23 | * Code is simpler, no boilerplate.
24 | * No irrelevant data field in concrete classes, only the necessary ones are added in each class.
25 | * All fields are final.
26 | * Compiler ensured that all required methods (abstract methods) are implemented for each flavor.
27 | * There’s a separate data type for every flavor that contains some basic data with it (Rectangle, Circle, Square...)
28 |
29 | **TL;DR**
30 |
31 | If you are tempted to write a class with an explicit tag field, think about whether the tag could be eliminated and the class replaced by a hierarchy. And when you encounter such class, consider refactoring it.
32 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item24/Item24.md:
--------------------------------------------------------------------------------
1 | # Item 24: Favor static member classes over non-static
2 | *Keywords: -*
3 |
4 | A static member class is the simplest kind of nested classes. It’s simply a class declared inside another class and has access to all of the enclosing class’s members, even the private ones.
5 |
6 | One common use of a static member class is a public helper class. For example, an enum describing possible operations supported by a calculator. The `Operation` enum declared inside `Calculator` class a public static member class.
7 |
--------------------------------------------------------------------------------
/Chapter 4 - Classes and Interfaces/Item25/Item25.md:
--------------------------------------------------------------------------------
1 | # Item 25: Limit Source Files to a Single Top Level Class
2 | *Keywords: -*
3 |
4 | Do not ever define to Top Level classes/interfaces in a single file;
5 | - You could conflict with yourself,
6 | - You make it harder for your readers to understand/follow your code.
7 |
8 | If you define two classes in two different source files, which you compiled first will affect the behavior of your code.
9 | If you really need to do that consider using `Static Member Classes` and put them in the same class as we discussed in [Item 24](https://github.com/recepinanc/effective-java-notes/blob/master/Chapter%204%20-%20Classes%20and%20Interfaces/Item24/Item24.md).
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Effective Java Notes
2 |
3 | This is a repository that I will share my notes as I read Effective Java. I am using the 3rd Edition of Effective Java. The book consists of 90 Items in total. I try to do my best to share at least an Item a week.
4 |
5 | ----
6 |
7 | # Repo Structure
8 |
9 | ## Items
10 |
11 | Every *chapter* will have its own directory and the **"Items"** will be located under each chapter.
12 |
13 |
14 | ## Keywords
15 |
16 | **"Keywords"** directories contain somewhat related topics to each chapter. It is something that I made up to take some notes on the concepts that I wanted to learn and remember later on.
17 |
18 | # Contribution
19 |
20 | All contributions are welcome. This repository is open for anyone who wants to correct any misunderstandings, add new perspectives and fixes.
21 |
--------------------------------------------------------------------------------