Core Java#
Nested Classes#
A nested class is a class that is defined within another class.
Inner class: A non-static type defined at the member level of a class.
Static nested class: A
statictype defined at the member level of a class.Local class: A class defines within a method body.
Anonymous class: A local class without a name.
Interfaces and enums can be declared as both inner classes and
staticnested classes, but not as local or anonymous classes.
Fail-fast and Fail-safe (weakly consistent) Iterators#
Fail-fast: Fail-fast iterator throws ConcurrentModificationException when any change has taken place to the collection.
Fail-safe: If a collection is modified concurrently with an iteration, the guarantees of what the iteration sees are weaker (may be it is working on a copy and don’t see the changes)
Fail-fast iterators are typically implemented using a volatile counter on the collection object.
When the collection is updated, the counter is incremented.
When an Iterator is created, the current value of the counter is embedded in the Iterator object.
When an Iterator operation is performed, the method compares the two counter values and throws a CME if they are different.
By contrast, weakly consistent iterators are typically light-weight and leverage properties of each concurrent collection’s internal data structures. There is no general pattern.
Ref.: https://stackoverflow.com/questions/17377407/what-are-fail-safe-fail-fast-iterators-in-java
Generics#
Allowing a type or method to operate on objects of various types while providing compile-time type safety. e.g., The Java Collection Framework supports generics to specify the type of objects stored in a collection instance.
<T extends A & B & C>
A can be a class or interface. B & C must be interface
Invariance
class Book {}
class Album extends Book {}
List<Album> albums = new ArrayList<>();
List<Book> books = albums; // compile-time error
// called invariance as container List<Book> does not extend List<Album>
// using wildcard will be helpful here
List<? extends Book> albumBooks = albums;
unbounded wildcards
?upper bounded wildcards
? extends ReferenceTypelower bounded wildcards
? super ReferenceType
Get and Put Principle
Use upper bounded wildcards when you only get values.
Use lower bounded wildcards when you only put values.
User unbounded wildcards when you get and put values.
Type Erasure#
To support backward compatibility with previous Java versions, information about generic types is erased by the compiler. The transformation process is called type erasure.
List<Integer> integers = new List<>()will becomeList integers = new List()
hashCode() and equals()#
Overriding equals()#
If the other object is
nullor is of different type, the objects are not equal.If
thisand other object have the same reference, the objects are equal.If all the selected fields are equal, the objects are equal, otherwise, the objects are not equal
class Person {
private String firstName;
private String lastName;
private int age;
// constructor, getters and setters
@Override
public boolean equals(Object other) {
/* Check this and other refer to the same object */
if (this == other) {
return true;
}
/* Check other is Person and not null */
if (!(other instanceof Person)) {
return false;
}
Person person = (Person) other;
/* Compare all required fields */
return (
age == person.age &&
Objects.equals(firstName, person.firstName) &&
Objects.equals(lastName, person.lastName)
);
}
}
Using java.util.Objects.equals(obj1, obj2) can avoid NullPointerException
Overriding hashCode()#
If hashCode() is not overridden, the class cannot be used correctly in collection that applies hashing mechanism (HashMap, HashSet, HashTable).
Since Java 7, we have an java.util.Objects.hash(Object... objects) utility method for hashing e.g., Objects.hash(firstName, lastName, age)
If two objects are equal, they MUST have same hash code.
If two objects have same hash code, they do NOT have to be equal too.
Comparable#
A sequence of data has the natural ordering, if for each 2 elements
aandb, whereais located to the left ofb, the conditiona.compareTo(b) <= 0is true.
ComparableprovidescompareTo()method which allows comparing an object with other objects of the same type.compareToshould be consistent with theequalsmethod.
Implementing the compareTo method
Return:
A positive integer (e.g., 1), if the current object is greater
A negative integer (e.g., -1), if the current object is less
Zero, if they are equal
Example of how the compareTo method is implemented in Integer class.
@Override
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
Comparator#
Comparator<T> is a generic interface that has a single abstract method (SAM) compare and few non-abstract methods, which can define rules for comparing Java objects.
compare method should return:
0 if both arguments are equal
positive number if first argument is greater than second one
negative number if first argument is less than second one
class PersonAgeComparator implements Comparator<Person> {
@Override
public int compare(Person person1, Person person2) {
if (person1.getAge() < person2.getAge()) {
return -1;
} else if (person1.getAge() == person2.getAge()) {
return 0;
} else {
return 1;
}
}
}
Since Comparator has only a single abstract method (SAM) and therefore is a functional interface, Comparator instance can be created using lambda expression.
Comparator<Person> personAgeComparator = (p1, p2) ->
Integer.compare(p1.getAge(), p2.getAge());
Utility methods
[ ] TODO: add examples
Comparator.naturalOrderreturns aComparatorof the type that comparesComparableobjects in the natural order. You will get compilation error ifComparableinterface is not implemented.Comparator.reverseOrdercomparesComparableobjects in reverse natural order.reversedwhen called onComparatorreturn a newComparatorwhich is reverse of the givenComparatorComparator.comparingthenComparing
Note
reversed() method will reverse the whole chain of preceding comparators. Scope can be limited using parenthesis.
Comparator vs Comparable#
Comparabledefines the natural order of a class implementing it, perfect where objects have natural order e.g., primitive types, ComplexNumber etc…Comparatorallows for customizing the ordering process.Comparatorcan also be useful when we don’t have access to source code of class for implementingComparable.With
Comparatormultiple can be joined to create a complex one or extractComparablesort keys.
Immutable#
An object is considered immutable if its state cannot change after it is constructed.
Weak immutability is when some fields of an object are immutable and others are mutable. Strong immutability is when all fields of an object are immutable
A strategy for defining immutable objects
Avoid “setter” methods that change field values or referenced objects.
Make all fields
finalandprivateto prevent external modification.Prevent method overriding in subclasses by declaring the class as
finalor usingprivateconstructors with factory methods for instance creation.For fields referencing mutable objects:
a. Do not provide methods that alter these mutable objects.
b. Avoid sharing or storing external mutable object references. Instead, use copies of these objects for internal storage and method returns
https://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html