int[] emptyArray = new int[0];
, but this won't even compile int[] compileError = new int[];
Execution Order:
1.Static block(s) โ Executed only once when the class is loaded (before objects are created).
2.Instance block(s) โ Executed before the constructor when an object is created.
3.Constructor(s) โ Executed after instance blocks when an object is created.
class Main {
static {
System.out.println("1. Static Block");
}
{
System.out.println("2. Instance Block");
}
Main() {
System.out.println("3. Constructor");
}
public static void main(String[] args) {
System.out.println("main Method Starts");
Main obj1 = new Main();
Main obj2 = new Main();
}
}
1. Static Block
main Method Starts
2. Instance Block
3. Constructor
2. Instance Block
3. Constructor
Execution Order in Inheritance:
When a subclass B extends a superclass A, the order of execution is:
- Static blocks of superclass (A)
- Static blocks of subclass (B)
- Instance blocks of superclass (A)
- Constructor of superclass (A)
- Instance blocks of subclass (B)
- Constructor of subclass (B)
class A {
static {
System.out.println("Static Block of A");
}
{
System.out.println("Instance Block of A");
}
A() {
System.out.println("Constructor of A");
}
}
class B extends A {
static {
System.out.println("Static Block of B");
}
{
System.out.println("Instance Block of B");
}
B() {
System.out.println("Constructor of B");
}
}
class Main {
public static void main(String[] args) {
System.out.println("main Method Starts");
A a = new A();
System.out.println("----------------------");
B obj1 = new B();
System.out.println("----------------------");
B obj2 = new B();
}
}
main Method Starts
Static Block of A
Instance Block of A
Constructor of A
----------------------
Static Block of B
Instance Block of A
Constructor of A
Instance Block of B
Constructor of B
----------------------
Instance Block of A
Constructor of A
Instance Block of B
Constructor of B
Marking a class as final in Java means that it cannot be subclassed (extended). This is done for several reasons e.g. Ensuring that the class's behavior remains as designed.
java.lang.String, java.lang.Integer, java.lang.Double, java.lang.Boolean (All wrapper classes) etc. are final classes in JDK.
public class Main {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = new String("Hello");
String s3 = s1;
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // true
System.out.println(s1 == s3); // true
}
}
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> immutableList = List.of("banana", "apple", "cherry");
// Trying to sort the immutable list, will throw java.lang.UnsupportedOperationException
// Collections.sort(immutableList);
// Trying to add element to a immutable list, , will throw java.lang.UnsupportedOperationException
// immutableList.add("orange");
}
}
Immutable empty collections are often returned from methods when there is no data, rather than returning null, its better to return empty immutable collection. Returning empty collection is safe way to guard against NullPointerException, any by returning immutable empty collection we can enfore that the collection can not be modified.
Collections.emptyList() or Collections.<String>emptyList()
Collections.emptySet() or Collections.<Integer>emptySet()
Collections.emptyMap() or Collections.<String,Integer>emptyMap()
Collectors.partitioningBy() is a collector in Java used to partition elements of a stream into two groups based on a given predicate. The result is a Map<Boolean, List> where:
true key contains elements that satisfy the predicate.
false key contains elements that do not satisfy the predicate.
import java.util.Map;
import java.util.stream.Collectors;
import java.util.List;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Partition numbers into even and odd
Map<Boolean, List<Integer>> partitioned = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println("Even numbers: " + partitioned.get(true));
System.out.println("Odd numbers: " + partitioned.get(false));
}
}
The default implementation of equals method is, two objects are same only if both refer to same instance.
The default implementation is the most discriminating possible equivalence relation on objects, most of the time you would want two objects having exact same values of some properties to return true, even if they are two distinct instances.
public boolean equals(Object obj) {
return (this == obj);
}
Returns true if the given object represents a String equivalent to this string, false otherwise.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
}
Compares this object to the specified object. The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
The exact algorithm depends on the JVM implementation, the returned hash code is typically based on the memory address of the object.
The default hashCode() implementation, does not guarantee different hash codes for two different objects.
Calling hashCode() on the same object multiple times must return same hash code.
If for two objects equals() method returns true, means they match, then calling hashcode() on those two objects should return exact same value.
import java.time.Instant;
public class Test {
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println("Now : "+now); // Now : 2024-11-08T16:10:02.367923Z
long millis = now.toEpochMilli();
System.out.println("Milis from Epoch :"+millis);
// Milis from Epoch :1731082202367
}
}
java.util.ArrayDeque
doesn't allow null while java.util.LinkedList
does allow adding null.
int[] arr1 = {5, 6, 3, 2, 10};
int[] arr2 = arr1.clone();
System.out.println("Arr 2 : " + Arrays.toString(arr2)); // {5, 6, 3, 2, 10}
int[][] arr3 = {{1, 2, 3}, {4, 5, 6}};
int[][] arr4 = arr3.clone();
for(int[] nums : arr4)
System.out.println("Arr 4 : " + Arrays.toString(nums)); // {{1, 2, 3}, {4, 5, 6}}
import java.util.*;
public class Test {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1, "one"); map.put(3, "three");
map.put(2, "two"); map.put(5, "five");
map.put(6, "six"); map.put(4, "four");
for(int key : map.keySet())
System.out.print(key+" , "); // the output order can't be guaranteed
// 1 , 2 , 3 , 4 , 5 , 6 ,
}
}
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<String,Integer> map = Map.of("one", 1, "two", 2, "three", 3);
map.forEach((k,v) -> System.out.println(k + "=" + v));
// two=2
// three=3
// one=1
}
}
import java.util.*;
public class Test {
public static void main(String[] args) {
Map<Integer,String> map = new LinkedHashMap<>();
map.put(1, "one"); map.put(3, "three");
map.put(2, "two"); map.put(5, "five");
map.put(6, "six"); map.put(4, "four");
for(int key : map.keySet())
System.out.print(key+" , ");
// 1 , 3 , 2 , 5 , 6 , 4 ,
}
}
import java.util.*;
class Main {
public static void main(String[] args) {
Map<Integer, List<Integer>> map = new HashMap<>();
map.put(9, Arrays.asList(1, 4));
map.put(2, new ArrayList<Integer>());
for (int key : map.keySet()) {
if (map.get(key).size() == 0) {
map.remove(key);
}
}
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1606)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1629)
at Test/net.mahtabalam.Main.main(Main.java:15)
import java.util.*;
class Main {
public static void main(String[] args) {
Map<Integer, List<Integer>> map = new HashMap<>();
map.put(9, Arrays.asList(1, 4));
map.put(2, new ArrayList<Integer>());
Iterator<Integer> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
Integer key = iterator.next();
if (map.get(key).size() == 0) {
iterator.remove();
}
}
System.out.println(map); // {9=[1, 4]}
}
}
Read operations are guaranteed not to be blocked or block a key.
Write operations are blocked and block other writes at the map Entry level.
These two ideas are important in environments where we want to achieve high throughput and eventual consistency.
HashTable and Collections.synchronizedMap collections also implement concurrency for reads and writes.
However, they are less efficient because they lock the entire collection
instead of locking just the Entry at which the thread is writing.
On the other hand, the ConcurrentHashMap class locks at a map Entry level.
Thus, other threads are not blocked from writing on other map keys.
Therefore, to achieve high throughput, ConcurrentHashMap in multi-thread environments is a better option
when compared to HashTable and synchronizedMap collections.
list = [[1,2], [3], [4,5] , [6]]
Collections.reverse(list)
// [[6], [4,5], [3], [1,2]]
Integer.toBinaryString(2) => 10
Integer.toBinaryString(-2) => 11111111111111111111111111111110
int num5 = 5;
int num8 = 8;
int or = 5 | 8;
int and = 5 & 8;
System.out.println("5 | 8 =" + or); // 13
System.out.println("5 & 8 =" + and); // 0
String s = "a";
System.out.println(s.substring(1)); => "" (empty string)
System.out.println(s.substring(2)); => StringIndexOutOfBoundsException
String s = "a" + "hello".charAt(1);
System.out.println(s); //ae
StringBuilder sb = new StringBuilder();
sb.append('a');
sb.append(1);
sb.append("ABC");
System.out.println(sb); // a1ABC
List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);
list.add(1, 5);
System.out.println(list); // [1, 5, 2, 3]
List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);
list.set(1, 5);
System.out.println(list); // [1, 5, 3]
import java.util.*;
class Main {
class Employee {
int id;
Employee(int id){
this.id = id;
}
}
public static void main(String[] args) {
new Main().check();
}
private void check() {
Employee e1 = new Employee(1);
Employee e2 = new Employee(1);
Set<Employee> set = new HashSet<>();
set.add(e1);
System.out.println(set.contains(e2)); // false
set.add(e2);
Employee e3 = e2;
System.out.println(set.contains(e3)); // true
}
}