Everything has to be inside a class in .java
source file. Filename must match the “entrypoint” classname (incl. case), and it ofcourse must have a main()
method inside.
public
and its name must match the filenameprivate
or protected
, it leads to compiler errorstatic
, it leads to compiler error. Nested classes can be static
though.public static final void main()
// only "final" is optional here
The argument has to be a String
array. So all of the below works:
String args[]
String foobar[]
String[] args
String... args
static
because it is called by JVM using class namestatic
from it will not cause any compile-time exception but cause NoSuchMethodError
error on runtimemain()
can be overloaded just like any other method but only String[]
one will be called by the JVMpublic static void main(String args[]){
args[0] // first argument (not program name) = 8
args[1] // second argument = "foobar"
}
/*
$ java Hello 8 foobar
*/
If we don’t pass required number of arguments: ArrayIndexOutOfBoundsException
package foo;
import java.util.*;
class Hello{
}
java.lang.*
is always implicitly imported regardlesspackage
declarations, then they need not import
each other explicitly as it’s trivialimport static
to import static methods and fields of a class (to access without instantiation)import java.nio.*
) only imports classes from the current package and not from children pacakages toojava.util.Date
and java.sql.*
both are imported, then Date
is fetched from util
packageimport java.util.*;
import java.sql.*; // Date will lead to error
import java.util.Date;
import java.sql.Date; // ambiguous still
java.util.Date dateVar;
java.sql.Date dbDateVar; //removes ambiguity
Ordering Rules:
package
declaration has to be first non-comment in a source fileimport
always comes after package
declarationNo nesting allowed.
// single line
/* block */
/**
* documentation
* style
* @author john doe
*/
data_type name = init_value;
$
, etc…_
) isn’t a valid identifier name (unlike C/C++) (this changed in 2024 with Java 22)final
variablesint x;
// no errors unless the variable is accessed without initialization
// all paths leading to access must initialize (Java is smart to detect this) or else error
final int a; // declaration
a = 5; // initialization
More on their initialization here
Variable Defaults:
Local -> no defaults (no garbage values), declaration only if value not assigned inline
non-final Instance -> default value assigned by compiler
non-final Class/static -> default value assigned by compiler
final Instance/Class -> no defaults, must be initialized before constructor finishes!
Do note that the defaults on non-final instance and class/static variables are not by constructor but by compiler itself. They are assigned default values even before any constructor finishes executing!
class A {
// inside some method
new B();
}
class B {
int x; // instance member
B(){
System.out.println(x); // prints 0; even before constructor has finished
}
}
var name = init_value; // type is implicitly inferred
var
variables inline, and once type is inferred, we can’t change itnull
but can be put in latervar
isn’t a reserved keyword and can be used as an identifier (weird!). We can’t have types (classes, enum, interface) with name “var”.var
is ONLY used for local variable type inference. Anywhere else it is used (method params, instance variables, constructors), it is errorvar
can’t be used in multiple-variable assignmentsvar a = 3, b = 5; //invalid
var
is known at compile-time and type cannot be changed ever after thatvar
can be used in Lambda Expression variables thoughFoobar foobar = (var a, var b) -> a < b;
int short long byte char
float double
boolean
// there is no explicit "unsigned" specifier for primitives in Java
// char is unsigned; other integral types are not
int
is 4 Bytesfloat
is 4 Byteschar
is unsigned Unicode (superset of ASCII), encoded as UTF-16 so one char can take one or two bytes. It is an integral type.boolean
is not convertible to int
and vice-versa, we cannot even use ==
with int
and boolean
values. Takes values true
or false
. Size is undefined and depends on JVM.while(1){ } // not allowed; expected boolean
55L // long -- l/L
0123 // octal
0xFBB // hex -- x/X (A to F case-insensitive)
0b1011 // binary -- b/B
0.33F // float -- f/F
1e4 // double
'a' '❤️' // chars
"foobar" // string
long n = 9999999999;
// it is compiler error unlike in C++ since literal is int and is overflowed
long n = 9999999999L; // solves the above issue
// underscores are allowed in all numeric types to make them easier to read
int million1 = 1000000;
int million2 = 1_000_000;
int binary_num = 0b0001_0101;
// underscore can't be at beginnning or end of literal or on either sides of a decimal point (.)
float exp = 1.010_101;
// multiple underscores together is valid; useless though
int eleven = 1__________1;
Logical/Bitwise operators:
& | ^ // can be applied to both boolean and integer types; works the same way as conditionals with boolean type: && ||
~ // only for integer types
Logical operators are not short circuited whereas Conditional operators are.
boolean a = false;
boolean b = (true) | (a = true); // logical AND (&)
System.out.println(a); // true
boolean a = false;
boolean b = (true) || (a = true); // conditional AND (&&)
System.out.println(a); // false
double x = 99; // valid; smaller to larger type cast is implicit
long y = x; // invalid; larger to smaller cast can lead to loss of data
float z = 9.0; // invalid; must be 9.0f
double a = 9; // implicit cast to double from int
int b = (int) a; // explicit cast from double to int
int
; this is to prevent numeric overflowshort x = 5;
byte y = 5;
x + y; // int
Another example of Integral Promotion:
System.out.println('b' + 'i' + 't'); // prints 319; ASCII addition result
~
operator is same as in C/C++. To find the bitwise complement of a number, multiply it by negative one and then subtract one.
System.out.println(~8); // -9; use -(n+1) formula
// it is supposed to perform 1's complement on the operand
Strings are immutable in Java
Advantages of immutability include:
All strings literals (anything within ""
) are cached in an area in Heap memory called “String Constant Pool” or “String Intern Pool” for performance optimization.
When we define literal without new
, we either get old ref or a string pool entry is created and we get it’s new ref.
When we create using new String()
, we force Java to create a new object regardless of any prior pool entry.
The sneaky thing is when we are allocating space using new
, we end up using literal (""
) in constructor call and a String literal ALWAYS gets placed in pool. So, its because of the String ""
literal use that we get two objects created in memory and not by virtue of using new
.
Reference: https://stackoverflow.com/a/66866401
// how many string literals does the following statement create internally?
String a = new String("A");
// 1 literal - if "A" exists in pool already
// 2 literal - if "A" doesn't exist in pool already
// compare that to simple literal
String b = "B";
// it can create 0 or 1 depending on existance in pool
// another example
String s = new String(new char[]{'a','b','c'});
// only 1 String literal is created in heap ("abc"), none in pool
String Representation: Since Java 9, a new representation is provided, called Compact Strings. This new format will choose the appropriate encoding between char[]
and byte[]
depending on the stored content.
The internal array representation has 65536 elements and String Pool can go OutOfMemory since it not eligible for Garbage Collection. The memory is freed only when JVM is restarted.
String a = "foo"; // stored in pool
String c = "foo"; // points to a only (a == c is true)
String b = new String("bar"); // stored in heap and b points to it, literal "bar" is also placed in pool
String d = b.concat("tender"); // d is in string pool (since "new" is not used)
// text block Strings
String d = """
foobar""";
/*
Rules:
1. Must have a new line after start """
2. \s puts two spaces
3. line splicing using \ is there
4. \" and \""" are available
5. escape characters work inside this
6. spaces at end of a line are ignored
*/
// Intern a string to copy it to Pool from String Object in heap if it doesn't exists there already and return it's reference, otherwise old ref from pool is returned
String internedStr = str.intern();
Once we have a String literal in pool or heap, we can’t “edit” (modify) it in-place.
String a = new String("foobar");
a = a.substring(0, 3) + "d";
// Literals created in pool: "foobar", "food" (new literal)
String b = "foo";
b = b + "bar";
// Literals created in pool: "foo", "foobar" (new literal)
a.equals(b);
c.equalsIgnoreCase(d);
// Avoid using "==" for string comparison since it compares object references and not actual value
// Naturally, only interned strings can be compared with ==
For-Each loop doesn’t work on String
object as it doesn’t implement the Iterable
interface.
The below works in C++ but not in Java:
String str = "foobar";
for(char c : str){ // compiler-error; Foreach not applicable to type 'java.lang.String'
// logic
}
// fixed
String str = "foobar";
for(char c : str.toCharArray()){
// logic
}
import java.lang.*;
new String("foobar");
new StringBuffer("foobar");
new StringBuilder("foobar");
StringBuffer
is slower but thread-safe since it is synchronized.StringBuilder
is faster but not thread-safe.String
can be casted to StringBuffer
or StringBuilder
using new
.toString()
can be performed on StringBuffer
or StringBuilder
to cast to immutable String
import java.util.*;
StringTokenizer();
StringJoiner();
Integer.parseInt(str) // returns int; takes Strings only; slower
Integer.valueOf(str) // returns Integer; takes both String and intgeral types; faster
String.valueOf(n) // n is primitive or any other type
x.toString() // where x is of type Integer
Injecting variable values into a string is called “String Interpolation”.
// + operator
name = "Heisenberg"
age = 69
System.out.println("My name is " + name + " and I am " + age + "years old.");
// String.format() method
name = "Heisenberg"
age = 69
System.format("My name is %s and I am %d years old.", name, age);
// using StringBuilder
// MessageFormat.format() method
Other programming languages like Python and Javascript make it much easier to interpolate strings.
switch
supports the following types:// all integer literal types:
int short long char byte enum
// and their wrapper classes: Short Integer Long Byte Char
String
var // if type is one of the supported types
// variables can be used but they must be "final"
switch
labels and expressions and case labels can be String
here too (unlike C/C++) and they have to be compile time constant//combining case values
case 1, 2:
case 1:
case 2: // old way
// switch expressions, notice semi-colon (;) at last
var result = switch(day) {
case 0 -> "Sunday";
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
default -> "Invalid value";
};
// switch expressions must handle all possible input values so "default" case becomes mandatory all the time!
// yield keyword: used to supply value incase we want to execute logic in case output block
var result = switch(num) {
case 0 -> "Zero";
case 1 -> "One";
case 2 -> "Two";
default -> {
System.out.println("Number not allowed."); // executing logic
yield "Invalid"; // must be last statement of the block
// otherwise unreachable code compiler-error
}
};
System.exit(0)
can be used to indicate successful termination, it even skips finally
block execution
for-each loop
int [] arr = new int[]{1, 2, 3, 4, 5};
for(int i : arr){
System.out.printf("%d ", i);
}
// 1 2 3 4 5
break;
break LABEL;
continue;
continue LABEL;
import java.util.*;
Scanner in = new Scanner(System.in);
in.nextInt(); // int
in.nextFloat(); // float
in.next(); // string
in.nextLine(); // full line until '\n'
in.close();
Scanner
is not thread-safe (no sync) wheareas BufferedReader
is.Scanner
buffer size is 1 KB wheareas BufferedReader
buffer size is 8 KB. So BufferedReader
is good for handling larger inputs.BufferedReader
is a bit faster than Scanner
.InputStreamReader r = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(r);
System.out.println("Enter your name");
String name = br.readLine();
System.out.println("Welcome " + name);
System.out.print()
System.out.println()
System.out.printf() // works mostly like C's printf()
String.format() // to store in another String, formatting works like printf
Available for all data types. Advantages include:
java.util
methods take in wrapper objects as argumentsCollection
framework deals with wrapper objectsBigInteger
and BigDecimal
provide huge ranges and utility methodsObjects of all primitive wrapper classes are immutable!
// 1. new
Integer n = new Integer(33); // deprecated way
// 2. valueOf()
Integer n = Integer.valueOf(33); // better way
// Points to old object if it already exists in constant pool
// 3. Autoboxing
Integer n = 5;
// unboxing
int num = n;
// Wrapper to primitive (explicitly; no unboxing)
int n = num.intValue();
// autoboxing and promotion can't happen in one go
Long l = 8; // compiler error
// promotion = int literal 8 to long
// autoboxing = long to Long
// autoboxing and unboxing null can lead to surprises
Character c = null; // valid since c is ref variable and it can store null ref
char ch = c; // NullPointerException; since we try and call method on c internally to get primitive out of it
// methods calls; same here
void foobar(Long x){ }
foobar(8L); // valid
foobar(9); // invalid
int[] arr;
Integer[] arrInt;
// both are different
Just like the String
class is immutable, wrapper classes like Integer
too are immutable and always Pass-by-Value (everything in Java is).
public static void main(String[] args) {
Integer n = 5;
increment(n);
System.out.println(n);
}
public static void increment(Integer n){
n = n + 6; // re-assignment of ref variable
}
// Output: 5
java.util.Object
classCloneable
and java.io.Serializable
interfaces0
or false
or null
int arr[];
int [] arr;
int arr[] = new int[5]; //init list not allowed; sets default values
int arr[] = new int[]{1, 2, 3}; // anonymous array
int arr[] = {1, 2, 3}; // still allocated in heap
int arr[] = new int[3]{1, 2, 3}; // compiler error; both size and initilizer can't be specified
//muti-dimensional arrays
int arr[][]; // 2D
int[][][] arr; // 3D
int[] arr[]; // 2D
// Range checking is strict unlike C & C++ and often results in RUNTIME Exceptions -
ArrayIndexOutOfBoundsException
NegativeArraySizeException
// in method parameters
void foobar(int[] arr){ }
// length of an array
arr.length // and not arr.length()
// multiple-declarations
int [] a, b; // two array ref variables
int a[], b; // one array ref variable, one primitive int
//utility methods
Arrays.sort()
Arrays.compare()
//etc...
Math.min()
Math.max()
Math.round()
Math.ceil()
Math.floor()
Math.pow()
Math.random()
// etc...
import java.util.*;
Date d = new Date(); // 1st way
Calendar c = Calendar.getInstance(); // 2nd way
c.get(Calendar.DAY_OF_WEEK)
c.get(Calendar.DAY_OF_YEAR) // etc...
import java.text.SimpleDateFormat;
import java.util.Date;
SimpleDateFormat ft = new SimpleDateFormat("dd-MM-yyyy");
String str = ft.format(new Date()); // 07-05-2022
Frees up memory in heap used by dereferenced objects and objects which has gone out-of-scope. Run by System.gc()
but nothing is guaranteed. When the garbage collection is triggered by the JVM isn’t guaranteed either.
Mark and Sweep Algorithm - identify and mark objects to clean, then sweep through and free up space.
Types of garbage collectors in Java:
Generational ZGC (Java 21) - based on generational hypothesis acc to which young objects are more likely to die first. Logically separates the heap into two generations: a young generation and an old generation. When an object is allocated, it is initially placed into the young generation, which is frequently scanned. If an object survives long enough, it will be promoted to the old generation.
Stopping everything is called stopping-the-world (STW) or pausing (GC Pause). It halts all the program threads. Stopping the world ensures that no one accesses or changes memory during a GC run.
References:
Called automatically when Garbage Collector is called by the JVM.
public void finalize() {
// we can do anything here
}