Java Material
Java Material
In Java, all objects are dynamically allocated on Heap. This is different from C++ where objects
can be allocated memory either on Stack or on Heap. In C++, when we allocate abject using
new(), the abject is allocated on Heap, otherwise on Stack if not global or static.
In Java, when we only declare a variable of a class type, only a reference is created (memory is
not allocated for the object). To allocate memory to an object, we must use new(). So the object
is always allocated memory on heap
For example, following program fails in compilation. Compiler gives error Error here because
t is not initialed.
class Test {
// class contents
void show() {
System.out.println("Test::show() called");
}
}
class Test {
// class contents
void show() {
System.out.println("Test::show() called");
}
}
No pointers
No sizeof operator
No scope resolution operator
Local variables in functions cannot be static
No Multiple Inheritance
No Operator Overloading
No preprocessor and macros
No user suggested inline functions
No goto
No default arguments
No unsigned int in Java
No -> operator in java
No stack allocated objects in java
No delete operator in java due to javas garbage collection
No destructor in java
No typedef in java
No global variables, no global function because java is pure OO.
No friend functions
No friend classes
No templates in java
final variables in Java
In Java, when final keyword is used with a variable of primitive data types (int, float, .. etc),
value of the variable cannot be changed.
When final is used with non-primitive variables (Note that non-primitive variables are always
references to objects in Java), the members of the referred object can be changed. final for non-
primitive variables just mean that they cannot be changed to refer to any other object
class Test1 {
int i = 10;
}
// filename: Test2.java
Output:
fun() called: x = 5
The Java program compiles and runs fine. Note that Test1 and fun() are not declared before their
use. Unlike C++, we dont need forward declarations in Java. Identifiers (class and method
names) are recognized automatically from source files. Similarly, library methods are directly
read from the libraries, and there is no need to create header files with declarations. Java uses
naming scheme where package and public class names must follow directory and file names
respectively. This naming scheme allows Java compiler to locate library files.
(Widening Primitive Conversion -Java)
Here is a small code snippet given. Try to Guess the output
Actual Output:
YO155.
Explanation:
When we use double quotes, the text is treated as a string and YO is printed, but when we use
single quotes, the characters L and O are converted to int. This is called widening primitive
conversion. After conversion to integer, the numbers are added ( L is 76 and O is 79) and 155
is printed.
Output: YOLO
Explanation: This will now print YOLO instead of YO7679. It is because the widening
primitive conversion happens only when + operator is present.
Widening primitive conversion is applied to convert either or both operands as specified by the
following rules. The result of adding Java chars, shorts or bytes is an int:
Creating a String
String literal
String s = HelloWorld;
String Methods
"HelloWorld".length(); // returns 10
"HelloWorld".charAt(3); // returns l
String substring (int i): Return the substring from the ith index character to end.
String substring (int i, int j): Returns the substring from i to j-1 index.
String concat( String str): Concatenates specified string to the end of this string.
String s1 = Hello;
String s2 = World;
String output = s1.concat(s2); // returns HelloWorld
int indexOf (String s): Returns the index within the string of the first occurrence of the
specified string.
String s = Learn Share Learn;
int output = s.indexOf(Share); // returns 6
int indexOf (String s, int i): Returns the index within the string of the first occurrence of
the specified string, starting at the specified index.
String s = Learn Share Learn;
int output = s.indexOf(a,3);// returns 8
Int lastindexOf( int ch): Returns the index within the string of the last occurrence of the
specified string.
String s = Learn Share Learn;
int output = s.lastindexOf(a); // returns 14
boolean equals( Object otherObj): Compares this string to the specified object.
Boolean out = Geeks.equals(Geeks); // returns true
Boolean out = Geeks.equals(geeks); // returns false
boolean equalsIgnoreCase (String anotherString): Compares string to another string,
ignoring case considerations.
Boolean out= Geeks.equalsIgnoreCase(Geeks); // returns true
Boolean out = Geeks.equalsIgnoreCase(geeks); // returns true
Note- In this case, it will not consider case of a letter (it will ignore whether it is
uppercase or lowercase).
String toLowerCase(): Converts all the characters in the String to lower case.
String word1 = HeLLo;
String word3 = word1.toLowerCase(); // returns hello"
String toUpperCase(): Converts all the characters in the String to upper case.
String word1 = HeLLo;
String word2 = word1.toUpperCase(); // returns HELLO
String trim(): Returns the copy of the String, by removing whitespaces at both ends. It
does not affect whitespaces in the middle.
String word1 = Learn Share Learn ;
String word2 = word1.trim(); // returns Learn Share Learn
String replace (char oldChar, char newChar): Returns new string by replacing all
occurrences of oldChar with newChar.
String s1 = feeksforfeeks;
String s2 = feeksforfeeks.replace(f ,g); // returns
geeksgorgeeks
Note:- s1 is still feeksforfeeks and s2 is geeksgorgeeks
import java.io.*;
import java.util.*;
class Test
{
public static void main (String[] args)
{
String s= "HelloWorld";
// or String s= new String ("HelloWorld");
// Converting cases
String word1 = "GeeKyMe";
System.out.println("Changing to lower Case " +
word1.toLowerCase());
// Converting cases
String word2 = "GeekyME";
System.out.println("Changing to UPPER Case " +
word1.toUpperCase());
// Replacing characters
String str1 = "feeksforfeeks";
System.out.println("Original String " + str1);
String str2 = "feeksforfeeks".replace('f' ,'g') ;
System.out.println("Replaced f with g -> " + str2);
}
}
Output :
String length = 13
Character at 3rd position = k
Substring ksforGeeks
Substring = eks
Concatenated string = HelloWorld
Index of Share 6
Index of a = 8
Checking Equality false
Checking Equality true
Checking Equalityfalse
If s1 = s2false
Changing to lower Case geekyme
Changing to UPPER Case GEEKYME
Trim the word Learn Share Learn
Original String feeksforfeeks
Replaced f with g -> geeksgorgeeks
volatile keyword in Java
Using volatile is yet another way (like synchronized, atomic wrapper) of making class thread
safe. Thread safe means that a method or class instance can be used by multiple threads at the
same time without any problem.
class SharedObj
{
// Changes made to sharedVar in one thread
// may not immediately reflect in other thread
static int sharedVar = 6;
}
Suppose that two threads are working on SharedObj. If two threads run on different processors
each thread may have its own local copy of sharedVar. If one thread modifies its value the
change might not reflect in the original one in the main memory instantly. This depends on the
write policy of cache. Now the other thread is not aware of the modified value which leads to
data inconsistency.
Below diagram shows that if two threads are run on different processors, then value of
sharedVar may be different in different threads.
Note that write of normal variables without any synchronization actions, might not be visible to
any reading thread (this behavior is called sequential consistency). Although most modern
hardware provide good cache coherence therefore most probably the changes in one cache are
reflected in other but its not a good practice to rely on hardware for to fix a faulty application.
class SharedObj
{
// volatile keyword here makes sure that
// the changes made in one thread are
// immediately reflect in other thread
static volatile int sharedVar = 6;
}
Note that volatile should not be confused with static modifier. static variables are class members
that are shared among all objects. There is only one copy of them in main memory.
volatile vs synchronized:
Before we move on lets take a look at two important features of locks and synchronization.
1. Mutual Exclusion: It means that only one thread or process can execute a block of code
(critical section) at a time.
2. Visibility: It means that changes made by one thread to shared data are visible to other
threads.
Javas synchronized keyword guarantees both mutual exclusion and visibility. If we make the
blocks of threads that modifies the value of shared variable synchronized only one thread can
enter the block and changes made by it will be reflected in the main memory. All other thread
trying to enter the block at the same time will be blocked and put to sleep.
In some cases we may only desire the visibility and not atomicity. Use of synchronized in such
situation is an overkill and may cause scalability problems. Here volatile comes to the rescue.
Volatile variables have the visibility features of synchronized but not the atomicity features. The
values of volatile variable will never be cached and all writes and reads will be done to and from
the main memory. However, use of volatile is limited to very restricted set of cases as most of
the times atomicity is desired. For example a simple increment statement such as x = x + 1; or
x++ seems to be a single operation but is s really a compound read-modify-write sequence of
operations that must execute atomically.
class Test
{
// Instance variable or member variable
private int value = 10;
void method()
{
// This local variable hides instance variable
int value = 40;
class UseTest
{
public static void main(String args[])
{
Test obj1 = new Test();
obj1.method();
}
}
Output:
class Main {
public static void main(String args[])
{
System.out.println("Hello");
}
}
Output:
Hello
Output:
Hello
Since we cant create object of abstract classes in Java, it is guaranteed that object of class with
main() is not created by JVM.
Using underscore in Numeric Literals
A new feature was introduced by JDK 7 which allows to write numeric literals using the
underscore character. Numeric literals are broken to enhance the readability.
This feature enables us to separate groups of digits in numeric literals, which improves readability
of code. For instance, if our code contains numbers with many digits, we can use an underscore
character to separate digits in groups of three, similar to how we would use a punctuation mark
like a comma, or a space, as a separator.
The following example shows different ways we can use underscore in numeric literals:
Output:
inum: 10000000
lnum: 10000000
fnum: 2.10001
dnum: 2.1012001
Scope of Variables In Java
Introduction
Scope of a variable is the part of the program where the variable is accessible. Like C/C++, in
Java, all identifiers are lexically (or statically) scoped, i.e., scope of a variable can determined at
compiler time and independent of function call stack.
On a side note, unlike Java/C/C++, Perl supports both dynamic ans static scoping. Perls
keyword my defines a statically scoped local variable, while the keyword local defines
dynamically scoped local variable i.e., scope depends on function call stack.
Java programs are organized in the form of classes. Every class is part of some package.
These variables must be declared inside class (outside any function). They can be directly
accessed anywhere in class. Lets take a look at an example:
Default (no
modifier) Yes No No
private No No No
Variables declared inside a method have method level scope and cant be accessed outside the
method.
public class Test
{
void method1()
{
// Local variable (Method level scope)
int x;
}
}
Heres another example of method scope, except this time the variable got passed in as a
parameter to the method:
class Test
{
private int x;
public void setX(int x)
{
this.x = x;
}
}
The above code uses this keyword to differentiate between the local and class variables.
Output:
Test.x: 22
t.x: 22
t.y: 33
y: 44
Loop Variables (Block Scope)
A variable declared inside pair of brackets { and } in a method has scope withing the
brackets only.
public class Test
{
public static void main(String args[])
{
{
// The variable x has scope within
// brackets
int x = 10;
System.out.println(x);
}
// System.out.println(x);
}
}
Output:
10
class Test
{
public static void main(String args[])
{
for (int x=0; x<4; x++)
{
System.out.println(x);
}
Output:
System.out.println(x);
}
}
Output:
0
1
2
3
4
Lets look at tricky example of loop scope. Predict the output of following program. You may be
surprised if you are regular C/C++ programmer.
class Test
{
public static void main(String args[])
{
int x = 5;
for (int x = 0; x < 5; x++)
{
System.out.println(x);
}
}
}
Output :
class Test
{
public static void main(String args[])
{
{
int x = 5;
{
int x = 10;
System.out.println(x);
}
}
}
}
To create an object of Scanner class, we usually pass the predefined object System.in,
which represents the standard input stream. We may pass an object of class File if we want
to read input from a file.
To read numerical values of a certain data type XYZ, the function to use is nextXYZ(). For
example, to read a value of type short, we can use nextShort()
To read strings, we use nextLine().
To read a single character, we use next().charAt(0). next() function returns the next
token/word in the input as a string and charAt(0) funtion returns the first character in that
string.
Let us look at the code snippet to read data of various data types.
// String input
String name = sc.nextLine();
// Character input
char gender = sc.next().charAt(0);
Geek
F
40
9876543210
9.9
Output :
Name: Geek
Gender: F
Age: 40
Mobile Number: 9876543210
CGPA: 9.9
Sometimes, we have to check if the next value we read is of a certain type or if the input has ended
(EOF marker encountered).
Then, we check if the scanners input is of the type we want with the help of hasNextXYZ()
functions where XYZ is the type we are interested in. The function returns true if the scanner has
a token of that type, otherwise false. For example, in the above code, we have used hasNextInt().To
check for a string, we use hasNextLine(). Similarly, to check for a single character, we use
hasNext().charAt(0).
Let us look at the code snippet to read some numbers from console and print their mean.
Input:
101
223
238
892
99
500
728
Output:
Mean: 397
Difference between Scanner and
BufferReader Class in Java
java.util.Scanner class is a simple text scanner which can parse primitive types and strings. It
internally uses regular expressions to read different types.
Input:
50
Geek
Output:
Enter an integer
Enter a String
You have entered:- 50 and name as
Let us try the same using Buffer class and same Input
Input:
50
Geek
Output:
Enter an integer
Enter a String
you have entered:- 50 and name as Geek
In Scanner class if we call nextLine() method after any one of the seven nextXXX() method then
the nextLine() doesnt not read values from console and cursor will not come into console it will
skip that step. The nextXXX() methods are nextInt(), nextFloat(), nextByte(), nextShort(),
nextDouble(), nextLong(), next().
In BufferReader class there is no such type of problem. This problem occurs only for Scanner
class, due to nextXXX() methods ignore newline character and nextLine() only reads newline
character. If we use one more call of nextLine() method between nextXXX() and nextLine(),
then this problem will not occur because nextLine() will consume the newline character. See this
for the corrected program. This problem is same as scanf() followed by gets() in C/C++.
Other differences:
One interesting fact related to the above topic is, we can use System.out.println() to print
messages to other sources too (and not just console) . However before doing so , we must
reassign the standard output by using the following method of System class:
System.setOut(PrintStream p);
PrintStream can be used for character output to a text file. Below program creates the file A.txt
and writes to the file using System.out.println(
Explanation:
The output is
9HelloWorld
HelloWorld2016
8HelloWorld2016
8HelloWorld9
This unpredictable output is due the fact that the compiler evaluates the given expression from left
to right given that the operators have same precedence. Once it encounters the String, it considers
the rest of the expression as of a String (again based on the precedence order of the expression).
In this article, we have discussed some ways to get around the difficulty and change the verdict
from TLE to (in most cases) AC.
7 3
1
51
966369
7
9
999996
11
Output:
1. Scanner Class (easy, less typing, but not recommended very slow, refer this for
reasons of slowness): In most of the cases we get TLE while using scanner class. It uses
built-in nextInt(), nextLong(), nextDouble methods to read the desired object after
initiating scanner object with input stream.(eg System.in). The following program many a
times gets time limit exceeded verdict and therefore not of much use.
public FastReader()
{
br = new BufferedReader(new
InputStreamReader(System.in));
}
String next()
{
while (st == null || !st.hasMoreElements())
{
try
{
st = new StringTokenizer(br.readLine());
}
catch (IOException e)
{
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt()
{
return Integer.parseInt(next());
}
long nextLong()
{
return Long.parseLong(next());
}
double nextDouble()
{
return Double.parseDouble(next());
}
String nextLine()
{
String str = "";
try
{
str = br.readLine();
}
catch (IOException e)
{
e.printStackTrace();
}
return str;
}
}
This gets accepted with a surprising time of just 0.28 s. Although this is ultra fast, it is clearly not
an easy method to remember.
public Reader()
{
din = new DataInputStream(System.in);
buffer = new byte[BUFFER_SIZE];
bufferPointer = bytesRead = 0;
}
if (neg)
return -ret;
return ret;
}
do {
ret = ret * 10 + c - '0';
}
while ((c = read()) >= '0' && c <= '9');
if (c == '.')
{
while ((c = read()) >= '0' && c <= '9')
{
ret += (c - '0') / (div *= 10);
}
}
if (neg)
return -ret;
return ret;
}
The purpose of this problem is to verify whether the method you are using to read input data is
sufficiently fast to handle problems branded with the enormous Input/Output warning. You are
expected to be able to process at least 2.5MB of input data per second at runtime.
Input
The input begins with two positive integers n k (n, k<=107). The next n lines of input contain one
positive integer ti, not greater than 109, each.
Output
Write a single integer to output, denoting how many integers ti are divisible by k.
Example
Input:
7 3
1
51
966369
7
9
999996
11
Output:
4
Bitwise right shift operators in Java
In C/C++ there is only one right shift operator >> which should be used only for positive
integers or unsigned integers. Use of right shift operator for negative numbers is not
recommended in C/C++, and when used for negative numbers, output is compiler dependent
(See this). Unlike C++, Java supports following two right shift operators.
1) >> (Signed right shift) In Java, the operator >> is signed right shift operator. All integers
are signed in Java, and it is fine to use >> for negative numbers. The operator >> uses the sign
bit (left most bit) to fill the trailing positions after shift. If the number is negative, then 1 is used
as a filler and if the number is positive, then 0 is used as a filler. For example, if binary
representation of number is 10.100, then right shifting it by 2 using >> will make it 11.1.
See following Java programs as example >>
class Test {
public static void main(String args[]) {
int x = -4;
System.out.println(x>>1);
int y = 4;
System.out.println(y>>1);
}
}
Output:
-2
2
2) >>> (Unsigned right shift) In Java, the operator >>> is unsigned right shift operator. It
always fills 0 irrespective of the sign of the number.
class Test {
public static void main(String args[]) {
Output:
7
3
1
Comparison of Autoboxed Integer objects in
Java
When we assign an integer value to an Integer object, the value is autoboxed into an Integer
object. For example the statement Integer x = 10 creates an object x with value 10.
Following are some interesting output questions based on comparison of Autoboxed Integer
objects.
Output:
Not Same
Since x and y refer to different objects, we get the output as Not Same
Output:
Same
In Java, values from -128 to 127 are cached, so the same objects are returned. The
implementation of valueOf() uses cached objects if the value is between -128 to 127.
If we explicitly create Integer objects using new operator, we get the output as Not Same. See
the following Java program. In the following program, valueOf() is not used.
Output:
Not Same
(Addition and Concatenation in Java)
Try to predict the output of following code:
Explanation:
The output is
9HelloWorld
HelloWorld2016
8HelloWorld2016
8HelloWorld9
This unpredictable output is due the fact that the compiler evaluates the given expression from left
to right given that the operators have same precedence. Once it encounters the String, it considers
the rest of the expression as of a String (again based on the precedence order of the expression).
to be same as,
Object o2;
if (true)
o2 = new Integer(4);
else
o2 = new Float(2.0);
Output:
4.0
4
According to Java Language Specification Section 15.25, the conditional operator will implement
numeric type promotion if there are two different types as 2nd and 3rd operand. The rules of
conversion are defined at Binary Numeric Promotion. Therefore, according to the rules given, If
either operand is of type double, the other is converted to double and hence 4 becomes 4.0.
Whereas, the if/else construct does not perform numeric promotion and hence behaves as expected.
Arrays in Java
Unlike C++, arrays are first class objects in Java. For example, in the following program, size of
array is accessed using length which is a member of arr[] object.
Output:
10 20 30 40 50
class Test
{
public static void main (String[] args)
{
int arr1[] = {1, 2, 3};
int arr2[] = {1, 2, 3};
if (arr1 == arr2) // Same as arr1.equals(arr2)
System.out.println("Same");
else
System.out.println("Not same");
}
}
Output:
Not Same
In Java, arrays are first class objects. In the above program, arr1 and arr2 are two references to
two different objects. So when we compare arr1 and arr2, two reference variables are compared,
therefore we get the output as Not Same (See this for more examples).
Output:
Same
import java.util.Arrays;
class Test
{
public static void main (String[] args)
{
// inarr1 and inarr2 have same values
int inarr1[] = {1, 2, 3};
int inarr2[] = {1, 2, 3};
Object[] arr1 = {inarr1}; // arr1 contains only one element
Object[] arr2 = {inarr2}; // arr2 also contains only one element
if (Arrays.equals(arr1, arr2))
System.out.println("Same");
else
System.out.println("Not same");
}
}
Output:
Not Same
So Arrays.equals() is not able to do deep comparison. Java provides another method for this
Arrays.deepEquals() which does deep comparison.
import java.util.Arrays;
class Test
{
public static void main (String[] args)
{
int inarr1[] = {1, 2, 3};
int inarr2[] = {1, 2, 3};
Object[] arr1 = {inarr1}; // arr1 contains only one element
Object[] arr2 = {inarr2}; // arr2 also contains only one element
if (Arrays.deepEquals(arr1, arr2))
System.out.println("Same");
else
System.out.println("Not same");
}
}
Output:
Same
import java.util.Arrays;
class Test
{
public static void main (String[] args)
{
int inarr1[] = {1, 2, 3};
int inarr2[] = {1, 2, 3};
Object[] arr1 = {inarr1}; // arr1 contains only one element
Object[] arr2 = {inarr2}; // arr2 also contains only one element
Object[] outarr1 = {arr1}; // outarr1 contains only one element
Object[] outarr2 = {arr2}; // outarr2 also contains only one
element
if (Arrays.deepEquals(outarr1, outarr2))
System.out.println("Same");
else
System.out.println("Not same");
}
}
Final arrays in Java
Predict the output of following Java program.
class Test
{
public static void main(String args[])
{
final int arr[] = {1, 2, 3, 4, 5}; // Note: arr is final
for (int i = 0; i < arr.length; i++)
{
arr[i] = arr[i]*10;
System.out.println(arr[i]);
}
}
}
Output:
10
20
30
40
50
The array arr is declared as final, but the elements of array are changed without any problem.
Arrays are objects and object variables are always references in Java. So, when we declare an
object variable as final, it means that the variable cannot be changed to refer to anything else. For
example, the following program 1 compiles without any error and program fails in compilation.
// Program 1
class Test
{
int p = 20;
public static void main(String args[])
{
final Test t = new Test();
t.p = 30;
System.out.println(t.p);
}
}
Output: 30
// Program 2
class Test
{
int p = 20;
public static void main(String args[])
{
final Test t1 = new Test();
Test t2 = new Test();
t1 = t2;
System.out.println(t1.p);
}
}
So a final array means that the array variable which is actually a reference to an object, cannot
be changed to refer to anything else, but the members of array can be modified.
class Test
{
public static void main(String args[])
{
final int arr1[] = {1, 2, 3, 4, 5};
int arr2[] = {10, 20, 30, 40, 50};
arr2 = arr1;
arr1 = arr2;
for (int i = 0; i < arr2.length; i++)
System.out.println(arr2[i]);
}
}
Jagged Array in Java
Jagged array is array of arrays such that member arrays can be of different sizes, i.e., we can
create a 2-D arrays but with variable number of columns in each row. These type of arrays are
also known as ragged arrays.
// Initializing array
int count = 0;
for (int i=0; i<arr.length; i++)
for(int j=0; j<arr[i].length; j++)
arr[i][j] = count++;
Output:
Following is another example where ith row has i columns, i.e., first row has 1 element, second
row has two elements and so on.
// Initializing array
int count = 0;
for (int i=0; i<arr.length; i++)
for(int j=0; j<arr[i].length; j++)
arr[i][j] = count++;
Output:
System.out.println(ar[i]);
}
Runtime error throws an Exception:
Output:
1
2
3
4
5
Here if you carefully see, the array is of size 5. Therefore while accessing its element using for
loop, the maximum value of index can be 4 but in our program it is going till 5 and thus the
exception.
import java.util.ArrayList;
lis.add("My");
lis.add("Name");
System.out.println(lis.get(2));
}
Runtime error here is a bit more informative than the previous time-
Use for-each loop: This automatically handles indices while accessing the elements of an array.
Example-
for(int m : ar){
}
Use Try-Catch: Consider enclosing your code inside a try-catch statement and manipulate the
exception accordingly. As mentioned, Java wont let you access an invalid index and will definitely
throw an ArrayIndexOutOfBoundsException. However, we should be careful inside the block of
the catch statement, because if we dont handle the exception appropriately, we may conceal it
and thus, create a bug in your application.
Comparison of static keyword in C++ and
Java
Static keyword is used for almost same purpose in both C++ and Java. There are some
differences though. This post covers similarities and differences of static keyword in C++ and
Java.
Static Data Members: Like C++, static data members in Java are class members and shared
among all objects. For example, in the following Java program, static variable count is used to
count the number of objects created.
class Test {
static int count = 0;
Test() {
count++;
}
public static void main(String arr[]) {
Test t1 = new Test();
Test t2 = new Test();
System.out.println("Total " + count + " objects created");
}
}
Output:
Static Member Methods: Like C++, methods declared as static are class members and have
following restrictions:
1) They can only call other static methods. For example, the following program fails in
compilation. fun() is non-static and it is called in static main()
class Main {
public static void main(String args[]) {
System.out.println(fun());
}
int fun() {
return 20;
}
}
3) They cannot access this or super . For example, the following program fails in compilation.
class Base {
static int x = 0;
}
Like C++, static data members and static methods can be accessed without creating an object.
They can be accessed using class name. For example, in the following program, static data
member count and static method fun() are accessed without any object.
class Test {
static int count = 0;
public static void fun() {
System.out.println("Static fun() called");
}
}
class Main
{
public static void main(String arr[]) {
System.out.println("Test.count = " + Test.count);
Test.fun();
}
}
Static Block: Unlike C++, Java supports a special block, called static block (also called static
clause) which can be used for static initialization of a class. This code inside static block is
executed only once. See Static blocks in Java for details.
Static Local Variables: Unlike C++, Java doesnt support static local variables. For example,
the following Java program fails in compilation.
class Test {
public static void main(String args[]) {
System.out.println(fun());
}
static int fun() {
static int x= 10; //Compiler Error: Static local variables are not
allowed
return x--;
}
}
Static blocks in Java
Unlike C++, Java supports a special block, called static block (also called static clause) which
can be used for static initializations of a class. This code inside static block is executed only
once: the first time you make an object of that class or the first time you access a static member
of that class (even if you never make an object of that class). For example, check output of
following Java program.
// filename: Main.java
class Test {
static int i;
int j;
class Main {
public static void main(String args[]) {
Output:
static block called
10
Also, static blocks are executed before constructors. For example, check output of following Java
program.
// filename: Main.java
class Test {
static int i;
int j;
static {
i = 10;
System.out.println("static block called ");
}
Test(){
System.out.println("Constructor called");
}
}
class Main {
public static void main(String args[]) {
Output:
static block called
Constructor called
Constructor called
class Test {
public static void main(String args[]) {
System.out.println(fun());
}
Java allows us to define a class within another class. Such a class is called a nested class. The
class which enclosed nested class is known as Outer class. In java, we cant make Top level class
static. Only nested classes can be static.
What are the differences between static and non-static nested classes?
Following are major differences between static nested class and non-static nested class. Non-
static nested class is also called Inner Class.
1) Nested static class doesnt need reference of Outer class, but Non-static nested class or Inner
class requires Outer class reference.
2) Inner class(or non-static nested class) can access both static and non-static members of Outer
class. A static class cannot access non-static members of the Outer class. It can access only static
members of Outer class.
3) An instance of Inner class cannot be created without an instance of outer class and an Inner
class can reference data and methods defined in Outer class in which it nests, so we dont need to
pass reference of an object to the constructor of the Inner class. For this reason Inner classes can
make program simple and concise.
Output:
Overriding : Overriding is a feature of OOP languages like Java that is related to run-time
polymorphism. A subclass (or derived class) provides a specific implementation of a method in
superclass (or base class).
The implementation to be executed is decided at run-time and decision is made according to the
object used for call. Note that signatures of both methods must be same.
Overloading: Overloading is also a feature of OOP languages like Java that is related to compile
time (or static) polymorphism. This feature allows different methods to have same name, but
different signatures, especially number of input parameters and type of input paramaters. Note
that in both C++ and Java, methods cannot be overloaded according to return type.
// filename Test.java
public class Test {
public static void foo() {
System.out.println("Test.foo() called ");
}
public static void foo(int a) {
System.out.println("Test.foo(int) called ");
}
public static void main(String args[])
{
Test.foo();
Test.foo(10);
}
}
Output:
Test.foo() called
Test.foo(int) called
// filename Test.java
public class Test {
public static void foo() {
System.out.println("Test.foo() called ");
}
public void foo() { // Compiler Error: cannot redefine foo()
System.out.println("Test.foo(int) called ");
}
public static void main(String args[]) {
Test.foo();
}
}
// Superclass
class Base {
// Subclass
class Derived extends Base {
// Driver class
public class Test {
public static void main(String args[ ]) {
Base obj1 = new Derived();
// As per overriding rules this should call to class Derive's static
// overridden method. Since static method can not be overridden, it
// calls Base's display()
obj1.display();
Output:
Following are some important points for method overriding and static methods in Java.
1) For class (or static) methods, the method according to the type of reference is called, not
according to the abject being referred, which means method call is decided at compile time.
2) For instance (or non-static) methods, the method is called according to the type of object
being referred, not according to the type of reference, which means method calls is decided at
run time.
3) An instance method cannot override a static method, and a static method cannot hide an
instance method. For example, the following program has two compiler errors.
// Superclass
class Base {
// Subclass
class Derived extends Base {
4) In a subclass (or Derived Class), we can overload the methods inherited from the superclass.
Such overloaded methods neither hide nor override the superclass methods they are new
methods, unique to the subclass.
final keyword in java
final keyword is used in Java in different contexts. The idea is make an entity non-modifiable.
Following are different contexts where final is used.
Final variables A final variable can only be assigned once. If the variable is a reference, this
means that the variable cannot be re-bound to reference another object.
Output
Note the difference between C++ const variables and Java final variables. const variables in C++
must be assigned a value when declared. For final variables n Java, it is not necessary. A final
variable can be assigned value later, but only once. For example see the following Java program.
Output:
20
class Base {
public final void show() {
System.out.println("Base::show() called");
}
}
Output:
1. Use of super with variables: This scenario occurs when a derived class and base class has
same data members. In that case there is a possibility of ambiguity for the JVM. We can
understand it more clearly using this code snippet:
void display()
{
/* print maxSpeed of base class (vehicle) */
System.out.println("Maximum Speed: " + super.maxSpeed);
}
}
Output:
In the above example, both base class and subclass have a member maxSpeed. We could access
maxSpeed of base class in sublcass using super keyword.
2. Use of super with methods: This is used when we want to call parent class method. So
whenever a parent and child class have same named methods then to resolve ambiguity we use
super keyword. This code snippet helps to understand the said usage of super keyword.
/* Base class Person */
class Person
{
void message()
{
System.out.println("This is person class");
}
}
/* Subclass Student */
class Student extends Person
{
void message()
{
System.out.println("This is student class");
}
Output:
In the above example, we have seen that if we only call method message() then, the current class
message() is invoked but with the use of super keyword, message() of superclass could also be
invoked.
3. Use of super with constructors: super keyword can also be used to access the parent class
constructor. One more important thing is that, super can call both parametric as well as non
parametric constructors depending upon the situation. Following is the code snippet to explain
the above concept:
/* superclass Person */
class Person
{
Person()
{
System.out.println("Person class Constructor");
}
}
Output:
In the above example we have called the superclass constructor using keyword super via subclass
constructor.
A blank final variable in Java is a final variable that is not initialized during declaration. Below
is a simple example of blank final.
Test(int x)
{
// Since we have initialized above, we
// must initialize i in constructor.
// If we remove this line, we get compiler
// error.
i = x;
}
}
// Driver Code
class Main
{
public static void main(String args[])
{
Test t1 = new Test(10);
System.out.println(t1.i);
Output:
10
20
If we have more than one constructors or overloaded constructor in class, then blank final
variable must be initialized in all of them. However constructor chaining can be used to
initialize the blank final variable.
// A Java program to demonstrate that we can
// use constructor chaining to initialize
// final members
class Test
{
final public int i;
Test()
{
// Calling Test(int val)
this(10);
}
Output:
10
20
Blank final variables are used to create immutable objects (objects whose members cant be
changed once initialized).
How are parameters passed in Java?
In Java, parameters are always passed by value. For example, following program prints i = 10, j
= 20.
// Test.java
class Test {
i = j;
j = temp;
swap(i, j);
Output:
5
We pass an int to the function change() and as a result the change in the value of that integer is
not reflected in the main method. Like C/C++, Java creates a copy of the variable being passed in
the method and then do the manipulations. Hence the change is not reflected in the main method.
In Java, all primitives like int, char, etc are similar to C/C++, but all non-primitives (or objects of
any class) are always references. So it gets tricky when we pass object references to methods.
Java creates a copy of references and pass it to method, but they still point to same memory
reference. Mean if set some other object to reference passed inside method, the object from
calling method as well its reference will remain unaffected.
The changes are not reflected back if we change the object itself to refer some other
location or object
If we assign reference to some other location, then changes are not reflected back in main().
class Main
{
public static void main(String[] args)
{
// t is a reference
Test t = new Test(5);
t.x = 10;
}
}
Output:
Changes are reflected back if we do not assign reference to a new location or object:
If we do not change the reference to refer some other object (or memory location), we can make
changes to the members and these changes are reflected back.
class Main
{
public static void main(String[] args)
{
// t is a reference
Test t = new Test(5);
Output:
10
// Test.java
class Main {
// swap() doesn't swap i and j
public static void swap(Integer i, Integer j)
{
Integer temp = new Integer(i);
i = j;
j = temp;
}
public static void main(String[] args)
{
Integer i = new Integer(10);
Integer j = new Integer(20);
swap(i, j);
System.out.println("i = " + i + ", j = " + j);
}
}
Returning Multiple values in Java
Java doesnt support multi-value returns. We can use following solutions to return multiple
values.
We can return an array in Java. Below is a Java program to demonstrate the same.
// A Java program to demonstrate that a method
// can return multiple values of same type by
// returning an array
class Test
{
// Returns an array such that first element
// of array is a+b, and second element is a-b
static int[] getSumAndSub(int a, int b)
{
int[] ans = new int[2];
ans[0] = a + b;
ans[1] = a - b;
// Driver method
public static void main(String[] args)
{
int[] ans = getSumAndSub(100,50);
System.out.println("Sum = " + ans[0]);
System.out.println("Sub = " + ans[1]);
}
}
Sum = 150
Sub = 50
We can be encapsulate all returned types into a class and then return an object of that class.
class Test
{
static MultiDiv getMultandDiv(int a, int b)
{
// Returning multiple values of different
// types by returning an object
return new MultiDiv(a*b, (double)a/b);
}
// Driver code
public static void main(String[] args)
{
MultiDiv ans = getMultandDiv(10, 20);
System.out.println("Multiplication = " + ans.mul);
System.out.println("Division = " + ans.div);
}
}
Output:
Multiplication = 200
Division = 0.5
Function overloading and return type
In C++ and Java, functions can not be overloaded if they differ only in the return type.
For example, the following program C++ and Java programs fail in compilation.
C++ Program
#include<iostream>
int foo() {
return 10;
}
int main()
{
char x = foo();
getchar();
return 0;
}
Java Program
// filename Main.java
public class Main {
public int foo() {
return 10;
}
public char foo() { // compiler error: foo() is already defined
return 'a';
}
public static void main(String args[])
{
}
}
Overriding equals method in Java
Consider the following Java program:
class Complex {
private double re, im;
Output:
Not Equal
The reason for printing Not Equal is simple: when we compare c1 and c2, it is checked
whether both c1 and c2 refer to same object or not (object variables are always references in
Java). c1 and c2 refer to two different objects, hence the value (c1 == c2) is false. If we create
another reference say c3 like following, then (c1 == c3) will give true.
So, how do we check for equality of values inside the objects? All classes in Java inherit from
the Object class, directly or indirectly (See point 1 of this). The Object class has some basic
methods like clone(), toString(), equals(),.. etc. We can override the equals method in our class to
check whether two objects have same data or not.
class Complex {
Output:
Equal
As a side note, when we override equals(), it is recommended to also override the hashCode()
method. If we dont do so, equal objects may get different hash-values; and hash based
collections, including HashMap, HashSet, and Hashtable do not work properly (see this for more
details). We will be coverig more about hashCode() in a separate post.
Overriding toString() in Java
This post is similar to Overriding equals method in Java. Consider the following Java program:
class Complex {
private double re, im;
Output:
Complex@19821f
The output is, class name, then at sign, and at the end hashCode of object. All classes in Java
inherit from the Object class, directly or indirectly (See point 1 of this). The Object class has
some basic methods like clone(), toString(), equals(),.. etc. The default toString() method in
Object prints class name @ hash code. We can override toString() method in our class to print
proper output. For example, in the following code toString() is overridden to print Real + i
Imag form.
class Complex {
private double re, im;
Output:
10.0 + i15.0
In general, it is a good idea to override toString() as we get get proper output when an object is
used in print() or println().
Private and final methods in Java
When we use final specifier with a method, the method cannot be overridden in any of the
inheriting classes. Methods are made final due to design reasons.
Since private methods are inaccessible, they are implicitly final in Java. So adding final specifier
to a private method doesnt add any value. It may in-fact cause unnecessary confusion.
class Base {
For example, both program 1 and program 2 below produce same compiler error foo() has
private access in Base.
Program 1
Program 2
// Normal main()
public static void main(String[] args) {
System.out.println("Hi Geek (from main)");
Test.main("Geek");
}
Output:
Important Points:
The main method in Java is no extra-terrestrial method. Apart from the fact that main() is just
like any other method & can be overloaded in a similar manner, JVM always looks for the
method signature to launch the program.
The normal main method acts as an entry point for the JVM to start the execution of
program.
We can overload the main method in Java. But the program doesnt execute the
overloaded main method when we run your program, we need to call the overloaded
main method from the actual main method only.
Valid variants of main() in Java
Below are different variants of main() that are valid.
1. Default prototype: Below is the most common way to write main() in Java.
class Test
{
public static void main(String[] args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
Output:
Main Method
Variants of String array arguments: We can place square brackets at different positions and
we can use varargs () for string parameter.
class Test
{
public static void main(String[] args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
class Test
{
public static void main(String []args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
class Test
{
public static void main(String args[])
{
System.out.println("Main Method");
}
}
Output:
Main Method
class Test
{
public static void main(String...args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
Final Modifier String argument: We can make String args[] as final.
class Test
{
public static void main(final String[] args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
Final Modifier to static main method: We can make main() as final.
class Test
{
public final static void main(String[] args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
synchronized keyword to static main method: We can make main() synchronized.
class Test
{
public synchronized static void main(String[] args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
strictfp keyword to static main method: strictfp can be used to restrict floating point
calculations.
class Test
{
public strictfp static void main(String[] args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
Combinations of all above keyword to static main method:
class Test
{
final static synchronized strictfp static void main(String[] args)
{
System.out.println("Main Method");
}
}
Output:
Main Method
Overloading Main method: We can overload main() with different types of parameters.
class Test
{
public static void main(String[] args)
{
System.out.println("Main Method String Array");
}
public static void main(int[] args)
{
System.out.println("Main Method int Array");
}
}
Output:
class B extends A
{
Two class files, A.class and B.class are generated by compiler. When we execute any of the
two .class, JVM executes with no error.
O/P: Java A
Main Method Parent
O/P: Java B
Main Method Parent
Method Hiding of main(), but not Overriding: Since main() is static, derived class main()
hides the base class main. (See Shadowing of static functions for details.)
class A
{
public static void main(String[] args)
{
System.out.println("Main Method Parent");
}
}
class B extends A
{
public static void main(String[] args)
{
System.out.println("Main Method Child");
}
}
Two classes, A.class and B.class are generated by Java Compiler javac. When we execute both
the .class, JVM executes with no error.
O/P: Java A
Main Method Parent
O/P: Java B
Main Method Child
Variable Arguments (Varargs) in Java
Variable arguments (or varargs) were introduced in JDK 5. Below is a code snippet for
illustrating the concept.
// Driver code
public static void main(String args[])
{
// Calling the varargs method with different number
// of parameters
fun(100); // one parameter
fun(1, 2, 3, 4); // four parameters
fun(); // no parameter
}
}
Output:
o The syntax tells the compiler that varargs has been used and these arguments
should be stored in the array referred to by a.
o The variable a is operated on as an array. In this case, we have defined the data type
of a as int. So it can take only integer values. The number of arguments can be
found out using a.length, the way we find the length of an array in Java.
A method can have normal parameters along with the variable length parameters but
one should ensure that there exists only one varargs parameter that should be written last
in the parameter list of the method declaration.
int nums(int a, float b, double c)
In this case, the first two arguments are matched with the first two parameters and the
remaining arguments belong to c.
An example program showcasing the use of varargs along with normal parameters :
System.out.println();
}
Vararg Methods can also be overloaded but overloading may lead to ambiguity.
Prior to JDK 5, variable length arguments could be handled into two ways : One was
using overloading, other was using array argument.
There can be only one variable argument in a method.
Variable argument (varargs) must be the last argument.
Output :
12
12
The parameter i is reference in modify and refers to same object as i in main(), but changes made
to i are not reflected in main(), why?
Explanation:
All primitive wrapper classes (Integer, Byte, Long, Float, Double, Character, Boolean and Short)
are immutable in Java, so operations like addition and subtraction create a new object and not
modify the old.
The below line of code in the modify method is operating on wrapper class Integer, not an int
i = i + 1;
// Driver Class
class Main
{
public static void main(String[] args)
{
Test ob1 = new Test();
System.out.println(ob1.x+" "+ob1.y);
System.out.println(ob2.x+" "+ob2.y);
}
}
Output:
10 20
100 20
100 20
The class whose objects copy is to be made must have a public clone method in it or in one of
its parent class.
Every class that implements clone() should call super.clone() to obtain the cloned object
reference.
The class must also implement java.lang.Cloneable interface whose object clone we want
to create otherwise it will throw CloneNotSupportedException when clone method is
called on that classs object.
Syntax:
// Driver class
public class Main
{
public static void main(String args[]) throws
CloneNotSupportedException
{
Test2 t1 = new Test2();
t1.a = 10;
t1.b = 20;
t1.c.x = 30;
t1.c.y = 40;
Test2 t2 = (Test2)t1.clone();
Output:
10 20 300 40
100 20 300 40
In the above example, t1.clone returns the shallow copy of the object t1. To obtain a deep copy
of the object certain modifications have to be made in clone method after obtaining the copy.
Shallow copies are cheap and simple to make. In above example, we created a shallow copy of
object.
Test2 t3 = (Test2)t1.clone();
t3.a = 100;
Output:
10 20 30 40
100 20 300 0
In the above example, we can see that a new object for Test class has been assigned to copy
object that will be returned in clone method.Due to this t3 will obtain a deep copy of the object
t1. So any changes made in c object fields by t3 ,will not be reflected in t1.
Working of RMI
The communication between client and server is handled by using two intermediate objects: Stub
object (on client side) and Skeleton object (on server side).
Stub Object
The stub object on the client machine builds an information block and sends this information to t
he server. The block consists of
Skeleton Object
The skeleton object passes the request from the stub object to the remote object.
It performs following tasks
It calls the desired method on the real object present on the server.
It forwards the parameters received from the stub object to the method.
Steps to implement Interface
The next step is to implement the remote interface. To implement the remote interface, the class
should extend to UnicastRemoteObject class of java.rmi package. Also, a default constructor
needs to be created to throw the java.rmi.RemoteException from its parent constructor in class.
Step 3: Creating Stub and Skeleton objects from the implementation class using rmic
The rmic tool is used to invoke the rmi compiler that creates the Stub and Skeleton objects. Its
prototype is
rmic classname. For above program the following command need to be executed at the command
prompt
rmic SearchQuery
Note: The above client and server program is executed on the same machine so localhost is used.
In order to access the remote object from another machine, localhost is to be replaced with the
IP address where the remote object is present.
Important Observations:
1. RMI is a pure java solution to Remote Procedure Calls (RPC) and is used to create
distributed application in java.
2. Stub and Skeleton objects are used for communication between client and server side.
Default constructor in Java
Like C++, Java automatically creates default constructor if there is no default or parameterized
constructor written by user, and (like C++) the default constructor automatically calls parent
default constructor. But unlike C++, default constructor in Java initializes member data variable
to default values (numeric values are initialized as 0, booleans are initialized as false and
references are initialized as null).
0
null
false
0
0.0
// Main.java
class Test {
int i;
Test t;
boolean b;
byte bt;
float ft;
}
If we make i as static final then we must assign value to i with the delcaration.
class Test {
static final int i = 10; // Since i is static final, it must be assigned
value here only.
Such behavior is obvious as static variables are shared among all the objects of a class; creating a
new object would change the same static variable which is not allowed if the static variable is
final.
Following is an example Java program that shows a simple use of copy constructor.
// filename: Main.java
class Complex {
// copy constructor
Complex(Complex c) {
System.out.println("Copy constructor called");
re = c.re;
im = c.im;
}
// Overriding the toString of Object class
@Override
public String toString() {
return "(" + re + " + " + im + "i)";
}
}
Output:
// filename: Main.java
class Complex {
1) In C++, all types (including primitive and pointer) can be thrown as exception. But in Java
only throwable objects (Throwable objects are instances of any subclass of the Throwable class)
can be thrown as exception. For example, following type of code works in C++, but similar code
doesnt work in Java.
#include <iostream>
using namespace std;
int main()
{
int x = -1;
Output:
Exception occurred: thrown value is -1
2) In C++, there is a special catch called catch all that can catch all kind of exceptions.
#include <iostream>
using namespace std;
int main()
{
int x = -1;
char *ptr;
getchar();
return 0;
}
Output:
Exception occurred: exiting
In Java, for all practical purposes, we can catch Exception object to catch all kind of exceptions.
Because, normally we do not catch Throwable(s) other than Exception(s) (which are Errors)
catch(Exception e){
.
}
3) In Java, there is a block called finally that is always executed after the try-catch block. This
block can be used to do cleanup work. There is no such block in C++.
class Main {
public static void main(String args[]) {
try {
throw new Test();
}
catch(Test t) {
System.out.println("Got the Test Exception");
}
finally {
System.out.println("Inside finally block ");
}
}
}
Output:
Got the error
Inside finally block
4) In C++, all exceptions are unchecked. In Java, there are two types of exceptions checked
and unchecked. See this for more details on checked vs Unchecked exceptions.
5) In Java, a new keyword throws is used to list exceptions that can be thrown by a function. In
C++, there is no throws keyword, the same keyword throw is used for this purpose also.
If both base and derived classes are caught as exceptions then catch block of derived class must
appear before the base class.
If we put base class first then the derived class catch block will never be reached. For example,
following C++ code prints Caught Base Exception
#include<iostream>
using namespace std;
In the above C++ code, if we change the order of catch statements then both catch statements
become reachable. Following is the modifed program and it prints Caught Derived Exception
#include<iostream>
using namespace std;
In Java, catching a base class exception before derived is not allowed by the compiler itself. In
C++, compiler might give warning about it, but compiles the code.
For example, following Java code fails in compilation with error message exception Derived
has already been caught
//filename Main.java
class Base extends Exception {}
class Derived extends Base {}
public class Main {
public static void main(String args[]) {
try {
throw new Derived();
}
catch(Base b) {}
catch(Derived d) {}
}
}
For example, consider the following Java program that opens file at locatiobn C:\test\a.txt and
prints first three lines of it. The program doesnt compile, because the function main() uses
FileReader() and FileReader() throws a checked exception FileNotFoundException. It also uses
readLine() and close() methods, and these methods also throw checked exception IOException
import java.io.*;
class Main {
public static void main(String[] args) {
FileReader file = new FileReader("C:\\test\\a.txt");
BufferedReader fileInput = new BufferedReader(file);
fileInput.close();
}
}
Output:
To fix the above program, we either need to specify list of exceptions using throws, or we need
to use try-catch block. We have used throws in the below program. Since
FileNotFoundException is a subclass of IOException, we can just specify IOException in the
throws list and make the above program compiler-error-free.
import java.io.*;
class Main {
public static void main(String[] args) throws IOException {
FileReader file = new FileReader("C:\\test\\a.txt");
BufferedReader fileInput = new BufferedReader(file);
fileInput.close();
}
}
2) Unchecked are the exceptions that are not checked at compiled time. In C++, all exceptions
are unchecked, so it is not forced by the compiler to either handle or specify the exception. It is
up to the programmers to be civilized, and specify or catch the exceptions.
In Java exceptions under Error and RuntimeException classes are unchecked exceptions,
everything else under throwable is checked.
+-----------+
| Throwable |
+-----------+
/ \
/ \
+-------+ +-----------+
| Error | | Exception |
+-------+ +-----------+
/ | \ / | \
\________/ \______/ \
+------------------+
unchecked checked | RuntimeException |
+------------------+
/ | | \
\_________________/
unchecked
Consider the following Java program. It compiles fine, but it throws ArithmeticException when
run. The compiler allows it to compile, because ArithmeticException is an unchecked exception.
class Main {
public static void main(String args[]) {
int x = 0;
int y = 10;
int z = y/x;
}
}
Output:
We pass the string to the constructor of the super class- Exception which is obtained using
getMessage() function on the object created.
Output:
Caught
GeeksGeeks
In the above code, constructor of MyException requires a string as its argument. The string is
passed to parent class Exceptions constructor using super(). The constructor of Exception class
can also be called without a parameter and call to super is not mandatory.
Output:
Caught
null
(Infinity or Exception?)
Consider the following code snippets:
Output:
Infinity
public class HelloWorld
{
public static void main(String[] args)
{
int p = 1;
System.out.println(p/0);
}
}
Output:
Explanation: In the first piece of code, a double value is being divided by 0 while in the other
case an integer value is being divide by 0. However the solution for both of them differs.
In case of double/float division, the output is Infinity, the basic reason behind that it
implements the floating point arithmetic algorithm which specifies a special values like
Not a number OR infinity for divided by zero cases as per IEEE 754 standards.
In case of integer division, it throws ArithmeticException.
Multicatch in Java
Background
Prior to Java 7, we had to catch only one exception type in each catch block. So whenever we
needed to handle more than one specific exception, but take same action for all exceptions, then
we had to have more than one catch block containing the same code.
In the following code, we have to handle two different exceptions but take same action for both.
So we needed to have two different catch blocks as of Java 6.0.
Input 1:
HelloWorld
Output 2:
Input 2:
Output 2:
Starting from Java 7.0, it is possible for a single catch block to catch multiple exceptions by
separating each with | (pipe symbol) in catch block.
// A Java program to demonstrate multicatch
// feature
import java.util.Scanner;
public class Test
{
public static void main(String args[])
{
Scanner scn = new Scanner(System.in);
try
{
int n = Integer.parseInt(scn.nextLine());
if (99%n == 0)
System.out.println(n + " is a factor of 99");
}
catch (NumberFormatException | ArithmeticException ex)
{
System.out.println("Exception encountered " + ex);
}
}
}
Input 1:
HelloWorld
Output 1:
Input 2:
Output 2:
Exception encountered
java.lang.ArithmeticException: / by zero
A catch block that handles multiple exception types creates no duplication in the bytecode
generated by the compiler, that is, the bytecode has no replication of exception handlers.
Important Points:
If all the exceptions belong to the same class hierarchy, we should catching the base
exception type. However, to catch each exception, it needs to be done separately in their
own catch blocks.
Single catch block can handle more than one type of exception. However, the base (or
ancestor) class and subclass (or descendant) exceptions can not be caught in one statement.
For Example
// Not Valid as Exception is an ancestor of
// NumberFormatException
catch(NumberFormatException | Exception ex)
All the exceptions must be separated by vertical bar pipe |.
Regular Expressions in Java
Regular Expressions or Regex (in short) is an API for defining String patterns that can be used for
searching, manipulating and editing a text. It is widely used to define constraint on strings such as
password. Regular Expressions are provided under java.util.regex package.
java.util.regex.Pattern Class
1. matches() It is used to check if the whole text matches a pattern. Its output is boolean.
2. // A Simple Java program to demonstrate working of
3. // Pattern.matches() in Java
4. import java.util.regex.Pattern;
5.
6. class Demo
7. {
8. public static void main(String args[])
9. {
10. // Following line prints "true" because the whole
11. // text "HelloWorld" matches pattern "geeksforge*ks"
12. System.out.println (Pattern.matches("geeksforge*ks",
13. "HelloWorld"));
14.
15. // Following line prints "false" because the whole
16. // text "geeksfor" doesn't match pattern "g*geeks*"
17. System.out.println (Pattern.matches("g*geeks*",
18. "geeksfor"));
19. }
}
Output:
true
false
20. compile() Used to create a pattern object by compiling a given string that may contain
regular expressions. Input may also contains flags like Pattern.CASE_INSENSITIVE,
Pattern.COMMENTS, .. etc (See this for details).
21. split() It is used to split a text into multiple strings based on a delimiter pattern.
java.util.regex.Matcher Class
1. find() It is mainly used for searching multiple occurrences of the regular expressions in
the text.
2. start() It is used for getting the start index of a match that is being found using find()
method.
3. end() It is used for getting the end index of a match that is being found using find()
method. It returns index of character next to last matching character
Note that Pattern.matches() checks if whole text matches with a pattern or not. Other methods
(demonstrated below) are mainly used to find multiple occurrences of pattern in text.
Java Programs to demonstrate workings of compile(), find(), start(), end() and split() :
Output:
Output:
Output:
70. Java program to demonstrate working of split() to split a text based on a delimiter
pattern
71. // Java program to demonstrate working of splitting a text by a
72. // given pattern
73. import java.util.regex.Matcher;
74. import java.util.regex.Pattern;
75.
76. class Demo
77. {
78. public static void main(String args[])
79. {
80. String text = "geeks1for2geeks3";
81.
82. // Specifies the string pattern which is to be searched
83. String delimiter = "\\d";
84. Pattern pattern = Pattern.compile(delimiter,
85. Pattern.CASE_INSENSITIVE);
86.
87. // Used to perform case insensitive search of the string
88. String[] result = pattern.split(text);
89.
90.
91. for (String temp: result)
92. System.out.println(temp);
93. }
94. }
Output:
geeks
for
geeks
Important Observations/Facts:
Quantifiers in Java
We strongly recommend to refer below post as a prerequisite of this.
Quantifiers allow user to specify the number of occurrences to match against. Below are some
commonly used quantifiers in Java.
class Test
{
public static void main(String[] args)
{
// Making an instance of Pattern class
// By default quantifier "+" is Greedy
Pattern p = Pattern.compile("g+");
while (m.find())
System.out.println("Pattern found from " + m.start() +
" to " + (m.end()-1));
}
}
Output :
Explanation : The pattern g+ means one or more occurrences of g. Text is ggg. The greedy
matcher would match the longest text even if parts of matching text also match. In this example,
g and gg also match, but the greedy matcher produces ggg.
while (m.find())
System.out.println("Pattern found from " + m.start() +
" to " + (m.end()-1));
}
}
Output :
Explanation : Since the quantifier is reluctant, it matches the shortest part of test with pattern. It
processes one character at a time.
class Test
{
public static void main(String[] args)
{
// Making an instance of Pattern class
// Here "+" is a Possessive quantifier because
// a "+' is appended after it.
Pattern p = Pattern.compile("g++");
while (m.find())
System.out.println("Pattern found from " + m.start() +
" to " + (m.end()-1));
}
}
Output :
Explanation: We get the same output as Greedy because whole text matches the pattern.
class Test
{
public static void main(String[] args)
{
// Create a pattern with Greedy quantifier
Pattern pg = Pattern.compile("g+g");
}
}
Output :
In the above example, since first quantifier is greedy, g+ matches with whole string. If we match
g+ with whole string, g+g doesnt match, the Greedy quantifier, removes last character, matches
gg with g+ and finds a match.
In Possessive quantifier, we start like Greedy. g+ matches whole string, but matching g+ with
whole string doesnt match g+g with ggg. Unlike Greedy, since quantifier is possessive, we stop
at this point.
Comparison of Inheritance in C++ and Java
The purpose of inheritance is same in C++ and Java. Inheritance is used in both languages for
reusing code and/or creating is-a relationship. There are following differences in the way both
languages provide support for inheritance.
1) In Java, all classes inherit from the Object class directly or indirectly. Therefore, there is
always a single inheritance tree of classes in Java, and Object class is root of the tree. In Java, if
we create a class that doesnt inherit from any class then it automatically inherits from Object
class . In C++, there is forest of classes; when we create a class that doesnt inherit from
anything, we create a new tree in forest.
Following Java example shows that Test class automatically inherits from Object class.
class Test {
// members of test
}
class Main {
public static void main(String[] args) {
Test t = new Test();
System.out.println("t is instanceof Object: " + (t instanceof Object));
}
}
Output:
2) In Java, members of the grandparent class are not directly accessible. See this G-Fact for more
details.
3) The meaning of protected member access specifier is somewhat different in Java. In Java,
protected members of a class A are accessible in other class B of same package, even if B
doesnt inherit from A (they both have to be in the same package). For example, in the following
program, protected members of A are accessible in B.
// filename B.java
class A {
protected int x = 10, y = 20;
}
class B {
public static void main(String args[]) {
A a = new A();
System.out.println(a.x + " " + a.y);
}
}
4) Java uses extends keyword for inheritence. Unlike C++, Java doesnt provide an inheritance
specifier like public, protected or private. Therefore, we cannot change the protection level of
members of base class in Java, if some data member is public or protected in base class then it
remains public or protected in derived class. Like C++, private members of base class are not
accessible in derived class.
Unlike C++, in Java, we dont have to remember those rules of inheritance which are
combination of base class access specifier and inheritance specifier.
5) In Java, methods are virtual by default. In C++, we explicitly use virtual keyword. See this G-
Fact for more details.
6) Java uses a separte keyword interface for interfaces, and abstract keyword for abstract classes
and abstract functions.
// An abstract method
abstract void myAbstractFun();
// A normal method
void fun() {
System.out.println("Inside My fun");
}
}
// An interface example
public interface myInterface {
// myAbstractFun() is public and abstract, even if we don't use these
keywords
void myAbstractFun(); // is same as public abstract void myAbstractFun()
}
// Note the implements keyword also.
public class myClass implements myInterface {
public void myAbstractFun() {
System.out.println("Inside My fun");
}
}
7) Unlike C++, Java doesnt support multiple inheritance. A class cannot inherit from more than
one class. A class can implement multiple interfaces though.
8 ) In C++, default constructor of parent class is automatically called, but if we want to call
parametrized constructor of a parent class, we must use Initializer list. Like C++, default
constructor of the parent class is automatically called in Java, but if we want to call parametrized
constructor then we must use super to call the parent constructor. See following Java example.
package main;
class Base {
private int b;
Base(int x) {
b = x;
System.out.println("Base constructor called");
}
}
class Main{
public static void main(String[] args) {
Derived obj = new Derived(1, 2);
}
}
Output:
// filename: Main.java
class Base {
Base() {
System.out.println("Base Class Constructor Called ");
}
}
But, if we want to call parameterized contructor of base class, then we can call it using super().
The point to note is base class comstructor call must be the first line in derived class
constructor. For example, in the following program, super(_x) is first line derived class
constructor.
// filename: Main.java
class Base {
int x;
Base(int _x) {
x = _x;
}
}
Output:
x = 10, y = 20
In C++, class member methods are non-virtual by default. They can be made virtual by using
virtual keyword. For example, Base::show() is non-virtual in following program and program
prints Base::show() called.
#include<iostream>
class Base {
public:
// non-virtual by default
void show() {
cout<<"Base::show() called";
}
};
int main()
{
Derived d;
Base &b = d;
b.show();
getchar();
return 0;
}
Adding virtual before definition of Base::show() makes program print Derived::show() called
In Java, methods are virtual by default and can be made non-virtual by using final keyword. For
example, in the following java program, show() is by default virtual and the program prints
Derived::show() called
class Base {
// virtual by default
public void show() {
System.out.println("Base::show() called");
}
}
Unlike C++ non-virtual behavior, if we add final before definition of show() in Base , then the
above program fails in compilation.
// filename Main.java
class Grandparent {
public void Print() {
System.out.println("Grandparent's Print()");
}
}
// filename Main.java
class Grandparent {
public void Print() {
System.out.println("Grandparent's Print()");
}
}
Grandparent's Print()
Parent's Print()
Child's Print()
class B extends A {
static void fun() {
System.out.println("B.fun()");
}
}
If we make both A.fun() and B.fun() as non-static then the above program would print B.fun().
class Base {
public void fun() {
System.out.println("Base fun");
}
}
class Base {
private void fun() {
System.out.println("Base fun");
}
}
We get compiler error fun() has private access in Base (See this). So the compiler tries to call
base class function, not derived class, means fun() is not overridden.
An inner class can access private members of its outer class. What if we extend an inner class
and create fun() in the inner class?
An Inner classes can access private members of its outer class, for example in the following
program, fun() of Inner accesses private data member msg which is fine by the compiler.
Output:
In the above program, we created an outer class and an inner class. We extended Inner from
Outer and created a method fun() in both Outer and Inner. If we observe our output, then it is
clear that the method fun() has not been overriden. It is so because private methods are bonded
during compile time and it is the type of the reference variable not the type of object that it
refers to that determines what method to be called.. As a side note, private methods may be
performance-wise better (compared to non-private and non-final methods) due to static binding.
Consider the following two programs. Program 1 fails in compilation and program 2 works fine.
Program 1
Program 2
Interfaces specify what a class must do and not how. It is the blueprint of the class.
An Interface is about capabilities like a Player may be an interface and any class
implementing Player must be able to (or must implement) move(). So it specifies a set of
methods that the class has to implement.
If a class implements an interface and does not provide method bodies for all functions
specified in the interface, then class must be declared abstract.
A Java library example is, Comparator Interface. If a class implements this interface, then
it can be used to sort a collection.
Interfaces are used to implement abstraction. So the question arises why use interfaces when we
have abstract classes?
The reason is, abstract classes may contain non-final variables, whereas variables in interface are
final, public and static.
// A simple interface
interface Player
{
final int id = 10;
int move();
}
// A simple interface
interface in1
{
// public, static and final
final int a = 10;
// Driver Code
public static void main (String[] args)
{
testClass t = new testClass();
t.display();
System.out.println(a);
}
}
Output:
Geek
10
1. Prior to JDK 8, interface could not define implementation. We can now add default
implementation for interface methods. This default implementation has special use and
does not affect the intention behind interfaces.
Suppose we need to add a new function in an existing interface. Obviously the old code
will not work as the classes have not implemented those new functions. So with the help
of default implementation, we will give a default body for the newly added functions. Then
the old codes will still work.
Output :
hello
2. Another feature that was added in JDK 8 is that we can now define static methods in
interfaces which can be called independently without an object. Note: these methods are
not inherited.
3. Output :
4. hello
Consider the following example, x is by default public static final and foo() is public even if
there are no specifiers.
interface Test {
int x = 10; // x is public static final and must be initialized here
void foo(); // foo() is public
}
1) private
2) default (when no access specifier is specified)
3) protected
4) public
But, the classes and interfaces themselves can have only two access specifiers when declared
outside any other class.
1) public
2) default (when no access specifier is specified)
We cannot declare class/interface with private or protected access specifiers. For example,
following program fails in compilation.
//filename: Main.java
protected class Test {}
}
}
Note : Nested interfaces and classes can have all access specifiers.
1) Like C++, in Java, an instance of an abstract class cannot be created, we can have references
of abstract class type though.
Output:
2) Like C++, an abstract class can contain constructors in Java. And a constructor of abstract
class is called when an instance of a inherited class is created. For example, the following is a
valid Java program.
Output:
3) In Java, we can have an abstract class without any abstract method. This allows us to create
classes that cannot be instantiated, but can only be inherited.
// An abstract class without any abstract method
abstract class Base {
void fun() { System.out.println("Base fun() called"); }
}
class Main {
public static void main(String args[]) {
Derived d = new Derived();
d.fun();
}
}
Output:
4) Abstract classes can also have final methods (methods that cannot be overridden). For
example, the following program compiles and runs fine.
class Main {
public static void main(String args[]) {
Base b = new Derived();
b.fun();
}
}
Output:
Exercise:
1. Is it possible to create abstract and final class in Java?
2. Is it possible to have an abstract method in a final class?
3. Is it possible to inherit from multiple abstract classes in Java?
Syntax:
Suppose we have an array/arraylist of our own class type, containing fields like rollno, name,
address, DOB etc and we need to sort the array based on Roll no or name?
Method 1: One obvious approach is to write our own sort() function using one of the standard
algorithms. This solution requires rewriting the whole sorting code for different criterion like Roll
No. and Name.
Method 2: Using comparator interface- Comparator interface is used to order the objects of user-
defined class. This interface is present java.util package and contains 2 methods compare(Object
obj1, Object obj2) and equals(Object element). Using comparator, we can sort the elements based
on data members. For instance it may be on rollno, name, age or anything else.
Method of Collections class for sorting List elements is used to sort the elements of List by the
given comparator.
Working Program:
// Constructor
public Student(int rollno, String name,
String address)
{
this.rollno = rollno;
this.name = name;
this.address = address;
}
// Driver class
class Main
{
public static void main (String[] args)
{
ArrayList<Student> ar = new ArrayList<Student>();
ar.add(new Student(111, "bbbb", "london"));
ar.add(new Student(131, "aaaa", "nyc"));
ar.add(new Student(121, "cccc", "jaipur"));
System.out.println("Unsorted");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
System.out.println("\nSorted by rollno");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
Collections.sort(ar, new Sortbyname());
System.out.println("\nSorted by name");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
}
}
Output:
Unsorted
111 bbbb london
131 aaaa nyc
121 cccc jaipur
Sorted by rollno
111 bbbb london
121 cccc jaipur
131 aaaa nyc
Sorted by name
131 aaaa nyc
111 bbbb london
121 cccc jaipu
By changing the return value in inside compare method you can sort in any order you want.
eg.for descending order just change the positions of a and b in above compare method.
class B implements A
{
// If we change public to anything else,
// we get compiler error
public void fun()
{
System.out.println("fun()");
}
}
class C
{
public static void main(String[] args)
{
B b = new B();
b.fun();
}
}
Output:
fun()
If we change fun() to anything other than public in class B, we get compiler error attempting to
assign weaker access privileges; was public
Interface in a class
Interfaces (or classes) can have only public and default access specifiers when declared outside
any other class (Refer this for details). This interface declared in a class can either be default,
public, private, protected. While implementing the interface, we mention the interface as
c_name.i_name where c_name is the name of the class in which it is nested and i_name is the
name of the interface itself.
Let us have a look at the following code:-
// Java program to demonstrate working of
// interface inside a class.
import java.util.*;
class Test
{
interface Yes
{
void show();
}
}
class A
{
public static void main(String[] args)
{
Test.Yes obj;
Testing t = new Testing();
obj=t;
obj.show();
}
}
show method of interface
The access specifier in above example is default. We can assign public, protected or private also.
Below is an example of protected. In this particular example, if we change access specifier to
private, we get compiler error because a derived class tries to access it.
class A
{
public static void main(String[] args)
{
Test.Yes obj;
Testing t = new Testing();
obj=t;
obj.show();
}
}
show method of interface
An interface can be declared inside another interface also. We mention the interface as
i_name1.i_name2 where i_name1 is the name of the interface in which it is nested and i_name2
is the name of the interface to be implemented.
// Java program to demonstrate working of
// interface inside another interface.
import java.util.*;
interface Test
{
interface Yes
{
void show();
}
}
class A
{
public static void main(String[] args)
{
Test.Yes obj;
Testing t = new Testing();
obj = t;
obj.show();
}
}
show method of interface
Note: In the above example, access specifier is public even if we have not written public. If we
try to change access specifier of interface to anything other than public, we get compiler error.
Remember, interface members can only be public..
class A
{
public static void main(String[] args)
{
Test.Yes obj;
Testing t = new Testing();
obj = t;
obj.show();
}
}
illegal combination of modifiers: public and protected
protected interface Yes
1. Comparable
2. Comparator
A comparable object is capable of comparing itself with another object. The class itself must
implements the java.lang.Comparable interface to compare its instances.
Consider a Movie class that has members like, rating, name, year. Suppose we wish to sort a list
of Movies based on year of release. We can implement the Comparable interface with the Movie
class, and we override the method compareTo() of Comparable interface.
// Constructor
public Movie(String nm, double rt, int yr)
{
this.name = nm;
this.rating = rt;
this.year = yr;
}
// Driver class
class Main
{
public static void main(String[] args)
{
ArrayList<Movie> list = new ArrayList<Movie>();
list.add(new Movie("Force Awakens", 8.3, 2015));
list.add(new Movie("Star Wars", 8.7, 1977));
list.add(new Movie("Empire Strikes Back", 8.8, 1980));
list.add(new Movie("Return of the Jedi", 8.4, 1983));
Collections.sort(list);
Output:
Now, suppose we want sort movies by their rating and names also. When we make a collection
element comparable(by having it implement Comparable), we get only one chance to implement
the compareTo() method. The solution is using Comparator.
Using Comparator
Unlike Comparable, Comparator is external to the element type we are comparing. Its a separate
class. We create multiple separate classes (that implement Comparator) to compare by different
members.
Collections class has a second sort() method and it takes Comparator. The sort() method invokes
the compare() to sort objects.
1. Create a class that implements Comparator (and thus the compare() method that does the
work previously done by compareTo()).
2. Make an instance of the Comparator class.
3. Call the overloaded sort() method, giving it both the list and the instance of the class that
implements Comparator.
// Constructor
public Movie(String nm, double rt, int yr)
{
this.name = nm;
this.rating = rt;
this.year = yr;
}
// Driver class
class Main
{
public static void main(String[] args)
{
ArrayList<Movie> list = new ArrayList<Movie>();
list.add(new Movie("Force Awakens", 8.3, 2015));
list.add(new Movie("Star Wars", 8.7, 1977));
list.add(new Movie("Empire Strikes Back", 8.8, 1980));
list.add(new Movie("Return of the Jedi", 8.4, 1983));
Output :
Sorted by rating
8.3 Force Awakens 2015
8.4 Return of the Jedi 1983
8.7 Star Wars 1977
8.8 Empire Strikes Back 1980
Sorted by name
Empire Strikes Back 8.8 1980
Force Awakens 8.3 2015
Return of the Jedi 8.4 1983
Star Wars 8.7 1977
Sorted by year
1977 8.7 Star Wars
1980 8.8 Empire Strikes Back
1983 8.4 Return of the Jedi
2015 8.3 Force Awakens
Comparable is meant for objects with natural ordering which means the object itself must
know how it is to be ordered. For example Roll Numbers of students. Whereas, Comparator
interface sorting is done through a separate class.
Logically, Comparable interface compares this reference with the object specified and
Comparator in Java compares two different class objects provided.
If any class implements Comparable interface in Java then collection of that object either
List or Array can be sorted automatically by using Collections.sort() or Arrays.sort()
method and objects will be sorted based on there natural order defined by CompareTo
method.
To summarize, if sorting of objects needs to be based on natural order then use Comparable
whereas if you sorting needs to be done on attributes of different objects, then use Comparator
in Java.
Multithreading in Java
Multithreading is a Java feature that allows concurrent execution of two or more parts of a
program for maximum utilization of CPU. Each part of such program is called a thread. So,
threads are light-weight processes within a process.
We create a class that extends the java.lang.Thread class. This class overrides the run() method
available in the Thread class. A thread begins its life inside run() method. We create an object of
our new class and call start() method to start the execution of a thread. Start() invokes the run()
method on the Thread object.
}
catch (Exception e)
{
// Throwing an exception
System.out.println ("Exception is caught");
}
}
}
// Main Class
public class Multithread
{
public static void main(String[] args)
{
int n = 8; // Number of threads
for (int i=0; i<8; i++)
{
MultithreadingDemo object = new MultithreadingDemo();
object.start();
}
}
}
Output :
Thread 8 is running
Thread 9 is running
Thread 10 is running
Thread 11 is running
Thread 12 is running
Thread 13 is running
Thread 14 is running
Thread 15 is running
We create a new class which implements java.lang.Runnable interface and override run()
method. Then we instantiate a Thread object and call start() method on this object.
}
catch (Exception e)
{
// Throwing an exception
System.out.println ("Exception is caught");
}
}
}
// Main Class
class Multithread
{
public static void main(String[] args)
{
int n = 8; // Number of threads
for (int i=0; i<8; i++)
{
Thread object = new Thread(new MultithreadingDemo());
object.start();
}
}
}
Output :
Thread 8 is running
Thread 9 is running
Thread 10 is running
Thread 11 is running
Thread 12 is running
Thread 13 is running
Thread 14 is running
Thread 15 is running
1. If we extend the Thread class, our class cannot extend any other class because Java doesnt
support multiple inheritance. But, if we implement the Runnable interface, our class can still
extend other base classes.
2. We can achieve basic functionality of a thread by extending Thread class because it provides
some inbuilt methods like yield(), interrupt() etc. that are not available in Runnable interface.
Synchronized in Java
Multi-threaded programs may often come to a situation where multiple threads try to access the
same resources and finally produce erroneous and unforeseen results.
So it needs to be made sure by some synchronization method that only one thread can access the
resource at a given point of time.
Java provides a way of creating threads and synchronizing their task by using synchronized blocks.
Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in
Java is synchronized on some object. All synchronized blocks synchronized on the same object
can only have one thread executing inside them at a time. All other threads attempting to enter the
synchronized block are blocked until the thread inside the synchronized block exits the block.
This synchronization is implemented in Java with a concept called monitors. Only one thread can
own a monitor at a given time. When a thread acquires a lock, it is said to have entered the monitor.
All other threads attempting to enter the locked monitor will be suspended until the first thread
exits the monitor.
// Driver class
class SyncDemo
{
public static void main(String args[])
{
Sender snd = new Sender();
ThreadedSend S1 =
new ThreadedSend( " Hi " , snd );
ThreadedSend S2 =
new ThreadedSend( " Bye " , snd );
Output:
Sending Hi
Hi Sent
Sending Bye
Bye Sent
In the above example, we chose to synchronize the Sender object inside the run() method of the
ThreadedSend class. Alternately, we could define the whole send() block as synchronized and
it would produce the same result. Then we dont have to synchronize the Message object inside
the run() method in ThreadedSend class.
// An alternate implementation to demonstrate
// that we can use synchronized with method also.
class Sender
{
public synchronized void send(String msg)
{
System.out.println("Sending\t" + msg );
try
{
Thread.sleep(1000);
}
catch (Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n" + msg + "Sent");
}
}
Output:
value of j = 0
Nested Inner class can access any private instance variable of outer class. Like any other
instance variable, we can have access modifier private, protected, public and default modifier.
Like class, interface can also be nested and can have access specifiers.
class Outer {
// Simple nested inner class
class Inner {
public void show() {
System.out.println("In a nested class method");
}
}
}
class Main {
public static void main(String[] args) {
Outer.Inner in = new Outer().new Inner();
in.show();
}
}
Output:
As a side note, we cant have static method in a nested inner class because an inner class is
implicitly associated with an object of its outer class so it cannot define any static method for
itself. For example the following program doesnt compile.
class Outer {
void outerMethod() {
System.out.println("inside outerMethod");
}
class Inner {
public static void main(String[] args){
System.out.println("inside inner class Method");
}
}
}
Output:
An interface can also be nested and nested interfaces have some interesting properties. We will
be covering nested interfaces in the next post.
class Outer {
void outerMethod() {
System.out.println("inside outerMethod");
// Inner class is local to outerMethod()
class Inner {
void innerMethod() {
System.out.println("inside innerMethod");
}
}
Inner y = new Inner();
y.innerMethod();
}
}
class MethodDemo {
public static void main(String[] args) {
Outer x = new Outer();
x.outerMethod();
}
}
Output
Inside outerMethod
Inside innerMethod
Method Local inner classes cant use local variable of outer method until that local variable is
not declared as final. For example, the following code generates compiler error (Note that x is
not final in outerMethod() and innerMethod() tries to access it)
class Outer {
void outerMethod() {
int x = 98;
System.out.println("inside outerMethod");
class Inner {
void innerMethod() {
System.out.println("x= "+x);
}
}
Inner y = new Inner();
y.innerMethod();
}
}
class MethodLocalVariableDemo {
public static void main(String[] args) {
Outer x=new Outer();
x.outerMethod();
}
}
Output:
But the following code compiles and runs fine (Note that x is final this time)
class Outer {
void outerMethod() {
final int x=98;
System.out.println("inside outerMethod");
class Inner {
void innerMethod() {
System.out.println("x = "+x);
}
}
Inner y = new Inner();
y.innerMethod();
}
}
class MethodLocalVariableDemo {
public static void main(String[] args){
Outer x = new Outer();
x.outerMethod();
}
}
Output-:
Inside outerMethod
X = 98
The main reason we need to declare a local variable as a final is that local variable lives on stack
till method is on the stack but there might be a case the object of inner class still lives on the
heap.
Method local inner class cant be marked as private, protected, static and transient but can be
marked as abstract and final, but not both at the same time.
class Outer {
private static void outerMethod() {
System.out.println("inside outerMethod");
}
Output
class Demo {
void show() {
System.out.println("i am in show method of super class");
}
}
class Flavor1Demo {
Output
In the above code, we have two class Demo and Flavor1Demo. Here demo act as super class and
anonymous class acts as a subclass, both classes have a method show(). In anonymous class
show() method is overridden.
class Flavor2Demo {
interface Hello {
void show();
}
Output:
i am in anonymous class
In above code we create an object of anonymous inner class but this anonymous inner class is an
implementer of the interface Hello. Any anonymous inner class can implement only one
interface at one time. It can either extend a class or implement interface at a time.
import java.io.*;
public class GFG
{
// Initializer block starts..
{
// This code is executed before every constructor.
System.out.println("Common part of constructors invoked !!");
}
// Initializer block ends
public GFG()
{
System.out.println("Default Constructor invoked");
}
public GFG(int x)
{
System.out.println("Parametrized constructor invoked");
}
public static void main(String arr[])
{
GFG obj1, obj2;
obj1 = new GFG();
obj2 = new GFG(0);
}
}
Output:
The order of initialization constructors and initializer block doesnt matter, initializer block is
always executed before constructor. See this for example.
What if we want to execute some code once for all objects of a class?
We use Static Block in Java
// Concatenates to StringBuilder
public static void concat2(StringBuilder s2)
{
s2.append("World");
}
// Concatenates to StringBuffer
public static void concat3(StringBuffer s3)
{
s3.append("World");
}
Output:
String: Hello
StringBuilder: HelloWorld
StringBuffer: HelloWorld
Explanation:
1. Concat1 : In this method, we pass a string Geeks and perform s1 = s1 + forgeeks. The
string passed from main() is not changed, this is due to the fact that String is immutable.
Altering the value of string creates another object and s1 in concat1() stores reference of new
string. References s1 in main() and cocat1() refer to different strings.
Conclusion:
Objects of String are immutable, and objects of StringBuffer and StringBuilder are
mutable.
StringBuffer and StringBuilder are similar, but StringBuilder is faster and preferred over
StringBuffer for single threaded program. If thread safety is needed, then StringBuffer is
used.
Output:
inside A
A's finally
Exception caught
inside B
B's finally
finalize: The automatic garbage collector call the finalize() method just before actually
destroying the object. A class can therefore override the finalize() method from the Object class
in order to define custom behavior during garbage collection.Syntax:
Note that there is no guarantee about the time when finalize is called. It may be called any time
after the object is not being referred anywhere (cab be garbage collected).
For example factorial of 100 contains 158 digits in it so we cant store it in any primitive data
type available. We can store as large Integer as we want in it. There is no theoretical limit on the
upper bound of the range because memory is allocated dynamically but practically as memory is
limited you can store a number which has Integer.MAX_VALUE number of bits in it which
should be sufficient to store mostly all large values.
return f;
}
// Driver method
public static void main(String args[]) throws Exception
{
int N = 20;
System.out.println(factorial(N));
}
}
Output:
2432902008176640000
If we have to write above program in C++, that would be too large and complex, we can look at
Factorail of Large Number.
In this way BigInteger class is very handy to use because of its large method library and it is also
used a lot in competitive programming.
Now below is given a list of simple statements in primitive arithmetic and its analogous
statement in terms of BigInteger objects.
Declaration
int a, b;
BigInteger A, B;
Initialization:
a = 54;
b = 23;
A = BigInteger.valueOf(54);
B = BigInteger.valueOf(37);
And for Integers available as string you can initialize them as:
A = new BigInteger(54);
B = new BigInteger(123456789123456789);
Some constant are also defined in BigInteger class for ease of initialization :
A = BigInteger.ONE;
// Other than this, available constant are BigInteger.ZERO
// and BigInteger.TEN
Mathematical operations:
int c = a + b;
BigInteger C = A.add(B);
Other similar function are subtract() , multiply(), divide(), remainder()
But all these function take BigInteger as their argument so if we want these operation with
integers or string convert them to BigInteger before passing them to functions as shown below:
Comparison:
Actually compareTo returns -1(less than), 0(Equal), 1(greater than) according to values.
if (A.equals(B)) {} // A is equal to B
SPOJ Problems:
So after above knowledge of function of BigInteger class, we can solve many complex problem
easily, but remember as BigInteger class internally uses array of integers for processing, the
operation on object of BigIntegers are not as fast as on primitives that is add function on
BigIntgers doesnt take constant time it takes time proportional to length of BigInteger, so
complexity of program will change accordingly.
// Parameterized constructor
Test(int a, int b)
{
this.a = a;
this.b = b;
}
void display()
{
//Displaying value of variables a and b
System.out.println("a = " + a + " b = " + b);
}
Output:
a = 10 b = 20
//Default constructor
Test()
{
this(10, 20);
System.out.println("Inside default constructor \n");
}
//Parameterized constructor
Test(int a, int b)
{
this.a = a;
this.b = b;
System.out.println("Inside parameterized constructor");
}
Output:
//Default constructor
Test()
{
a = 10;
b = 20;
}
Output:
a = 10 b = 20
4. Using this keyword as method parameter
//Default constructor
Test()
{
a = 10;
b = 20;
}
Output:
a = 10 b = 20
Serialization in Java
Serialization is a mechanism of converting the state of an object into a byte stream.
Deserialization is the reverse process where the byte stream is used to recreate the actual Java
object in memory. This mechanism is used to persist the object.
The byte stream created is platform independent. So, the object serialized on one platform can be
deserialized on a different platform.
To make a Java object serializable we implement the java.io.Serializable interface.
import java.io.*;
// Default constructor
public Demo(int a, String b)
{
this.a = a;
this.b = b;
}
class Test
{
public static void main(String[] args)
{
Demo object = new Demo(1, "HelloWorld");
String filename = "file.ser";
// Serialization
try
{
//Saving of object in a file
FileOutputStream file = new FileOutputStream(filename);
ObjectOutputStream out = new ObjectOutputStream(file);
out.close();
file.close();
System.out.println("Object has been serialized");
catch(IOException ex)
{
System.out.println("IOException is caught");
}
// Deserialization
try
{
// Reading the object from a file
FileInputStream file = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(file);
in.close();
file.close();
catch(IOException ex)
{
System.out.println("IOException is caught");
}
catch(ClassNotFoundException ex)
{
System.out.println("ClassNotFoundException is caught");
}
}
}
Output :
Till now, we were always taught Comments do not Execute. Let us see today The
comments that execute
Output:
comment executed
The reason for this is that the Java compiler parses the unicode character \u000d as a new line
and gets transformed into:
i = 0 j = 0
i = 0 j = 1
i = 0 j = 2
i = 0 j = 3
i = 0 j = 4
i = 1 j = 0
i = 1 j = 1
i = 1 j = 2
i = 1 j = 3
i = 1 j = 4
i = 2 j = 0
i = 2 j = 1
i = 2 j = 2
i = 2 j = 3
i = 2 j = 4
You can also use continue to jump to start of the named loop.
We can also use break (or continue) in a nested if-else with for loops in order to break several
loops with if-else, so one can avoid setting lot of flags and testing them in the if-else in order to
continue or not in this nested level.
There is no foreach loop in C, but both C++ and Jave support foreach type of loop. In C++, it
was introduced in C++ 11 and Java in JDK 1.5.0
The keyword used for foreach loop is for in both C++ and Java.
C++ Program:
int main()
{
int arr[] = {10, 20, 30, 40};
Output:
10
20
30
40
Java program
Output:
10
20
30
40
For example,
// A Java program to demonstrate flexible nature of
// java.lang.Object
public class GFG
{
public static void main(String arr[])
{
Object y;
y = 'A';
System.out.println(y.getClass().getName());
y = 1;
System.out.println(y.getClass().getName());
y = "Hi";
System.out.println(y.getClass().getName());
y = 1.222;
System.out.println(y.getClass().getName());
y = false;
System.out.println(y.getClass().getName());
}
}
Output:
java.lang.Character
java.lang.Integer
java.lang.String
java.lang.Double
java.lang.Boolean
Such a behaviour can be attributed to the fact that java.lang.Object is super class to all other
classes. Hence, a reference variable of type Object can be practically used to refer objects of any
class. So, we could also assign y = new InputStreamReader(System.in) in the above code!
A Simple Solution is to swap members. For example, if the class Car has only one integer
attribute say no (car number), we can swap cars by simply swapping the members of two cars.
// Driver method
public static void main(String[] args)
{
Car c1 = new Car(1);
Car c2 = new Car(2);
swap(c1, c2);
System.out.println("c1.no = " + c1.no);
System.out.println("c2.no = " + c2.no);
}
}
Output:
c1.no = 2
c2.no = 1
// Constructor
Car(int model, int no)
{
this.model = model;
this.no = no;
}
// Utility method to print Car
void print()
{
System.out.println("no = " + no +
", model = " + model);
}
}
// Driver method
public static void main(String[] args)
{
Car c1 = new Car(101, 1);
Car c2 = new Car(202, 2);
swap(c1, c2);
c1.print();
c2.print();
}
}
Output:
no = 1, model = 101
no = 2, model = 202
As we can see from above output, the objects are not swapped. We have discussed in a previous
post that parameters are passed by value in Java. So when we pass c1 and c2 to swap(), the
function swap() creates a copy of these references.
Solution is to use Wrapper Class If we create a wrapper class that contains references of Car,
we can swap cars by swapping references of wrapper class.
// Constructor
Car(int model, int no)
{
this.model = model;
this.no = no;
}
// Constructor
CarWrapper(Car c) {this.c = c;}
}
// Driver method
public static void main(String[] args)
{
Car c1 = new Car(101, 1);
Car c2 = new Car(202, 2);
CarWrapper cw1 = new CarWrapper(c1);
CarWrapper cw2 = new CarWrapper(c2);
swap(cw1, cw2);
cw1.c.print();
cw2.c.print();
}
}
Output:
no = 2, model = 202
no = 1, model = 101
So a wrapper class solution works even if the user class doesnt have access to members of the
class whose objects are to be swapped.
Python: In Python, there is a simple and syntactically neat construct to swap variables, we just
need to write x, y = y, x.
The above solution is wrong in C/C++ as it causes undefined behaviour (compiler is free to
behave in any way). The reason is, modifying a variable more than once in an expression causes
undefined behaviour if there is no sequence point between the modifications.
However, we can use comma to introduce sequence points. So the modified solution is
Java: In Java, rules for subexpression evaluations are clearly defined. The left hand operand is
always evaluated before right hand operand (See this for more details). In Java, the expression x
^= y ^= x ^= y; doesnt produce the correct result according to Java rules. It makes x = 0.
However, we can use x = x ^ y ^ (y = x); Note the expressions are evaluated from left to right.
If x = 5 and y = 10 initially, the expression is equivalent to x = 5 ^ 10 ^ (y = 5);. Note that we
cant use this in C/C++ as in C/C++, it is not defined whether left operand or right operand is
executed for any operator (See this for more details)
As you can easily guess, like any method we can provide access specifier to the constructor. If its
made private, then it can only be accessed inside the class.
There are various scenarios where we can use private constructors. The major ones are
As the name implies, a class is said to be singleton if it limits the number of objects of that class
to one.
Singleton classes are employed extensively in concepts like Networking and Database
Connectivity.
The constructor of singleton class would be private so there must be another way to get the instance
of that class. This problem is resolved using a class member instance and a factory method to
return the class member.
class MySingleton
{
static MySingleton instance = null;
public int x = 10;
return instance;
}
}
// Driver Class
class Main
{
public static void main(String args[])
{
MySingleton a = MySingleton.getInstance();
MySingleton b = MySingleton.getInstance();
a.x = a.x + 10;
System.out.println("Value of a.x = " + a.x);
System.out.println("Value of b.x = " + b.x);
}
}
Output:
Value of a.x = 20
Value of b.x = 20
We changed value of a.x, value of b.x also got updated because both a and b refer to same
object, i.e., they are objects of a singleton class.
Generics in Java
Generics in Java is similar to templates in C++. The idea is to allow type (Integer, String, etc
and user defined types) to be a parameter to methods, classes and interfaces. For example,
classes like HashSet, ArrayList, HashMap, etc use generics very well. We can use them for any
type.
Generic Class
Like C++, we use <> to specify parameter types in generic class creation. To create objects of
generic class, we use following syntax.
// To create an instance of generic class
BaseType <Type> obj = new BaseType <Type>()
Output:
15
HelloWorld
obj.print();
}
}
Output:
GfG
15
Generic Functions:
We can also write generic functions that can be called with different types of arguments based on
the type of arguments passed to generic method, the compiler handles each method.
// A Simple Java program to show working of user defined
// Generic functions
class Test
{
// A Generic method example
static <T> void genericDisplay (T element)
{
System.out.println(element.getClass().getName() +
" = " + element);
}
// Driver method
public static void main(String[] args)
{
// Calling generic method with Integer argument
genericDisplay(11);
Output :
java.lang.Integer = 11
java.lang.String = HelloWorld
java.lang.Double = 1.0
Advantages of Generics:
Programs that uses Generics has got many benefits over non-generic code.
1. Code Reuse: We can write a method/class/interface once and use for any type we want.
2. Type Safety : Generics make errors to appear compile time than at run time (Its always
better to know problems in your code at compile time rather than making your code fail
at run time). Suppose you want to create an ArrayList that store name of students and if
by mistake programmer adds an integer object instead of string, compiler allows it. But,
when we retrieve this data from ArrayList, it causes problems at runtime.
class Test
{
public static void main(String[] args)
{
// Creatinga an ArrayList without any type specified
ArrayList al = new ArrayList();
al.add("Sachin");
al.add("Rahul");
al.add(10); // Compiler allows this
String s1 = (String)al.get(0);
String s2 = (String)al.get(1);
// Causes Runtime Exception
String s3 = (String)al.get(2);
}
}
Output :
class Test
{
public static void main(String[] args)
{
// Creating a an ArrayList with String specified
ArrayList <String> al = new ArrayList<String> ();
al.add("Sachin");
al.add("Rahul");
String s1 = (String)al.get(0);
String s2 = (String)al.get(1);
String s3 = (String)al.get(2);
}
}
Output:
Individual Type Casting is not needed: If we do not use generics, then, in the above example
every-time we retrieve data from ArrayList, we have to typecast it. Typecasting at every retrieval
operation is a big headache. If we already know that our list only holds string data then we need
not to typecast it every time.
// We don't need to typecast individual members of ArrayList
import java.util.*;
class Test
{
public static void main(String[] args)
{
// Creating a an ArrayList with String specified
ArrayList <String> al = new ArrayList<String> ();
al.add("Sachin");
al.add("Rahul");
Implementing generic algorithms: By using generics, we can implement algorithms that work
on different types of objects and at the same they are type safe too.s
Reflection in Java
Reflection is an API which is used to examine or modify the behavior of methods, classes,
interfaces at runtime.
The required classes for reflection are provided under java.lang.reflect package.
Reflection gives us information about the class to which an object belongs and also the
methods of that class which can be executed by using the object.
Through reflection we can invoke methods at runtime irrespective of the access specifier
used with them.
1. Class The getClass() method is used to get the name of the class to which an object
belongs.
2. Constructors The getConstructors() method is used to get the public constructors of the
class to which an object belongs.
3. Methods The getMethods() method is used to get the public methods of the class to
which an objects belongs.
class Demo
{
public static void main(String args[]) throws Exception
{
// Creating object whose property is to be checked
Test obj = new Test();
Output :
Important observations :
1. We can invoke an method through reflection if we know its name and parameter types.
We use below two methods for this purpose
getDeclaredMethod() : To create an object of method to be invoked. The syntax for this
method is
2. Class.getDeclaredMethod(name, parametertype)
3. name- the name of method whose object is to be created
parametertype - parameter is an array of Class objects
Method.invoke(Object, parameter)
If the method of the class doesnt accepts any
parameter then null is passed as argument.
4. Through reflection we can access the private variables and methods of a class with the
help of its class object and invoke the method by using the object as discussed above. We
use below two methods for this purpose.
Drawbacks:
o Performance Overhead: Reflective operations have slower performance than
their non-reflective counterparts, and should be avoided in sections of code which
are called frequently in performance-sensitive applications.
o Exposure of Internals: Reflective code breaks abstractions and therefore may
change behavior with upgrades of the platform.
Assertions in Java
An assertion allows testing the correctness of any assumptions that have been made in the
program.
Assertion is achieved using the assert statement in Java. While executing assertion, it is believed
to be true. If it fails, JVM throws an error named AssertionError. It is mainly used for testing
purposes during development.
The assert statement is used with a Boolean expression and can be written in two different ways.
First way :
assert expression;
Second way :
Example of Assertion:-
class Test
{
public static void main( String args[] )
{
int value = 15;
assert value >= 20 : " Underweight";
System.out.println("value is "+value);
}
}
Output:
value is 15
Enabling Assertions
By default, assertions are disabled. We need to run the code as given. The syntax for enabling
assertion statement in Java source code is:
java ea Test
Or
Disabling Assertions
java da Test
Or
Arguments to private methods. Private arguments are provided by developers code only
and developer may want to check his/her assumptions about arguments.
Conditional cases.
Conditions at the beginning of any method.
Note : Note that the <Key, Value> pair used in HashMap/TreeMap. Here, <Key, Value> simply
refers to a pair of values that are stored together.
Example:
Output:
true false
String toString() : This method will return the String representation of the Pair.
K getKey() : It returns key for the pair.
V getValue() : It returns value for the pair.
int hashCode() : Generate a hash code for the Pair.
Note : You need to have Java 8 installed on your machine in order to run the below
program.
class Test
{
/* This method returns a Pair which hasmaximum score*/
public static Pair <String,Integer>
getMaximum(ArrayList < Pair <String,Integer> > l)
{
// Assign minimum value initially
int max = Integer.MIN_VALUE;
Output :
Platform independence means that execution of your program does not dependent on type of
operating system(it could be any : Linux, windows, Mac ..etc). So compile code only once and
run it on any System (In C/C++, we need to compile the code for every machine on which we
run it). Java is both compiler(javac) and interpreter(jvm) based lauguage. Your java source code
is first compiled into byte code using javac compiler. This byte code can be easily converted to
equivalent machine code using JVM. JVM(Java Virtual Machine) is available in all operating
systems we install. Hence, byte code generated by javac is universal and can be converted to
machine code on any operating system, this is the reason why java is platform independent.
Final keyword in java is used to restrict usage of variable, class and method.
Variable: Value of Final variable is constant, you can not change it.
Method: you cant override a Final method.
Class: you cant inherit from Final class.
String is an Immutable class, i.e. you can not modify its content once created. While
StringBuffer is a mutable class, means you can change its content later. Whenever we alter
content of String object, it creates a new string and refer to that,it does not modify the existing
one. This is the reason that the performance with StringBuffer is better than with String.
Refer this for details.
Java supports multiple inheritance but not through classes, it supports only through its interfaces.
The reason for not supporting multiple inheritance is to avoid the conflict and complexity arises
due to it and keep Java a Simple Object Oriented Language. If we recall this in C++, there is a
special case of multiple inheritance (diamond problem) where you have a multiple inheritance
with two classes which have methods in conflicts. So, Java developers decided to avoid such
conflicts and didnt allow multiple inheritance through classes at all.
Top level classes in java cant be private or protected, but inner classes in java can. The reason
for not making a top level class as private is very obvious, because nobody can see a private
class and thus they can not use it. Declaring a class as protected also doesnt make any sense.
The only difference between default visibility and protected visibility is that we can use it in any
package by inheriting it. Since in java there is no such concept of package inheritance, defining a
class as protected is no different from default.
What is the difference between throw and throws in Java Exception Handling?
throw keyword is used to throw Exception from any method or static block whereas
throws is used to indicate that which Exception can possibly be thrown by this method
If any method throws checked Exception, then caller can either handle this
exception(using try catch block )or can re throw it by declaring another throws clause in
method declaration.
throw clause can be used in any part of code where you feel a specific exception needs to
be thrown to the calling method
E.g.
throw
throw new Exception(You have some exception)
throw new IOException(Connection failed!!)
throws
throws IOException, NullPointerException, ArithmeticException
Unlike c++ , we dont need to destroy objects explicitly in Java. Garbage Collector does that
automatically for us. Garbage Collector checks if no references to an object exist, that object is
assumed to be no longer required, and the memory occupied by the object can be freed.
Sometimes an object can hold non-java resources such as file handle or database connection,
then you want to make sure these resources are also released before object is destroyed. To
perform such operation Java provide protected void finalize() in object class. You can override
this method in your class and do the required tasks. Right before an object is freed, the java run
time calls the finalize() method on that object. Refer this for more details.
Set and List both are child interface of Collection interface. There are following two main
differences between them
List can hold duplicate values but Set doesnt allow this.
In List interface data is present in the order you inserted but in the case of Set insertion
order is not preserved.
What will happen if you put System.exit(0) on try or catch block? Will finally block
execute?
By Calling System.exit(0) in try or catch block, we can skip the finally block. System.exit(int)
method can throw a SecurityException. If Sysytem.exit(0) exits the JVM without throwing that
exception then finally block will not execute. But, if System.exit(0) does throw security
exception then finally block will be executed.
Annotations in Java
Annotations are used to provide supplement information about a program.
Categories of Annotations
Example: - @TestAnnotation()
Example: - @TestAnnotation(testing);
3. Full Annotations:
These annotations consist of multiple data members/ name, value, pairs.
@Deprecated Annotation
It is a marker annotation. It indicates that a declaration is obsolete and has been replaced
by a newer form.
The Javadoc @deprecated tag should be used when an element has been deprecated.
@deprecated tag is for documentation and @Deprecated annotation is for runtime
reflection.
@deprecated tag has higher priority than @Deprecated annotation when both are together
used.
Output:
Deprecatedtest display()
@Override Annotation
It is a marker annotation that can be used only on methods. A method annotated with
@Override must override a method from a superclass. If it doesnt, a compile-time error will
result (see this for example). It is used to ensure that a superclass method is actually overridden,
and not simply overloaded.
Example:-
class Base
{
public void Display()
{
System.out.println("Base display()");
}
Derived display()
@SuppressWarnings
It is used to inform the compiler to suppress specified compiler warnings. The warnings to
suppress are specified by name, in string form. This type of annotation can be applied to any type
of declaration.
Java groups warnings under two categories. They are : deprecation and unchecked.. Any
unchecked warning is generated when a legacy code interfaces with a code that use generics.
class DeprecatedTest
{
@Deprecated
public void Display()
{
System.out.println("Deprecatedtest display()");
}
}
Output:
Deprecatedtest display()
@Documented Annotations
It is a marker interface that tells a tool that an annotation is to be documented. Annotations are
not included by Javadoc comments. Use of @Documented annotation in the code enables tools
like Javadoc to process it and include the annotation type information in the generated document.
@Target
It is designed to be used only as an annotation to another annotation. @Target takes one
argument, which must be constant from the ElementType enumeration. This argument specifies
the type of declarations to which the annotation can be applied. The constants are shown below
along with the type of declaration to which they correspond.
We can specify one or more of these values in a @Targetannotation. To specify multiple values,
we must specify them within a braces-delimited list. For example, to specify that an annotation
applies only to fields and local variables, you can use this @Target annotation:
@Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE}) @Retention
Annotation It determines where and how long the annotation is retent. The 3 values that the
@Retention annotation can have:
SOURCE: Annotations will be retained at the source level and ignored by the compiler.
CLASS: Annotations will be retained at compile time and ignored by the JVM.
@Inherited
@Inherited is a marker annotation that can be used only on annotation declaration. It affects only
annotations that will be used on class declarations. @Inherited causes the annotation for a
superclass to be inherited by a subclass. Therefore, when a request for a specific annotation is
made to the subclass, if that annotation is not present in the subclass, then its superclass is
checked. If that annotation is present in the superclass, and if it is annotated with @Inherited,
then that annotation will be returned.
User-defined annotations can be used to annotate program elements, i.e. variables, constructors,
methods, etc. These annotations can be applied just before declaration of an element
(constructor, method, classes, etc).
Syntax of Declaration:-
AnnotationName is an identifier.
Parameter should not be associated with method declarations and throws clause should
not be used with method declaration.
Parameters will not have a null value but can have a default value.
default value is optional.
Return type of method should be either primitive, enum, string, class name or array of
primitive, enum, string or class name type.
package source;
// A Java program to demonstrate user defined annotations
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// user-defined annotation
@Documented
@Retention(RetentionPolicy.RUNTIME)
@ interface TestAnnotation
{
String Developer() default "Rahul";
String Expirydate();
} // will be retained at runtime
@TestAnnotation(Developer="Anil", Expirydate="01-10-2021")
void fun2()
{
System.out.println("Test method 2");
}
Output :
Hello
But it is strongly recommended that one must read this blog completely and try and decipher the
nitty gritty of what goes into implementing a hash map and then try to write the code yourself.
Background
Every hash-table stores data in the form of (key, value) combination. Interestingly every key is
unique in a Hash Table but values can repeat which means values can be same for different keys
present in it. Now as we observe in an array to fetch a value we provide the position/index
corresponding to the value in that array. In a Hash Table, instead of an index we use a key to fetch
the value corresponding to that key. Now the entire process is described below
Every time a key is generated. The key is passed to a hash function. Every hash function has two
parts a Hash code and a Compressor.
Hash code is an Integer number (random or nonrandom). In Java every Object has its own hash
code. We will use the hash code generated by JVM in our hash function and to compress the hash
code we modulo(%) the hash code by size of the hash table. So modulo operator is compressor in
our implementation.
The entire process ensures that for any key, we get an integer position within the size of the Hash
Table to insert the corresponding value.
So the process is simple, user gives a (key, value) pair set as input and based on the value generated
by hash function an index is generated to where the value corresponding to the particular key is
stored. So whenever we need to fetch a value corresponding to a key that is just O(1).
This picture stops being so rosy and perfect when the concept of hash collision is introduced.
Imagine for different key values same block of hash table is allocated now where do the previously
stored values corresponding to some other previous key go. We certainly cant replace it .That will
be disastrous! To resolve this issue we will use Separate Chaining Technique, Please note there
are other open addressing techniques like double hashing and linear probing whose efficiency is
almost same as to that of separate chaining and you can read more about them at Link 1 Link 2
Link3
Now what we do is make a linked list corresponding to the particular bucket of the Hash Table, to
accommodate all the values corresponding to different keys who map to the same bucket.
Now there may be a scenario that all the keys get mapped to the same bucket and we have a linked
list of n(size of hash table) size from one single bucket, with all the other buckets empty and this
is the worst case where a hash table acts a linked list and searching is O(n).So what do we do ?
Load Factor
If n be the total number of buckets we decided to fill initially say 10 and lets say 7 of them got
filled now, so the load factor is 7/10=0.7.
In our implementation whenever we add a key value pair to the Hash Table we check the load
factor if it is greater than 0.7 we double the size of our hash table.
Implementation
We will try to make a generic map without putting any restrictions on the data type of the key and
the value . Also every hash node needs to know the next node it is pointing to in the linked list so
a next pointer is also required.
get(K key) : returns the value corresponding to the key if the key is present in HT (Hast
Table)
getSize() : return the size of the HT
add() : adds new valid key, value pair to the HT, if already present updates the value
remove() : removes the key, value pair
isEmpty() : returns true if size is zero
Every Hash Map must have an array list/linked list with an initial size and a bucket size which gets
increased by unity every time a key, value pair is added and decreased by unity every time a node
is deleted
A Helper Function is implemented to get the index of the key, to avoid redundancy in other
functions like get, add and remove. This function uses the in built java function to generate a
hash code and we compress the hash code by the size of the HT so that the index is within the
range of the size of the HT
get()
The get function just takes a key as an input and returns the corresponding value if the key is
present in the table otherwise returns null. Steps are:
remove()
Fetch the index corresponding to the input key using the helper function
The traversal of linked list similar like in get() but what is special here is that one needs to
remove the key along with finding it and two cases arise
If the key to be removed is present at the head of the linked list
If the key to be removed is not present at head but somewhere else
add()
Now to the most interesting and challenging function of this entire implementation.It is
interesting because we need to dynamically increase the size of our list when load factor is above
the value we specified.
Just like remove steps till traversal and adding and two cases (addition at head spot or non-
head spot) remain the same.
Towards the end if load factor is greater than 0.7
We double the size of the array list and then recursively call add function on existing keys
because in our case hash value generated uses the size of the array to compress the inbuilt
JVM hash code we use ,so we need to fetch new indices for the existing keys. This is very
important to understand please re read this paragraph till you get a hang of what is
happening in the add function.
Java does in its own implementation of Hash Table uses Binary Search Tree if linked list
corresponding to a particular bucket tend to get too long.
// A node of chains
class HashNode<K, V>
{
K key;
V value;
// Constructor
public HashNode(K key, V value)
{
this.key = key;
this.value = value;
}
}
// Reduce size
size--;
// Remove key
if (prev != null)
prev.next = head.next;
else
bucketArray.set(bucketIndex, head.next);
return head.value;
}
Output :
3
4
null
2
false
Java provides two function under java.math.BigInteger to deal with Prime Numbers.
class CheckPrimeTest
{
//Function to check and return prime numbers
static boolean checkPrime(long n)
{
// Converting long to BigInteger
BigInteger b = new BigInteger(String.valueOf(n));
return b.isProbablePrime(1);
}
// Driver method
public static void main (String[] args)
throws java.lang.Exception
{
long n = 13;
System.out.println(checkPrime(n));
}
}
Output:
true
nextProbablePrime() : Another method present in BigInteger class. This functions returns the
next Prime Number greater than current BigInteger.
class NextPrimeTest
{
// Function to get nextPrimeNumber
static long nextPrime(long n)
{
BigInteger b = new BigInteger(String.valueOf(n));
return Long.parseLong(b.nextProbablePrime().toString());
}
// Driver method
public static void main (String[] args)
throws java.lang.Exception
{
long n = 14;
System.out.println(nextPrime(n));
}
}
Output:
17
Myth about the file name and class name in
Java
The first lecture note given during java class is In java file name and class name should be the
same. When the above law is violated a compiler error message will appear as below
Output:
javac Trial.java
Trial.java:9: error: class Geeks is public, should be
declared in a file named Geeks.java
public class Geeks
^
1 error
But the myth can be violated in such a way to compile the above file.
Step1 will create a Geeks.class (byte code) without any error message since the class is not
public.
The myth about the file name and class name should be same only when the class is declared in
public.
The above program works as follows :
Now this .class file can be executed. By the above features some more miracles can be done. It is
possible to have many classes in a java file. For debugging purposes this approach can be used.
Each class can be executed separately to test their functionalities(only on one condition:
Inheritance concept should not be used).
For example:
class GeeksTest
{
public static void main(String[] args){
System.out.println("Geeks Test class");
}
}
When the above file is compiled as javac Trial.java will create two .class files as
ForGeeks.class and GeeksTest.class .
Since each class has separate main() stub they can be tested individually.
When java ForGeeks is executed the output is For Geeks class.
When java GeeksTest is executed the output is Geeks Test class.
Mark-and-Sweep: Garbage Collection
Algorithm
Background
All the objects which are created dynamically (using new in C++ and Java) are allocated memory
in the heap. If we go on creating objects we might get Out Of Memory error, since it is not possible
to allocate heap memory to objects. So we need to clear heap memory by releasing memory for all
those objects which are no longer referenced by the program (or the unreachable objects) so that
the space is made available for subsequent new objects. This memory can be released by the
programmer itself but it seems to be an overhead for the programmer, here garbage collection
comes to our rescue, and it automatically releases the heap memory for all the unreferenced
objects.
There are many garbage collection algorithms which run in the background. One of them is mark
and sweep.
Any garbage collection algorithm must perform 2 basic operations. One, it should be able to
detect all the unreachable objects and secondly, it must reclaim the heap space used by the
garbage objects and make the space available again to the program.
The above operations are performed by Mark and Sweep Algorithm in two phases:
1) Mark phase
2) Sweep phase
Mark Phase
When an object is created, its mark bit is set to 0(false). In the Mark phase, we set the marked bit
for all the reachable objects (or the objects which a user can refer to) to 1(true). Now to perform
this operation we simply need to do a graph traversal, a depth first search approach would work
for us. Here we can consider every object as a node and then all the nodes (objects) that are
reachable from this node (object) are visited and it goes on till we have visited all the reachable
nodes.
Root is a variable that refer to an object and is directly accessible by local variable. We
will assume that we have one root only.
We can access the mark bit for an object by: markedBit(obj).
Mark(root)
If markedBit(root) = false then
markedBit(root) = true
For each v referenced by root
Mark(v)
Note: If we have more than one root, then we simply have to call Mark() for all the root
variables.
Sweep Phase
As the name suggests it sweeps the unreachable objects i.e. it clears the heap memory for all
the unreachable objects. All those objects whose marked value is set to false are cleared from the
heap memory, for all other objects (reachable objects) the marked bit is set to false.
Now the mark value for all the reachable objects is set to false, since we will run the algorithm
(if required) and again we will go through the mark phase to mark all the reachable objects.
Sweep()
For each object p in heap
If markedBit(p) = true then
markedBit(p) = false
else
heap.release(p)
The mark-and-sweep algorithm is called a tracing garbage collector because is traces out the
entire collection of objects that are directly or indirectly accessible by the program.
Example:
It handles the case with cyclic references, even in case of a cycle, this algorithm never ends
up in an infinite loop.
There are no additional overheads incurred during the execution of the algorithm.
The main disadvantage of the mark-and-sweep approach is the fact that that normal
program execution is suspended while the garbage collection algorithm runs.
Other disadvantage is that, after the Mark and Sweep Algorithm is run several times on a
program, reachable objects end up being separated by many, small unused memory regions.
Look at the below figure for better understanding.
Figure:
Here white blocks denote the free memory, while the grey blocks denote the memory taken by all
the reachable objects.
Now the free segments (which are denoted by white color) are of varying size lets say the 5 free
segments are of size 1, 1, 2, 3, 5 (size in units).
Now we need to create an object which takes 10 units of memory, now assuming that memory can
be allocated only in contiguous form of blocks, the creation of object isnt possible although we
have an available memory space of 12 units and it will cause OutOfMemory error. This problem
is termed as Fragmentation. We have memory available in fragments but we are unable to
utilize that memory space.
We can reduce the fragmentation by compaction; we shuffle the memory content to place all the
free memory blocks together to form one large block. Now consider the above example, after
compaction we have a continuous block of free memory of size 12 units so now we can allocate
memory to an object of size 10 units.
Why binding of static, final and private methods is always a static binding?
Static binding is better performance wise (no extra overhead is required). Compiler knows that all
such methods cannot be overridden and will always be accessed by object of local class. Hence
compiler doesnt have any difficulty to determine object of class (local class for sure). Thats the
reason binding for such methods is static.
Lets see by an example
Before scrolling further down, Guess the output of the above program?
Output:
print in superclass.
print in superclass.
As you can see, in both cases print method of superclass is called. Lets see how this happens
We have created one object of subclass and one object of superclass with the reference of
the superclass.
Since the print method of superclass is static, compiler knows that it will not be overridden
in subclasses and hence compiler knows during compile time which print method to call
and hence no ambiguity.
As an exercise, reader can change the reference of object B to subclass and then check the
output.
Dynamic Binding: In Dynamic binding compiler doesnt decide the method to be called.
Overriding is a perfect example of dynamic binding. In overriding both parent and child classes
have same method . Lets see by an example
Output:
print in superclass.
print in subclass.
Here the output differs. But why? Lets break down the code and understand it thoroughly.
Important Points
private, final and static members (methods and variables) use static binding while for
virtual methods (In Java methods are virtual by default) binding is done during run time
based upon run time object.
Static binding uses Type information for binding while Dynamic binding uses Objects to
resolve binding.
Overloaded methods are resolved (deciding which method to be called when there are
multiple methods with same name) using static binding while overridden methods using
dynamic binding, i.e, at run time.
Collections in Java
A Collection is a group of individual objects represented as a single unit. Java provides
Collection Framework which defines several classes and interfaces to represent a group of
objects as a single unit.
The Collection interface (java.util.Collection) and Map interface (java.util.Map) are two main
root interfaces of Java collection classes.
Before Collection Framework (or before JDK 1.2) was introduced, the standard methods for
grouping Java objects (or collections) were array or Vector or Hashtable. All three of these
collections had no common interface.
For example, if we want to access elements of array, vector or Hashtable. All these three have
different methods and syntax for accessing members:
// Java program to show whey collection framework was needed
import java.io.*;
import java.util.*;
class Test
{
public static void main (String[] args)
{
// Creating instances of array, vector and hashtable
int arr[] = new int[] {1, 2, 3, 4};
Vector<Integer> v = new Vector();
Hashtable<Integer, String> h = new Hashtable();
v.addElement(1);
v.addElement(2);
h.put(1,"geeks");
h.put(2,"4geeks");
Output:
1
1
geek
As we can see, none of the collections (Array, Vector or Hashtable) implements a standard
member access interface. So, it was very difficult for programmers to write algorithm that can
work for all kind of collections.
Another drawback is that, most of the Vector methods are final. So, we cannot extend Vector
class to implement a similar kind of collection.
Java developers decided to come up with a common interface to deal with the above mentioned
problems and introduced Collection Framework, they introduced collections in JDK 1.2 and
changed the legacy Vector and Hashtable to conform to the collection framework.
1. Consistent API : The API has basic set of interfaces like Collection, Set, List, or Map. All
those classes (such as ArrayList, LinkedList, Vector etc) which implements, these
interfaces have some common set of methods.
2. Reduces programming effort: The programmer need not to worry about design of
Collection rather than he can focus on its best use in his program.
3. Increases program speed and quality: Increases performance by providing high-
performance implementations of useful data structures and algorithms.
The difference between Set and Map interface is, in Set we have only
keys, but in Map, we have key value pairs.
java.util package has public interface Iterator and contains three methods:
2. Object next(): It returns the next element in the collection until the hasNext()method return
true. This method throws NoSuchElementException if there is no next element.
3.void remove(): It removes the current element in the collection. This method throws
IllegalStateException if this function is called before next( ) is invoked.
class Test
{
public static void main (String[] args)
{
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
while (iterator.hasNext())
System.out.print(iterator.next()+ " ");
System.out.println();
}
}
Output:
List elements :
A B C D E
ListIterator in Java is an Iterator which allows users to traverse Collection in both direction. It
contains the following methods:
1. void add(Object object): It inserts object in front of the element that is returned by the next( )
function.
4. Object next( ): It returns the next element of the list. It throws NoSuchElementException if
there is no next element in the list.
6. void remove( ): It removes the current element from the list. It throws IllegalStateException
if this function is called before next( ) or previous( ) is invoked.
class Test
{
public static void main (String[] args)
{
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
System.out.println();
while(iterator.hasPrevious())
System.out.print(iterator.previous()+ " ");
System.out.println();
}
}
Output:
We read the : used in for-each loop as in. So loop reads as for each element e in elements,
here elements is the collection which stores Element type items.
Note : In Java 8 using lambda expressions we can simply replace for-each loop with
Modifying a collection simply means removing an element or changing content of an item stored
in the collection. This occurs because for-each loop implicitly creates an iterator but it is not
exposed to the user thus we cant modify the items in the collections.
In the above code we are calling the next() method again and again for itr1 (i.e., for List l). Now
we are advancing the iterator without even checking if it has any more elements left in the
collection(in the inner loop), thus we are advancing the iterator more than the number of elements
in the collection which leads to NoSuchElementException.
for-each loops are tailor made for nested loops. Replace the iterator code with the below code.
Output:
2 2 2 3 3 3 4 4
Performance Analysis
Traversing a collection using for-each loops or iterators give the same performance. Here, by
performance we mean the time complexity of both these traversals.
If you iterate using the old styled C for loop then we might increase the time complexity
drastically.
// Here l is List ,it can be ArrayList /LinkedList and n is size of the List
for (i=0;i<n;i++)
System.out.println(l.get(i));
Here if the list l is an ArrayList then we can access it in O(1) time since it is allocated contiguous
memory blocks (just like an array) i.e random access is possible. But if the collection is LinkedList,
then random access is not possible since it is not allocated contiguous memory blocks, so in order
to access a element we will have to traverse the link list till you get to the required index, thus the
time taken in worst case to access an element will be O(n).
Iterator and for-each loop are faster than simple for loop for collections with no random
access, while in collections which allows random access there is no performance change with
for-each loop/for loop/iterator.
Following are the 4 ways to retrieve any elements from a collection object:
For-each
We read the : used in for-each loop as in. So loop reads as for each element e in elements,
here elements is the collection which stores Element type items.
Note : In Java 8 using lambda expressions we can simply replace for-each loop with
It has 3 methods:
boolean hasNext(): This method returns true if the iterator has more elements.
elements next(): This method returns the next elements in the iterator.
void remove(): This method removes from the collection the last elements returned by the
iterator.
Output:
America
Japan
India
ListIteratoris an interface that contains methods to retrieve the elements from a collection object,
both in forward and reverse directions. This iterator is for list based collections.
booleanhasNext(): This returns true if the ListIterator has more elements when traversing
the list in the forward direction.
booleanhasPerivous(): This returns true if the ListIterator has more elements when
traversing the list in the reverse direction.
element next(): This returns the next element in the list.
element previous():This returns the previous element in the list.
void remove(): This removes from the list the last elements that was returned by the next()
or previous() methods.
int nextIndex() Returns the index of the element that would be returned by a subsequent
call to next(). (Returns list size if the list iterator is at the end of the list.)
int previousIndex() Returns the index of the element that would be returned by a
subsequent call to previous(). (Returns -1 if the list iterator is at the beginning of the list.)
Iterator can retrieve the elements only in forward direction. But ListIterator can retrieve the
elements in forward and reverse direction also. So ListIterator is preferred to Iterator.
Since ListIterator can access elements in both directions and supports additional operators,
ListIterator cannot be applied on Set (e.g., HashSet and TreeSet. See this). However, we can use
LisIterator with vector and list (e.g. ArrayList ).
class Test
{
public static void main(String args[])
{
// take a vector to store Integer objects
Vector<Integer> v = new Vector<Integer>();
// Creating a ListIterator
ListIterator lit = v.listIterator();
System.out.println("In Forward direction:");
while (lit.hasNext())
System.out.print(lit.next()+" ") ;
Output :
In Forward direction:
10 20 30
In backward direction:
30 20 10
EnumerationIterator Interface
The interface is useful to retrieve one by one the element. This iterator is based on data from
Enumeration and has methods:
booleanhasMoreElements(): This method tests if the Enumeration has any more elements
or not .
element nextElement(): This returns the next element that is available in elements that is
available in Enumeration
Iterator has an option to remove elements from the collection which is not available in
Enumeration. Also, Iterator has methods whose names are easy to follow and Enumeration
methods are difficult to remember.
import java.util.Vector;
import java.util.Enumeration;
public class Test
{
public static void main(String args[])
{
Vector dayNames = new Vector();
dayNames.add("Sunday");
dayNames.add("Monday");
dayNames.add("Tuesday");
dayNames.add("Wednesday");
dayNames.add("Thursday");
dayNames.add("Friday");
dayNames.add("Saturday");
// Creating enumeration
Enumeration days = dayNames.elements();
Output:
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Set in Java
Set is an interface which extends Collection. It is an unordered collection of objects in
which duplicate values cannot be stored.
Basically, Set is implemented by HashSet, LinkedSet or TreeSet (sorted representation).
Set has various methods to add, remove clear, size, etc to enhance the usage of this interface
System.out.println(hash_Set);
(Please note that we have entered a duplicate entity but it is not displayed in the output. Also, we
can directly sort the entries by passing the unordered Set in as the parameter of TreeSet).
Output:
Note: As we can see the duplicate entry Geeks is ignored in the final output, Set interface
doesnt allow duplicate entries.
Now we will see some of the basic operations on the Set i.e. Union, Intersection and Difference.
[1, 3, 2, 4, 8, 9, 0]
[1, 3, 7, 5, 4, 0, 7, 5]
Union
In this, we could simply add one Set with other. Since the Set will itself not allow any duplicate
entries, we need not take care of the common values.
Expected Output:
Union : [0, 1, 2, 3, 4, 5, 7, 8, 9]
Intersection
We just need to retain the common values from both Sets.
Expected Output:
Intersection : [0, 1, 3, 4]
Difference
We just need to remove tall the values of one Set from the other.
Expected Output:
Difference : [2, 8, 9]
// To find union
Set<Integer> union = new HashSet<Integer>(a);
union.addAll(b);
System.out.print("Union of the two Set");
System.out.println(union);
// To find intersection
Set<Integer> intersection = new HashSet<Integer>(a);
intersection.retainAll(b);
System.out.print("Intersection of the two Set");
System.out.println(intersection);
Output:
HashSet in Java
HashSet:
Constructors in HashSet:
The initial capacity means the number of buckets when hashtable (HashSet internally uses
hashtable data structure) is created. Number of buckets will be automatically increased if the
current size gets full.
The load factor is a measure of how full the HashSet is allowed to get before its capacity is
automatically increased. When the number of entries in the hash table exceeds the product of the
load factor and the current capacity, the hash table is rehashed (that is, internal data structures are
rebuilt) so that the hash table has approximately twice the number of buckets.
E.g. If internal capacity is 16 and load factor is 0.75 then, number of buckets will automatically
get increased when table has 12 elements in it.
Effect on performance:
Load factor and initial capacity are two main factors that affect the performance of HashSet
operations. Load factor of 0.75 provides very effective performance as respect to time and space
complexity. If we increase the load factor value more than that then memory overhead will be
reduced (because it will decrease internal rebuilding operation) but, it will affect the add and
search operation in hashtable. To reduce the rehashing operation we should choose initial
capacity wisely. If initial capacity is greater than the maximum number of entries divided by the
load factor, no rehash operation will ever occur.
Sample Program:
class Test
{
public static void main(String[]args)
{
HashSet<String> h = new HashSet<String>();
// printing HashSet
System.out.println(h);
System.out.println("List contains India or not:" +
h.contains("India"));
// Removing an item
h.remove("Australia");
System.out.println("List after removing Australia:"+h);
// Constructor - 1
// All the constructors are internally creating HashMap Object.
public HashSet()
{
// Creating internally backing HashMap object
map = new HashMap<>();
}
// Constructor - 2
public HashSet(int initialCapacity)
{
// Creating internally backing HashMap object
map = new HashMap<>(initialCapacity);
}
We can notice that, add() method of HashSet class internally calls put() method of backing
HashMap object by passing the element you have specified as a key and constant PRESENT
as its value.
remove() method also works in the same manner. It internally calls remove method of Map
interface.
1. boolean add(Object element) : It appends the element to the end of the list.
2. void add(int index, Object element): It inserts the element at the position index in the list.
3. void addFirst(Object element) : It inserts the element at the beginning of the list.
4. void addLast(Object element) : It appends the element at the end of the list.
5. boolean contains(Object element) : It returns true if the element is present in the list.
6. Object get(int index) : It returns the element at the position index in the list. It throws
IndexOutOfBoundsException if the index is out of range of the list.
7. int indexOf(Object element) : If element is found, it returns the index of the first occurrence
of the element. Else, it returns -1.
8. Object remove(int index) : It removes the element at the position index in this list. It throws
NoSuchElementException if the list is empty.
10. void clear() : It removes all of the elements from the list.
import java.util.*;
{
public static void main(String args[])
object.add("A");
object.add("B");
object.addLast("C");
object.addFirst("D");
object.add(2, "E");
object.add("F");
object.add("G");
object.remove("B");
object.remove(3);
object.removeFirst();
object.removeLast();
if(status)
else
object.set(2, "Y");
Output :
It extends Vector class with five methods that allow a vector to be treated as a stack. The five
methods are:
2. Object pop() : Removes and returns the top element of the stack. An EmptyStackException
exception is thrown if we call pop() when the invoking stack is empty.
3. Object peek( ) : Returns the element on the top of the stack, but does not remove it.
4. boolean empty() : It returns true if nothing is on the top of the stack. Else, returns false.
5. int search(Object element) : It determines whether an object exists in the stack. If the
element is found, it returns the position of the element from the top of the stack. Else, it returns -
1.
// Java code for stack implementation
import java.io.*;
import java.util.*;
class Test
{
// Pushing element on the top of the stack
static void stack_push(Stack<Integer> stack)
{
for(int i = 0; i < 5; i++)
{
stack.push(i);
}
}
if(pos == -1)
System.out.println("Element not found");
else
System.out.println("Element is found at position " + pos);
}
Output :
Pop :
4
3
2
1
0
Element on stack top : 4
Element is found at position 3
Element not found
//----------------hashmap--------------------------------
HashMap<Integer,String> hm=new HashMap<Integer,String>();
hm.put(100,"Amit");
hm.put(104,"Amit"); // hash map allows duplicate values
hm.put(101,"Vijay");
hm.put(102,"Rahul");
System.out.println("-----------Hash map-----------");
for (Map.Entry m:hm.entrySet()) {
System.out.println(m.getKey()+" "+m.getValue());
}
}
}
Output:
-------------Hash table--------------
103 Rahul
102 Ravi
101 Vijay
-----------Hash map-----------
100 Amit
101 Vijay
102 Rahul
104 Amit
Hashmap vs Hashtable
1. HashMap is non synchronized. It is not-thread safe and cant be shared between many threads
without proper synchronization code whereas Hashtable is synchronized. It is thread-safe and
can be shared with many threads.
2. HashMap allows one null key and multiple null values whereas Hashtable doesnt allow any
null key or value.
3. HashMap is generally preferred over HashTable if thread synchronization is not needed
HashMap
java.util.HashMap class is a Hashing based implementation. In HashMap, we have a key and a
value pair<Key, Value>.
HashMap<K, V> hmap = new HashMap<K, V>();
Let us consider below example where we have to count occurrences of each integer in given
array of integers.
class Main
{
// This function prints frequencies of all elements
static void printFreq(int arr[])
{
// Creates an empty HashMap
HashMap<Integer, Integer> hmap =
new HashMap<Integer, Integer>();
// Print result
for (Map.Entry m:hmap.entrySet())
System.out.println("Frequency of " + m.getKey() +
" is " + m.getValue());
}
Frequency of 34 is 1
Frequency of 3 is 1
Frequency of 5 is 2
Frequency of 10 is 3
Key Points
HashMap does not maintain any order neither based on key nor on basis of value, If we
want the keys to be maintained in a sorted order, we need to use TreeMap.
Complexity: get/put/containsKey() operations are O(1) in average case but we cant
guarantee that since it all depends on how much time does it take to compute the hash.
Application:
HashMap is basically an implementation of hashing. So wherever we need hashing with key
value pairs, we can use HashMap. For example, in Web Applications username is stored as a key
and user data is stored as a value in the HashMap, for faster retrieval of user data corresponding
to a username.
TreeMap
TreeMap can be a bit handy when we only need to store unique elements in a sorted order.
Java.util.TreeMap uses a red-black tree in the background which makes sure that there are no
duplicates; additionally it also maintains the elements in a sorted order.
TreeMap<K, V> hmap = new TreeMap<K, V>();
Below is TreeMap based implementation of same problem. This solution has more time
complexity O(nLogn) compared to previous one which has O(n). The advantage of this method
is, we get elements in sorted order.
class Main
{
// This function prints frequencies of all elements
static void printFreq(int arr[])
{
// Creates an empty TreeMap
TreeMap<Integer, Integer> tmap =
new TreeMap<Integer, Integer>();
// Print result
for (Map.Entry m:tmap.entrySet())
System.out.println("Frequency of " + m.getKey() +
" is " + m.getValue());
}
Output:
Frequency of 3 is 1
Frequency of 5 is 2
Frequency of 10 is 3
Frequency of 34 is 1
Key Points
For operations like add, remove, containsKey, time complexity is O(log n where n is
number of elements present in TreeMap.
TreeMap always keeps the elements in a sorted(increasing) order, while the elements in a
HashMap have no order. TreeMap also provides some cool methods for first, last, floor
and ceiling of keys.
Overview:
1. Array: Simple fixed sized arrays that we create in Java, like below
class Test
{
public static void main(String args[])
{
/* ........... Normal Array............. */
int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
System.out.println(arr[0]);
/*............ArrayList..............*/
// Create an arrayList with initial capacity 2
ArrayList<Integer> arrL = new ArrayList<Integer>(2);
Output:
1
1
Array is a fixed size data structure while ArrayList is not. One need not to mention the size of
Arraylist while creating its object. Even if we specify some initial capacity, we can add more
elements.
// A Java program to demonstrate differences between array
// and ArrayList
import java.util.ArrayList;
import java.util.Arrays;
class Test
{
public static void main(String args[])
{
/* ........... Normal Array............. */
// Need to specify the size for array
int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
// We cannot add more elements to array arr[]
/*............ArrayList..............*/
// Need not to specify size
ArrayList<Integer> arrL = new ArrayList<Integer>();
arrL.add(1);
arrL.add(2);
arrL.add(3);
arrL.add(4);
// We can add more elements to arrL
System.out.println(arrL);
System.out.println(Arrays.toString(arr));
}
}
Output:
[1, 2, 3, 4]
[1, 2, 3]
.
Array can contain both primitive data types as well as objects of a class depending on the
definition of the array. However, ArrayList only supports object entries, not the primitive data
types.
Note: When we do arraylist.add(1); : it converts the primitive int data type into an Integer object.
Sample Code:
import java.util.ArrayList;
class Test
{
public static void main(String args[])
{
// allowed
int[] array = new int[3];
// Allowed
ArrayList<Integer> arrL1 = new ArrayList<>();
ArrayList<String> arrL2 = new ArrayList<>();
ArrayList<object> arrL3 = new ArrayList<>();
}
}
Since ArrayList cant be created for primitive data types, members of ArrayList are always
references to objects at different memory locations (See this for details). Therefore in
ArrayList, the actual objects are never stored at contiguous locations. References of the
actual objects are stored at contiguous locations.
In array, it depends whether the arrays is of primitive type or object type. In case of
primitive types, actual values are contiguous locations, but in case of objects, allocation is
similar to ArrayList.
Constructor: PriorityQueue()
This creates a PriorityQueue with the default initial capacity that orders its elements according to
their natural ordering.
Methods:
1. booleanadd(E element): This method inserts the specified element into this priority queue.
2. public remove(): This method removes a single instance of the specified element from this
queue, if it is present
3. public poll(): This method retrieves and removes the head of this queue, or returns null if
this queue is empty.
4. public peek(): This method retrieves, but does not remove, the head of this queue, or returns
null if this queue is empty.
6. booleancontains(Object o): This method returns true if this queue contains the specified
element
class Example
{
public static void main(String args[])
{
// Creating empty priority queue
PriorityQueue<String> pQueue =
new PriorityQueue<String>();
// Removing Java
pQueue.remove("Java");
System.out.println("after removing Java with" +
" remove function:");
Iterator<String> itr3 = pQueue.iterator();
while (itr3.hasNext())
System.out.println(itr3.next());
Output:
Applications :
Implementing Dijkstras and Prims algorithms.