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
static
type 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
static
nested 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 ReferenceType
lower 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
null
or is of different type, the objects are not equal.If
this
and 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
a
andb
, wherea
is located to the left ofb
, the conditiona.compareTo(b) <= 0
is true.
Comparable
providescompareTo()
method which allows comparing an object with other objects of the same type.compareTo
should be consistent with theequals
method.
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.naturalOrder
returns aComparator
of the type that comparesComparable
objects in the natural order. You will get compilation error ifComparable
interface is not implemented.Comparator.reverseOrder
comparesComparable
objects in reverse natural order.reversed
when called onComparator
return a newComparator
which is reverse of the givenComparator
Comparator.comparing
thenComparing
Note
reversed()
method will reverse the whole chain of preceding comparators. Scope can be limited using parenthesis.
Comparator vs Comparable#
Comparable
defines the natural order of a class implementing it, perfect where objects have natural order e.g., primitive types, ComplexNumber etc…Comparator
allows for customizing the ordering process.Comparator
can also be useful when we don’t have access to source code of class for implementingComparable
.With
Comparator
multiple can be joined to create a complex one or extractComparable
sort 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
final
andprivate
to prevent external modification.Prevent method overriding in subclasses by declaring the class as
final
or usingprivate
constructors 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