JavaInterviewQuestions UdemyCourse September2016
JavaInterviewQuestions UdemyCourse September2016
www.in28minutes.com
Java Interview
Questions and
Answers
TABLE OF CONTENTS
JAVA PLATFORM ................................................................................................................................ 10
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
STRINGS ............................................................................................................................................. 18
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
MODIFIERS ......................................................................................................................................... 43
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
WHAT ACCESS TYPES OF VARIABLES CAN BE ACCESSED FROM A CLASS IN SAME PACKAGE? ................ 44
WHAT ACCESS TYPES OF VARIABLES CAN BE ACCESSED FROM A CLASS IN DIFFERENT PACKAGE? ......... 44
WHAT ACCESS TYPES OF VARIABLES CAN BE ACCESSED FROM A SUB CLASS IN SAME PACKAGE? ......... 45
WHAT ACCESS TYPES OF VARIABLES CAN BE ACCESSED FROM A SUB CLASS IN DIFFERENT PACKAGE? ... 45
WHAT IS THE USE OF A FINAL MODIFIER ON A CLASS? ................................................................. 46
WHAT IS THE USE OF A FINAL MODIFIER ON A METHOD? ............................................................. 46
WHAT IS A FINAL VARIABLE? .................................................................................................. 46
WHAT IS A FINAL ARGUMENT? ............................................................................................... 47
WHAT HAPPENS WHEN A VARIABLE IS MARKED AS VOLATILE? ...................................................... 47
WHAT IS A STATIC VARIABLE? ................................................................................................ 47
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
WHAT DESIGN PATTERN IS USED TO IMPLEMENT EXCEPTION HANDLING FEATURES IN MOST LANGUAGES?
......................................................................................................................................... 53
IN WHAT SCENARIOS IS CODE IN FINALLY NOT EXECUTED? ............................................................ 55
WILL FINALLY BE EXECUTED IN THE PROGRAM BELOW? ............................................................... 56
IS TRY WITHOUT A CATCH IS ALLOWED? ................................................................................... 56
IS TRY WITHOUT CATCH AND FINALLY ALLOWED? ....................................................................... 56
CAN YOU EXPLAIN THE HIERARCHY OF EXCEPTION HANDLING CLASSES? ......................................... 57
WHAT IS THE DIFFERENCE BETWEEN ERROR AND EXCEPTION? ..................................................... 57
WHAT IS THE DIFFERENCE BETWEEN CHECKED EXCEPTIONS AND UNCHECKED EXCEPTIONS? ............. 57
HOW DO YOU THROW AN EXCEPTION FROM A METHOD? ............................................................ 58
WHAT HAPPENS WHEN YOU THROW A CHECKED EXCEPTION FROM A METHOD? ............................. 58
103.
WHAT ARE THE OPTIONS YOU HAVE TO ELIMINATE COMPILATION ERRORS WHEN HANDLING CHECKED
EXCEPTIONS? ...................................................................................................................... 59
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
COLLECTIONS ..................................................................................................................................... 71
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
WHAT IS THE DIFFERENCE BETWEEN SYNCHRONIZED AND CONCURRENT COLLECTIONS IN JAVA? ......... 88
EXPLAIN ABOUT THE NEW CONCURRENT COLLECTIONS IN JAVA? ................................................... 88
EXPLAIN ABOUT COPYONWRITE CONCURRENT COLLECTIONS APPROACH? ..................................... 88
WHAT IS COMPAREANDSWAP APPROACH? .............................................................................. 88
WHAT IS A LOCK? HOW IS IT DIFFERENT FROM USING SYNCHRONIZED APPROACH? .......................... 89
WHAT IS INITIAL CAPACITY OF A JAVA COLLECTION? ................................................................... 89
WHAT IS LOAD FACTOR? ....................................................................................................... 89
WHEN DOES A JAVA COLLECTION THROW UNSUPPORTEDOPERATIONEXCEPTION? .......................... 89
175.
176.
177.
GENERICS ........................................................................................................................................... 92
178.
179.
180.
181.
182.
183.
184.
WHY DO WE NEED GENERICS? CAN YOU GIVE AN EXAMPLE OF HOW GENERICS MAKE A PROGRAM MORE
FLEXIBLE? ........................................................................................................................... 92
WHAT ARE THE RESTRICTIONS IN USING GENERIC TYPE THAT IS DECLARED IN A CLASS DECLARATION? .. 93
HOW CAN WE RESTRICT GENERICS TO A SUBCLASS OF PARTICULAR CLASS? ..................................... 93
HOW CAN WE RESTRICT GENERICS TO A SUPER CLASS OF PARTICULAR CLASS? ................................. 94
CAN YOU GIVE AN EXAMPLE OF A GENERIC METHOD? ................................................................ 94
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
10
Java Platform
Why is Java so Popular?
Two main reasons for popularity of Java are
1. Platform Independence
2. Object Oriented Language
We will look at these in detail in later sections.
bytecode
Platform Independence is also called build once, run anywhere. Java is one of the most popular platform
independent languages. Once we compile a java program and build a jar, we can run the jar (compiled
java program) in any Operating System - where a JVM is installed.
Java achieves Platform Independence in a beautiful way. On compiling a java file the output is a class file
- which contains an internal java representation called bytecode. JVM converts bytecode to executable
instructions. The executable instructions are different in different operating systems. So, there are
different JVM's for different operating systems. A JVM for windows is different from a JVM for mac.
However, both the JVM's understand the bytecode and convert it to the executable code for the
respective operating system.
What is ByteCode?
Java bytecode is the instruction set of the Java virtual machine. Each bytecode is composed of one, or in
some cases two bytes that represent the instruction (opcode), along with zero or more bytes for passing
parameters.
1. JVM
a. Virtual machine that run the Java bytecode.
b. Makes java portable.
2. JRE
a. JVM + Libraries + Other Components (to run applets and other java applications)
11
12
3. JDK
a. JRE + Compilers + Debuggers
13
14
Wrapper Classes
What are wrapper classes?
A brief description is provided below.
A primitive wrapper class in the Java programming language is one of eight classes provided in the
java.lang package to provide object methods for the eight primitive types. All of the primitive wrapper
classes in Java are immutable.
Wrapper: Boolean,Byte,Character,Double,Float,Integer,Long,Short
Primitive: boolean,byte,char
,double, float, int , long,short
Character c1 = new Character('C');//Only char constructor
//Character c2 = new Character(124);//COMPILER ERROR
Boolean b = new Boolean(true);
//"true" "True" "tRUe" - all String Values give True
//Anything else gives false
Boolean b1 = new Boolean("true");//value stored - true
Boolean b2 = new Boolean("True");//value stored - true
Boolean b3 = new Boolean("False");//value stored - false
Boolean b4 = new Boolean("SomeString");//value stored - false
15
16
return new Integer(i);
}
Example 2
Integer ten = new Integer(10);
ten++;//allowed. Java does had work behind the screen for us
What is Casting?
Casting is used when we want to convert on data type to another.
There are two types of Casting
Implicit Casting
Explicit Casting
17
18
Strings
Are all Strings immutable?
Value of a String Object once created cannot be modified. Any modification on a String object creates a
new String object.
String str3 = "value1";
str3.concat("value2");
System.out.println(str3); //value1
Note that the value of str3 is not modified in the above example. The result should be assigned to a new
reference variable (or same variable can be reused). All wrapper class instances are immutable too!
String concat = str3.concat("value2");
System.out.println(concat); //value1value2
This value will be stored in a "String constant pool" which is inside the Heap memory. If compiler finds
a String literal,it checks if it exists in the pool. If it exists, it is reused.
String str5 = "value";
In above example, when str5 is created - the existing value from String Constant Pool is reused.
Approach 2
However, if new operator is used to create string object, the new object is created on the heap. There
will not be any reuse of values.
//String Object - created on the heap
String str2 = new String("value");
Objects of type String are immutable. StringBuffer is used to represent values that can be
modified.
In situations where values are modified a number to times, StringBuffer yields significant
performance benefits.
Both String and StringBuffer are thread-safe.
StringBuffer is implemented by using synchronized keyword on all methods.
19
20
System.out.println("abcdefghij".substring(3)); //cdefghij
//All characters from index 3 to 6
System.out.println("abcdefghij".substring(3,7)); //defg
Class
A class is a Template. In above example, Class CricketScorer is the template for creating multiple
objects. A class defines state and behavior that an object can exhibit.
What is an Object?
An instance of a class. In the above example, we create an object using new CricketScorer(). The
reference of the created object is stored in scorer variable. We can create multiple objects of the same
class.
21
22
scorer.six();
//State of scorer is (score => 6)
scorer.four();
//State of scorer is (score => 10)
23
24
//client3 and client1 refer to the same client objects.
System.out.println(client1 == client3);//true
//similar output to ==
System.out.println(client1.equals(client2));//false
System.out.println(client1.equals(client3));//true
We can override the equals method in the Client class to check the content of the objects. Consider the
example below: The implementation of equals method checks if the id's of both objects are equal. If so, it
returns true. Note that this is a basic implementation of equals and more needs to be done to make it foolproof.
class Client {
private int id;
public Client(int id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
Client other = (Client) obj;
if (id != other.id)
return false;
return true;
}
}
Consider running the code below:
Client client1 = new Client(25);
Client client2 = new Client(25);
Client client3 = client1;
//both id's are 25
System.out.println(client1.equals(client2));//true
//both id's are 25
System.out.println(client1.equals(client3));//true
Above code compares the values (id's) of the objects.
25
26
}
We can extend this class by using the keyword extends. Hero class extends Actor.
//IS-A relationship. Hero is-a Actor
public class Hero extends Actor {
public void fight(){
System.out.println("fight");
};
}
We can now create an instance of Hero class. Since Hero extends Animal, the methods defined in Animal
are also available through an instance of Hero class. In the example below, we invoke the act method on
hero object.
Hero hero = new Hero();
//act method inherited from Actor
hero.act();//Act
hero.fight();//fight
Lets look at another class extending Actor class - Comedian.
//IS-A relationship. Comedian is-a Actor
public class Comedian extends Actor {
public void performComedy(){
System.out.println("Comedy");
};
}
We can now reuse Actor methods from an instance of Comedian class as well.
Comedian comedian = new Comedian();
//act method inherited from Actor
comedian.act();//Act
comedian.performComedy();//Comedy
Example 1
doIt method is overloaded in the below example:
class Foo{
public void doIt(int number){
}
public void doIt(String string){
}
}
Example 2
Overloading can also be done from a sub class.
Java Example
Constructors
o public HashMap(int initialCapacity, float loadFactor)
o public HashMap() {
o public HashMap(int initialCapacity)
Methods
o public boolean addAll(Collection<? extends E> c)
o public boolean addAll(int index, Collection<? extends E> c)
Lets define an Animal class with a method shout.
public class Animal {
public String bark() {
return "Don't Know!";
}
}
Lets create a sub class of Animal Cat - overriding the existing shout method in Animal.
class Cat extends Animal {
public String bark() {
return "Meow Meow";
}
}
bark method in Cat class is overriding the bark method in Animal class.
Java Example : HashMap public int size() overrides AbstractMap public int size()
Can super class reference variable can hold an object of sub class?
Yes. Look at the example below:
Actor reference variables actor1, actor2 hold the reference of objects of sub classes of Animal, Comedian
and Hero.
Since object is super class of all classes, an Object reference variable can also hold an instance of any
class.
27
28
//Object is super class of all java classes
Object object = new Hero();
public class Actor {
public void act(){
System.out.println("Act");
};
}
//IS-A relationship. Hero is-a Actor
public class Hero extends Actor {
public void fight(){
System.out.println("fight");
};
}
//IS-A relationship. Comedian is-a Actor
public class Comedian extends Actor {
public void performComedy(){
System.out.println("Comedy");
};
}
Actor actor1 = new Comedian();
Actor actor2 = new Hero();
What is an Interface?
//public abstract are not necessary
public abstract interface Flyable {
//public abstract are not necessary
public abstract void fly();
}
Example 1
Class Aeroplane implements Flyable and implements the abstract method fly().
public class Aeroplane implements Flyable{
@Override
public void fly() {
System.out.println("Aeroplane is flying");
}
}
Example 2
public class Bird implements Flyable{
@Override
public void fly() {
System.out.println("Bird is flying");
}
}
Interface methods are by default public and abstract. Before Java 8, A concrete method (fully defined
method) cannot be created in an interface. Consider the example below:
interface ExampleInterface1 {
//By default - public abstract. No other modifier allowed
void method1();//method1 is public and abstract
//private void method6();//COMPILER ERROR!
//This method, uncommented, would have given COMPILER ERROR!
29
30
//in Java 7. Allowed from Java 8.
default void method5() {
System.out .println("Method5");
}
}
Class implementing SubInterface1 should implement both methods - method3 and method1(from
ExampleInterface1)
An interface cannot extend a class.
/* //COMPILE ERROR IF UnCommented
//Interface cannot extend a Class
interface SubInterface2 extends Integer{
void method3();
}
*/
}
}
Abstract method can be declared only in Abstract Class. In the example below, abstractMethod() gives a
compiler error because NormalClass is not abstract.
class NormalClass{
abstract void abstractMethod();//COMPILER ERROR
}
31
32
What is a Constructor?
Constructoris invoked whenever we create an instance(object) of a Class. We cannot create an object
without a constructor.
Constructor has the same name as the class and no return type. It can accept any number of parameters.
class Animal {
String name;
// This is called a one argument constructor.
public Animal(String name) {
this.name = name;
}
public static void main(String[] args) {
// Since we provided a constructor, compiler does not
// provide a default constructor.
// Animal animal = new Animal();//COMPILER ERROR!
// The only way we can create Animal1 object is by using
Animal animal = new Animal("Tommy");
}
}
Answer is no. Since we provided a constructor, compiler does not provide a default constructor
Answer is NO. super should be always called on the first line of the constructor.
33
34
this.name = name;
}
Is a super class constructor called even when there is no explicit call from a
sub class constructor?
If a super class constructor is not explicitly called from a sub class constructor, super class (no argument)
constructor is automatically invoked (as first line) from a sub class constructor.
Consider the example below:
class Animal {
public Animal() {
System.out.println("Animal Constructor");
}
}
class Dog extends Animal {
public Dog() {
System.out.println("Dog Constructor");
}
}
class Labrador extends Dog {
public Labrador() {
System.out.println("Labrador Constructor");
}
}
public class ConstructorExamples {
public static void main(String[] args) {
Labrador labrador = new Labrador();
}
}
Program Output
Animal Constructor
Dog Constructor
Labrador Constructor
Lets create two new sub classes of Animal overriding the existing shout method in Animal.
class Cat extends Animal {
public String shout() {
return "Meow Meow";
}
}
class Dog extends Animal {
public String shout() {
return "BOW BOW";
}
public void run(){
}
}
Look at the code below. An instance of Animal class is created. shout method is called.
Animal animal1 = new Animal();
System.out.println(
animal1.shout()); //Don't Know!
Look at the code below. An instance of Dog class is created and store in a reference variable of type
Animal.
Animal animal2 = new Dog();
//Reference variable type => Animal
//Object referred to => Dog
//Dog's bark method is called.
System.out.println(
animal2.shout()); //BOW BOW
When shout method is called on animal2, it invokes the shout method in Dog class (type of the object
pointed to by reference variable animal2).
35
36
Even though dog has a method run, it cannot be invoked using super class reference variable.
//animal2.run();//COMPILE ERROR
Lets consider the code below. We create a few instances of the classes declared above.
SubClass subClass = new SubClass();
Object subClassObj = new SubClass();
SubClass2 subClass2 = new SubClass2();
SomeOtherClass someOtherClass = new SomeOtherClass();
Lets now run instanceof operator on the different instances created earlier.
System.out.println(subClass instanceof SubClass);//true
System.out.println(subClass instanceof SuperClass);//true
System.out.println(subClassObj instanceof SuperClass);//true
System.out.println(subClass2
instanceof SuperClassImplementingInteface);//true
instanceof can be used with interfaces as well. Since Super Class implements the interface, below code
prints true.
System.out.println(subClass2
instanceof Interface);//true
// instanceof SomeOtherClass);//Compiler Error
What is Coupling?
Coupling is a measure of how much a class is dependent on other classes. There should minimal
dependencies between classes. So, we should always aim for low coupling between classes.
37
38
Consider a better implementation with lesser coupling between classes below: In this implementation,
changes in ShoppingCartEntry or CartContents might not affect Order class at all.
class ShoppingCartEntry
{
float price;
int quantity;
public float getTotalPrice()
{
return price * quantity;
}
}
class CartContents
{
ShoppingCartEntry[] items;
public float getTotalPrice()
{
float totalPrice = 0;
for (ShoppingCartEntry item:items)
{
totalPrice += item.getTotalPrice();
}
return totalPrice;
}
}
class Order
{
private CartContents cart;
private float salesTax;
public Order(CartContents cart, float salesTax)
{
this.cart = cart;
this.salesTax = salesTax;
}
public float totalPrice()
{
return cart.getTotalPrice() * (1.0f + salesTax);
}
}
What is Cohesion?
Cohesion is a measure of how related the responsibilities of a class are. A class must be highly cohesive
i.e. its responsibilities (methods) should be highly related to one another.
Example Problem
Example class below is downloading from internet, parsing data and storing data to database. The
responsibilities of this class are not really related. This is not cohesive class.
class DownloadAndStore{
void downloadFromInternet(){
}
void parseData(){
}
void storeIntoDatabase(){
}
void doEverything(){
downloadFromInternet();
parseData();
storeIntoDatabase();
}
}
Solution
This is a better way of approaching the problem. Different classes have their own responsibilities.
class InternetDownloader {
public void downloadFromInternet() {
}
}
class DataParser {
public void parseData() {
}
}
class DatabaseStorer {
public void storeIntoDatabase() {
}
}
class DownloadAndStore {
void doEverything() {
new InternetDownloader().downloadFromInternet();
new DataParser().parseData();
new DatabaseStorer().storeIntoDatabase();
}
}
What is Encapsulation?
Encapsulation is hiding the implementation of a Class behind a well defined interface. Encapsulation
helps us to change implementation of a class without breaking other code.
Approach 1
In this approach we create a public variable score. The main method directly accesses the score variable,
updates it.
public class CricketScorer {
public int score;
39
40
}
Lets use the CricketScorer class.
public static void main(String[] args) {
CricketScorer scorer = new CricketScorer();
scorer.score = scorer.score + 4;
}
Approach 2
In this approach, we make score as private and access value through get and set methods. However, the
logic of adding 4 to the score is performed in the main method.
public class CricketScorer {
private int score;
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
Lets use the CricketScorer class.
public static void main(String[] args) {
CricketScorer scorer = new CricketScorer();
int score = scorer.getScore();
scorer.setScore(score + 4);
}
Approach 3
In this approach - For better encapsulation, the logic of doing the four operation also is moved to the
CricketScorer class.
public class CricketScorer {
private int score;
public void four() {
score += 4;
}
}
Lets use the CricketScorer class.
public static void main(String[] args) {
CricketScorer scorer = new CricketScorer();
scorer.four();
}
Description
In terms of encapsulation Approach 3 > Approach 2 > Approach 1. In Approach 3, the user of scorer class
does not even know that there is a variable called score. Implementation of Scorer can change without
changing other classes using Scorer.
41
42
Comparator<String> reverseComparator = new Comparator<String>() {
/* Anonymous Class */
@Override
public int compare(String string1,
String string2) {
return string2.compareTo(string1);
}
};
Arrays.sort(array, reverseComparator);
return array;
}
public static void main(String[] args) {
String[] array = { "Apple", "Cat", "Boy" };
System.out .println(Arrays
.toString(reverseSort(array)));//[Cat, Boy, Apple]
/* Second Anonymous Class - SubClass of Animal*/
Animal animal = new Animal() {
void bark() {
System.out .println("Subclass bark");
}
};
animal.bark();//Subclass bark
}
}
Modifiers
What is default class modifier?
A class is called a Default Class is when there is no access modifier specified on a class.
Default classes are visible inside the same package only.
Default access is also called Package access.
Example
package com.rithus.classmodifiers.defaultaccess.a;
/* No public before class. So this class has default access*/
class DefaultAccessClass {
//Default access is also called package access
}
43
44
What access types of variables can be accessed from a Class in Same Package?
Look at the code below to understand what can be accessed and what cannot be.
package com.rithus.membermodifiers.access;
public class TestClassInSamePackage {
public static void main(String[] args) {
ExampleClass example = new ExampleClass();
example.publicVariable = 5;
example.publicMethod();
//privateVariable is not visible
//Below Line, uncommented, would give compiler error
//example.privateVariable=5; //COMPILE ERROR
//example.privateMethod();
example.protectedVariable = 5;
example.protectedMethod();
example.defaultVariable = 5;
example.defaultMethod();
}
}
//defaultVariable,defaultMethod are not visible
//Below Lines, uncommented, would give compiler error
//example.defaultVariable = 5;//COMPILE ERROR
//example.defaultMethod();//COMPILE ERROR
}
}
What access types of variables can be accessed from a Sub Class in Same
Package?
Look at the code below to understand what can be accessed and what cannot be.
package com.rithus.membermodifiers.access;
public class SubClassInSamePackage extends ExampleClass {
void subClassMethod(){
publicVariable = 5;
publicMethod();
//privateVariable is not visible to SubClass
//Below Line, uncommented, would give compiler error
//privateVariable=5; //COMPILE ERROR
//privateMethod();
protectedVariable = 5;
protectedMethod();
defaultVariable = 5;
defaultMethod();
}
}
What access types of variables can be accessed from a Sub Class in Different
Package?
Look at the code below to understand what can be accessed and what cannot be.
package com.rithus.membermodifiers.access.different;
import com.rithus.membermodifiers.access.ExampleClass;
public class SubClassInDifferentPackage extends ExampleClass {
void subClassMethod(){
publicVariable = 5;
publicMethod();
//privateVariable is not visible to SubClass
//Below Line, uncommented, would give compiler error
//privateVariable=5; //COMPILE ERROR
//privateMethod();
45
46
protectedVariable = 5;
protectedMethod();
//privateVariable is not visible to SubClass
//Below Line, uncommented, would give compiler error
//defaultVariable = 5; //COMPILE ERROR
//defaultMethod();
}
}
final int finalValue = 5;
//finalValue = 10; //COMPILER ERROR
Final Variable example : java.lang.Math.PI
47
48
4 instances of the Cricketer class are created. Variable count is incremented with every instance created
in the constructor.
49
50
System.out.println("Default");
}
Output of above switch
2
3
Default
In this example, there is no break statement in every case. If there is no break, then all the case's until
we find break are executed.
Since there is no break after case 2, execution falls through to case 3. There is no break in case 3 as well.
So, execution falls through to default.
Rule: Code in switch is executed from a matching case until a break or end of switch statement is
encountered.
Program Output
Number is 2 or 3.
Case 2 matches. Since there is no code in case 2, execution falls through to case 3, executes the println.
Break statement takes execution out of the switch
Example Output
Default
Code Output
0123456789
Example Output
12345
Result:
Infinite loop => Loop executes until the program is terminated.
51
52
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 10; k++) {
System.out.print(j + "" + k);
if (k == 5) {
break;//Takes out of loop using k
}
}
}
Program Output
000102030405101112131415
Each time the value of k is 5 the break statement is executed. The break statement takes execution out
of the k loop and proceeds to the next value of j.
Program Output
000102030405
Exception Handling
Why is Exception Handling important?
Most applications are large and complex. Ive not seen an application without defects in my 15 year
experience. It is not that bad programmers create defects. Even good programmers write code that has
defects and throws exceptions. There are two things that are important when exceptions are thrown.
A friendly message to the user : You do not want a windows blue screen. When something goes
wrong and an exception occurs, it would be great to let the user know that something went
wrong and tech support has been notified. Additional thing we can do is to give the user a
unique exception identifier and information on how to reach the tech support.
Enough Information for the Support Team/Support Developer to debug the problem : When
writing code, always think about what information would I need to debug a problem in this
piece of code. Make sure that information is made available, mostly in the logs, if there are
exceptions. It would be great to tie the information with the unique exception identifier given to
the user.
53
54
Program Output
Exception in thread "main" java.lang.NullPointerException at
com.rithus.exceptionhandling.ExceptionHandlingExample1.method2(ExceptionHandlingExample1.java:1
5)
at
com.rithus.exceptionhandling.ExceptionHandlingExample1.method1(ExceptionHandlingExample1.java:1
0)
at com.rithus.exceptionhandling.ExceptionHandlingExample1.main(ExceptionHandlingExample1.java:6)
Look at the stack trace. Exception which is thrown in method2 is propagating to method1 and then to
main. This is because there is no exception handling in all 3 methods - main, method1 and method2
55
56
Yes. It will be. Finally will be executed even when there is a return statement in try or catch.
Exception
Exception is used when a programmer can handle the exception.
Checked Exception
Other Exception Classes (which dont fit the earlier definition). These are also called Checked Exceptions.
Exception, CheckedException1,CheckedException2 are checked exceptions. They are subclasses of
Exception which are not subclasses of RuntimeException.
57
58
Output
Exception in thread "main" java.lang.RuntimeException: Currencies don't match
at com.rithus.exceptionhandling.AmountAdder.addAmounts(ExceptionHandlingExample2.java:17)
at com.rithus.exceptionhandling.ExceptionHandlingExample2.main(ExceptionHandlingExample2.java:28)
Exception message shows the type of exception(java.lang.RuntimeException) and the string message
passed to the RuntimeException constructor("Currencies don't match");
class AmountAdder {
static Amount addAmounts(Amount amount1, Amount amount2) {
if (!amount1.currency.equals(amount2.currency)) {
throw new Exception("Currencies don't match");// COMPILER ERROR!
// Unhandled exception type Exception
}
return new Amount(amount1.currency, amount1.amount + amount2.amount);
}
}
What are the options you have to eliminate compilation errors when handling
checked exceptions?
All classes that are not RuntimeException or subclasses of RuntimeException but extend Exception are
called CheckedExceptions. The rule for CheckedExceptions is that they should either be handled or
thrown. Handled means it should be completed handled - i.e. not throw out of the method. Thrown
means the method should declare that it throws the exception
Option 1 : Declaring that a method would throw an exception
Let's look at how to declare throwing an exception from a method.
class AmountAdder {
static Amount addAmounts(Amount amount1, Amount amount2) throws Exception {
if (!amount1.currency.equals(amount2.currency)) {
throw new Exception("Currencies don't match");
}
return new Amount(amount1.currency, amount1.amount + amount2.amount);
}
}
Look at the line "static Amount addAmounts(Amount amount1, Amount amount2) throws Exception". This
is how we declare that a method throws Exception. This results in compilation error in main method. This
is because Main method is calling a method which is declaring that it might throw Exception. Main method
again has two options a. Throw b. Handle
Code with main method throwing the exception below
public static void main(String[] args) throws Exception {
AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5));
}
Output
Exception in thread "main" java.lang.Exception: Currencies don't match
at com.rithus.exceptionhandling.AmountAdder.addAmounts(ExceptionHandlingExample2.java:17)
at com.rithus.exceptionhandling.ExceptionHandlingExample2.main(ExceptionHandlingExample2.java:28)
Output
Exception Handled in Main
59
60
in
AmountAdder
to
remove
the
declaration
"
throws
No compilation error occurs since RuntimeException and subclasses of RuntimeException are not
Checked Exception's. So, they don't need to be handled or declared. If you are interested in handling
them, go ahead and handle them. But, java does not require you to handle them.
Remove try catch from main method. It is not necessary since CurrenciesDoNotMatchException is now a
RuntimeException.
public class ExceptionHandlingExample2 {
public static void main(String[] args) {
AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5));
}
}
Output:
Exception in thread "main" com.rithus.exceptionhandling.CurrenciesDoNotMatchException at
com.rithus.exceptionhandling.AmountAdder.addAmounts(ExceptionHandlingExample2.java:21)
at com.rithus.exceptionhandling.ExceptionHandlingExample2.main(ExceptionHandlingExample2.java:30)
Compilation Error. Specific Exception catch blocks should be before the catch block for a Generic
Exception. For example, CurrenciesDoNotMatchException should be before Exception.
How do you handle multiple exception types with same exception handling
block?
This is a new feature in Java 7.
61
62
try {
...
} catch( IOException | SQLException ex ) {
...
}
Consider the example below. When the try block ends the resources are automatically released. We do
not need to create a separate finally block.
try (BufferedReader br = new BufferedReader(new FileReader("FILE_PATH")))
{
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
Never Hide Exceptions. At the least log them. printStactTrace method prints the entire stack
trace when an exception occurs. If you handle an exception, it is always a good practice to log
the trace.
Do not use exception handling for flow control in a program. They have a significant
performance impact.
Think about the user. What does the user want to see if there is an exception?
Think about the support developer. What does the support developer need to debug the
exception?
Think about the calling method. Can the calling method do something about the exception being
thrown? If not, create un checked exceptions. For example, Spring Framework chooses to make
most of the jdbc exceptions as unchecked exceptions because , in most cases, there is nothing
that a caller of the method can do about a jdbc exception.
Have global exception handling.
Miscellaneous Topics
What are the default values in an array?
New Arrays are always initialized with default values.
int marks2[] = new int[5];
System.out.println(marks2[0]);//0
Default Values
byte,short,int,long 0
float,double 0.0
boolean false
object null
Printing a 2D Array
int[][] matrix3 = { { 1, 2, 3 }, { 4, 5, 6 } };
System.out.println(matrix3); //[[I@1d5a0305
System.out.println(
Arrays.toString(matrix3));
//[[I@6db3f829, [I@42698403]
System.out.println(
Arrays.deepToString(matrix3));
//[[1, 2, 3], [4, 5, 6]]
matrix3[0] is a 1D Array
System.out.println(matrix3[0]);//[I@86c347
System.out.println(Arrays.toString(matrix3[0]));//[1, 2, 3]
63
64
What is an Enum?
Enum allows specifying a list of values for a Type. Consider the example below. It declares an enum
Season with 4 possible values.
enum Season {
WINTER, SPRING, SUMMER, FALL
};
65
66
Code within static{ and } is called a static initializer. This is run only when class is first loaded. Only static
variables can be accessed in a static initializer.
Example Output
Static Initializer
Count when Static Initializer is run is 0
Even though three instances are created static initializer is run only once.
int i;
{
//This is an instance initializers. Run every time an object is created.
//static and instance variables can be accessed
System.out.println("Instance Initializer");
i = 6;
count = count + 1;
System.out.println("Count when Instance Initializer is run is " + count);
}
public static void main(String[] args) {
InitializerExamples example = new InitializerExamples();
InitializerExamples example1 = new InitializerExamples();
InitializerExamples example2 = new InitializerExamples();
}
}
Code within instance initializer is run every time an instance of the class is created.
Example Output
Instance Initializer
Count when Instance Initializer is run is 1
Instance Initializer
Count when Instance Initializer is run is 2
Instance Initializer
Count when Instance Initializer is run is 3
What is Tokenizing?
Tokenizing means splitting a string into several sub strings based on delimiters. For example, delimiter ;
splits the string ac;bd;def;e into four sub strings ac, bd, def and e.
Delimiter can in itself be any of the regular expression(s) we looked at earlier.
String.split(regex) function takes regex as an argument.
Example:
tokenize("ac;bd;def;e",";");//[ac, bd, def, e]
What is Serialization?
Serialization helps us to save and retrieve the state of an object.
Serialization => Convert object state to some internal object representation.
De-Serialization => The reverse. Convert internal representation to object.
Two important methods
67
68
}
int length;
int breadth;
transient int area;
}
If you run the program again, you would get following output
System.out.println(rectangle.length);// 5
System.out.println(rectangle.breadth);// 6
System.out.println(rectangle.area);// 0
Note that the value of rectangle.area is set to 0. Variable area is marked transient. So, it is not stored into
the serialized file. And when de-serialization happens area value is set to default value i.e. 0.
69
70
public House(int number) {
super();
this.number = number;
}
transient Wall wall;
int number;
}
class Wall implements Serializable {
int length;
int breadth;
int color;
}
With both these programs, earlier main method would run without throwing an exception.
If you try de-serializing, In Example2, state of wall object is retained whereas in Example1, state of wall
object is lost.
Collections
Why do we need Collections in Java?
Arrays are not dynamic. Once an array of a particular size is declared, the size cannot be modified. To
add a new element to the array, a new array has to be created with bigger size and all the elements
from the old array copied to new array.
Collections are used in situations where data is dynamic. Collections allow adding an element, deleting
an element and host of other operations. There are a number of Collections in Java allowing to choose
the right Collection for the right context.
71
72
What are the important methods that are declared in the Collection Interface?
Most important methods declared in the collection interface are the methods to add and remove an
element. add method allows adding an element to a collection and delete method allows deleting an
element from a collection.
size() methods returns number of elements in the collection. Other important methods defined as part
of collection interface are shown below.
interface Collection<E> extends Iterable<E>
{
boolean add(E paramE);
boolean remove(Object paramObject);
int size();
boolean isEmpty();
void clear();
boolean contains(Object paramObject);
boolean containsAll(Collection<?> paramCollection);
boolean addAll(Collection<? extends E> paramCollection);
boolean removeAll(Collection<?> paramCollection);
boolean retainAll(Collection<?> paramCollection);
Iterator<E> iterator();
//A NUMBER OF OTHER METHODS AS WELL..
}
E set(int paramInt, E paramE);
void add(int paramInt, E paramE);
E remove(int paramInt);
int indexOf(Object paramObject);
int lastIndexOf(Object paramObject);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int paramInt);
List<E> subList(int paramInt1, int paramInt2);
}
Code like below is permitted because of auto boxing. 5 is auto boxed into Integer object and stored in
ArrayList.
integers.add(5);//new Integer(5)
Add method (by default) adds the element at the end of the list.
73
74
Iterator<String> arraylistIterator = arraylist
.iterator();
while (arraylistIterator.hasNext()) {
String str = arraylistIterator.next();
System.out.println(str);//Prints the 4 names in the list on separate lines.
}
Other option to sort collections is by creating a separate class which implements Comparator interface.
Example below:
class DescendingSorter implements Comparator<Cricketer> {
//compareTo returns -1 if cricketer1 < cricketer2
// 1 if cricketer1 > cricketer2
// 0 if cricketer1 = cricketer2
//Since we want to sort in descending order,
//we should return -1 when runs are more
@Override
public int compare(Cricketer cricketer1,
Cricketer cricketer2) {
if (cricketer1.runs > cricketer2.runs) {
return -1;
}
if (cricketer1.runs < cricketer2.runs) {
return 1;
}
return 0;
}
}
75
76
// Thread Safe - Synchronized Methods
// implements RandomAccess, a marker interface, meaning it support fast
// almost constant time - access
}
Vector has the same operations as an ArrayList. However, all methods in Vector are synchronized. So,
we can use Vector if we share a list between two threads and we would want to them synchronized.
Linked List extends List and Queue.Other than operations exposed by the Queue interface, LinkedList
has the same operations as an ArrayList. However, the underlying implementation of Linked List is
different from that of an ArrayList.
ArrayList uses an Array kind of structure to store elements. So, inserting and deleting from an ArrayList
are expensive operations. However, search of an ArrayList is faster than LinkedList.
LinkedList uses a linked representation. Each object holds a link to the next element. Hence, insertion
and deletion are faster than ArrayList. But searching is slower.
}
//Main difference between Set and SortedSet is - an implementation of
//SortedSet interface maintains its elements in a sorted order. Set
//interface does not guarantee any Order.
interface SortedSet<E> extends Set<E> {
SortedSet<E> subSet(E fromElement, E toElement);
SortedSet<E> headSet(E toElement);
SortedSet<E> tailSet(E fromElement);
E first();
E last();
}
//A SortedSet extended with navigation methods reporting closest matches for
//given search targets.
interface NavigableSet<E> extends SortedSet<E> {
E lower(E e);
E floor(E e);
E ceiling(E e);
E higher(E e);
E pollFirst();
E pollLast();
Can you give examples of classes that implement the Set Interface?
HashSet, LinkedHashSet and TreeSet implement the Set interface.
77
78
// Order of Insertion : A, X
// Possible Order of Storing
class HashSet /* implements
// unordered, unsorted
// uses hashCode()
}
, B
: X, A ,B
Set */{
- iterates in random order
What is a HashSet?
HashSet implements set interface. So, HashSet does not allow duplicates. However, HashSet does not
support ordering. The order in which elements are inserted is not maintained.
HashSet Example
Set<String> hashset = new HashSet<String>();
hashset.add("Sachin");
System.out.println(hashset);//[Sachin]
hashset.add("Dravid");
System.out.println(hashset);//[Sachin, Dravid]
Lets try to add Sachin to the Set now. Sachin is Duplicate. So will not be added. returns false.
hashset.add("Sachin");//returns false since element is not added
System.out.println(hashset);//[Sachin, Dravid]
79
80
//Find the lowest number higher than or equal to 25
System.out.println(numbersTreeSet.ceiling(25));//25
81
82
//waits until element becomes available
E take() throws InterruptedException;
//waits for specified time and returns null if time expires
E poll(long timeout, TimeUnit unit) throws InterruptedException;
int remainingCapacity();
boolean remove(Object o);
public boolean contains(Object o);
int drainTo(Collection<? super E> c);
int drainTo(Collection<? super E> c, int maxElements);
}
What is a PriorityQueue?
PriorityQueue implements the Queue interface.
//The elements of the priority queue are ordered according to their natural
ordering
class PriorityQueue /* implements Queue */{
// sorted - natural order
}
//Using default constructor - uses natural ordering of numbers
//Smaller numbers have higher priority
PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>();
//This comparator gives high priority to the biggest number.
Comparator reverseComparator = new Comparator<Integer>() {
public int compare(Integer paramT1,
Integer paramT2) {
return paramT2 - paramT1;
}
};
Get method allows to get a value from the Map based on the key.
V get(Object paramObject);
83
84
V put(K paramK, V paramV);
V remove(Object paramObject);
void putAll(Map<? extends K, ? extends V> paramMap);
void clear();
Set<K> keySet();
Collection<V> values();
Set<Entry<K, V>> entrySet();
boolean equals(Object paramObject);
int hashCode();
public static abstract interface Entry<K, V>
{
K getKey();
V getValue();
V setValue(V paramV);
boolean equals(Object paramObject);
int hashCode();
}
}
What is a HashMap?
HashMap implements Map interface there by supporting key value pairs. Lets look at an example.
HashMap Example
Map<String, Cricketer> hashmap = new HashMap<String, Cricketer>();
hashmap.put("sachin",
new Cricketer("Sachin", 14000));
hashmap.put("dravid",
new Cricketer("Dravid", 12000));
hashmap.put("ponting", new Cricketer("Ponting",
11500));
hashmap.put("bradman", new Cricketer("Bradman",
9996));
If existing key is reused, it would replace existing value with the new value passed in.
//In the example below, an entry with key "ponting" is already present.
//Runs are updated to 11800.
hashmap.put("ponting", new Cricketer("Ponting",
11800));
//gets the recently updated value
System.out.println(hashmap.get("ponting"));//Ponting 11800
We will now insert a Cricketer with key dravid. In sorted order,dravid comes before sachin. So, the value
with key dravid is inserted at the start of the Map.
treemap.put("dravid",
new Cricketer("Dravid", 12000));
System.out.println(treemap);
//{dravid=Dravid 12000, sachin=Sachin 14000}
We will now insert a Cricketer with key ponting. In sorted order, ponting fits in between dravid and
sachin.
treemap.put("ponting", new Cricketer("Ponting",
11500));
System.out.println(treemap);
//{dravid=Dravid 12000, ponting=Ponting 11500, sachin=Sachin 14000}
treemap.put("bradman", new Cricketer("Bradman",
9996));
System.out.println(treemap);
85
86
//{bradman=Bradman 9996, dravid=Dravid 12000, ponting=Ponting 11500, sachin=Sachin
14000}
Example Program
TreeMap<Integer, Cricketer> numbersTreeMap = new TreeMap<Integer, Cricketer>();
numbersTreeMap.put(55, new Cricketer("Sachin",
14000));
numbersTreeMap.put(25, new Cricketer("Dravid",
12000));
numbersTreeMap.put(35, new Cricketer("Ponting",
12000));
numbersTreeMap.put(5,
new Cricketer("Bradman", 9996));
numbersTreeMap
.put(45, new Cricketer("Lara", 10000));
lowerKey method finds the highest key lower than specified key. floorKey method finds the highest key
lower than or equal to specified key. Corresponding methods for finding lowest key higher than
specified key are higher and ceiling. A few examples using the Map created earlier below.
//Find the highest key which is lower than 25
System.out.println(numbersTreeMap.lowerKey(25));//5
//Find the highest key which is lower than or equal to 25
System.out.println(numbersTreeMap.floorKey(25));//25
//Find the lowest key higher than 25
System.out.println(numbersTreeMap.higherKey(25));//35
//Find the lowest key higher than or equal to 25
System.out.println(numbersTreeMap.ceilingKey(25));//25
87
88
Advanced Collections
What is the difference between synchronized and concurrent collections in
Java?
Synchronized collections are implemented using synchronized methods and synchronized blocks. Only
one thread can executing any of the synchronized code at a given point in time. This places severe
restrictions on the concurrency of threads thereby affecting performance of the application. All the
pre Java 5 synchronized collections (HashTable & Vector, for example) use this approach.
Post Java 5, collections using new approaches to synchronization are available in Java. These are called
concurrent collections. More details below.
Copy on Write
Compare and Swap
Locks
These new approaches to concurrency provide better performance in specific contexts. We would
discuss each of these approaches in detail below.
All values in collection are stored in an internal immutable (not-changeable) array. A new array
is created if there is any modification to the collection.
Read operations are not synchronized. Only write operations are synchronized.
Copy on Write approach is used in scenarios where reads greatly out number writes on a collection.
CopyOnWriteArrayList & CopyOnWriteArraySet are implementations of this approach. Copy on Write
collections are typically used in Subject Observer scenarios, where the observers very rarely change.
Most frequent operations would be iterating around the observers and notifying them.
Example : CopyOnWriteArrayList : public boolean add(E e)
current value of member variable. If the value is not modified, the calculated result is stored into the
member variable. If another thread has modified the value, then the calculation can be performed
again. Or skipped as the need might be.
ConcurrentLinkedQueue uses this approach.
89
90
Arrays.asList returns a fixed-size list backed by the specified array. When an attempt is made to add or
remove from this collection an UnsupportedOperationException is thrown. Below code throws
UnsupportedOperationException.
Fail Safe Iterators do not throw exceptions even when there are changes in the collection. This is the
default behavior of the concurrent collections, introduced since Java 5.
Fail Safe Iterator makes copy of the internal data structure (object array) and iterates over the copied
data structure.
Fail Safe is efficient when traversal operations vastly outnumber mutations
package com.in28minutes.java.collections;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
public class FailSafe {
public static void main(String[] args) {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
while (iterator.hasNext()) {
System.out.println(map.get(iterator.next()));
map.put("key4", "value4");
}
91
92
Generics
What are Generics?
Generics are used to create Generic Classes and Generic methods which can work with different
Types(Classes).
Why do we need Generics? Can you give an example of how Generics make a
program more flexible?
Consider the class below:
class MyList {
private List<String> values;
void add(String value) {
values.add(value);
}
void remove(String value) {
values.remove(value);
}
}
To store integers, we need to create a new class. This is problem that Generics solve. Instead of hardcoding String class as the only type the class can work with, we make the class type a parameter to the
class.
Example with Generics
Lets replace String with T and create a new class. Now the MyListGeneric class can be used to create a
list of Integers or a list of Strings
class MyListGeneric<T> {
private List<T> values;
void add(T value) {
values.add(value);
}
void remove(T value) {
values.remove(value);
}
T get(int index) {
return values.get(index);
}
}
MyListGeneric<String> myListString = new MyListGeneric<String>();
myListString.add("Value 1");
myListString.add("Value 2");
MyListGeneric<Integer> myListInteger = new MyListGeneric<Integer>();
myListInteger.add(1);
myListInteger.add(2);
What are the restrictions in using generic type that is declared in a class
declaration?
If a generic is declared as part of class declaration, it can be used any where a type can be used in a class
- method (return type or argument), member variable etc. For Example: See how T is used as a
parameter and return type in the class MyListGeneric.
93
94
restrictedListInteger.add(1);
restrictedListInteger.add(2);
The method can now be called with any Class type extend Number.
Integer i = 5;
Integer k = doSomething(i);
Multi Threading
What is the need for Threads in Java?
Threads allow Java code to run in parallel. Lets look at an example to understand what we can do with
Threads.
Need for Threads
We are creating a Cricket Statistics Application. Let's say the steps involved in the application are
Steps I, II and III are independent and can be run in parallel to each other. Run individually this program
takes 160 minutes. We would want to run this program in lesser time. Threads can be a solution to this
problem. Threads allow us to run STEP I, II and III in parallel and run Step IV when all Steps I, II and III are
completed.
Below example shows the way we would write code usually without using Threads.
ThreadExamples example = new ThreadExamples();
example.downloadAndStoreBattingStatistics();
example.downloadAndStoreBowlingStatistics();
example.downloadAndStoreFieldingStatistics();
example.mergeAndAnalyze();
95
96
class BattingStatisticsThread extends Thread {
//run method without parameters
public void run() {
for (int i = 0; i < 1000; i++)
System.out
.println("Running Batting Statistics Thread "
+ i);
}
}
NEW;
RUNNABLE;
RUNNING;
BLOCKED/WAITING;
TERMINATED/DEAD;
Description
A thread is in NEW state when an object of the thread is created but the start method is not yet called.
At the end of line 1, battingThread1 is in NEW state.
A thread is in RUNNABLE state when it is eligible to run, but not running yet. (A number of Threads can
be in RUNNABLE state. Scheduler selects which Thread to move to RUNNING state). In the above
example, sometimes the Batting Statistics thread is running and at other time, the Bowling Statistics
Thread is running. When Batting Statistics thread is Running, the Bowling Statistics thread is ready to
run. Its just that the scheduler picked Batting Statistics thread to run at that instance and vice-versa.
When Batting Statistics thread is Running, the Bowling Statistics Thread is in Runnable state (Note that
the Bowling Statistics Thread is not waiting for anything except for the Scheduler to pick it up and run it).
A thread is RUNNING state when its the one that is currently , what else to say, Running.
A thread is in BLOCKED/WAITING/SLEEPING state when it is not eligible to be run by the Scheduler.
Thread is alive but is waiting for something. An example can be a Synchronized block. If Thread1 enters
synchronized block, it blocks all the other threads from entering synchronized code on the same
instance or class. All other threads are said to be in Blocked state.
A thread is in DEAD/TERMINATED state when it has completed its execution. Once a thread enters dead
state, it cannot be made active again.
97
98
Thread Priority Example
Consider the thread example declared below:
class ThreadExample extends Thread {
public void run() {
for (int i = 0; i < 1000; i++)
System.out
.println( this.getName() + " Running "
+ i);
}
}
What is ExecutorService?
The java.util.concurrent.ExecutorService interface is a new way of executing tasks asynchronously in the
background. An ExecutorService is very similar to a thread pool.
// Creates a thread pool that reuses a fixed number of threads
// operating off a shared unbounded queue. At any point, the parameter
// specifies the most threads that will be active processing tasks.
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
// Creates a thread pool that can schedule commands to run after a
// given delay, or to execute periodically.
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
99
If following method is running in two different threads, funny things can happen. After setting the value
to each cell, there is a call for the Thread to sleep for some time. After Thread 1 sets the value of cell1, it
goes to Sleep. So, Thread2 starts executing. If Thread 2 is executing return cell1 + cell2 + cell3;, it uses
cell1 value set by Thread 1 and cell2 and cell3 values set by Thread 2. This results in the unexpected
results that we see when the method is run in parallel. What is explained is one possible scenario. There
are several such scenarios possible.
The way you can prevent multiple threads from executing the same method is by using the synchronized
keyword on the method. If a method is marked synchronized, a different thread gets access to the
method only when there is no other thread currently executing the method.
Lets mark the method as synchronized:
synchronized int setandGetSum(int a1, int a2, int a3) {
cell1 = a1;
sleepForSomeTime();
cell2 = a2;
sleepForSomeTime();
cell3 = a3;
sleepForSomeTime();
return cell1 + cell2 + cell3;
}
Static methods and block are synchronized on the class. Instance methods and blocks are synchronized
on the instance of the class i.e. an object of the class. Static synchronized methods and instance
synchronized methods dont affect each other. This is because they are synchronized on two different
things.
static int getCount2(){
synchronized (SynchronizedSyntaxExample.class) {
return count;
}
}
Lets say we would want to run thread2 and thread3 in parallel but thread4 can only run when thread3
is finished. This can be achieved using join method.
Join method example
Look at the example code below:
thread3.start();
thread2.start();
thread3.join();//wait for thread 3 to complete
System.out.println("Thread3 is completed.");
thread4.start();
thread3.join() method call force the execution of main method to stop until thread3 completes
execution. After that, thread4.start() method is invoked, putting thread4 into a Runnable State.
Overloaded Join method
Join method also has an overloaded method accepting time in milliseconds as a parameter.
thread4.join(2000);
In above example, main method thread would wait for 2000 ms or the end of execution of thread4,
whichever is minimum.
10
1
What is a deadlock?
Lets consider a situation where thread1 is waiting for thread2 ( thread1 needs an object whose
synchronized code is being executed by thread1) and thread2 is waiting for thread1. This situation is
called a Deadlock. In a Deadlock situation, both these threads would wait for one another for ever.
Can you write a synchronized program with wait and notify methods?
package com.rithus.threads;
class Calculator extends Thread {
long sumUptoMillion;
long sumUptoTenMillion;
Output
Million done
499999500000
Ten Million done
10
3
@Test
public void sumOfOddNumbers_Usual() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
int sum = 0;
for (int number : numbers)
if (number % 2 != 0)
sum += number;
assertEquals(11, sum);
}
@Test
public void sumOfOddNumbers_FunctionalProgrammingExample() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
int sum = numbers.stream().filter(Test123::isOdd).reduce(0,
Integer::sum);
assertEquals(11, sum);
}
static boolean isOdd(int number) {
return number % 2 != 0;
}
What is a Stream?
A Stream is a source of objects. In the above example, we created a stream from List.
Streams have Intermediate Operations and Terminal Operations. In the example above, we used filter as
intermediate operation and reduce as a terminal operation.
Arrays.stream(new String[] {
"Ram", "Robert", "Rahim"
})
.filter(s - > s.startsWith("Ro"))
.map(String::toLowerCase)
.sorted()
.forEach(System.out::println);
In general any use of streams involves
Stateful : Elements need to be compared against one another (sort, distinct etc)
Stateless : No need for comparing with other elements (map, filter etc)
10
5
@Test
public void streamExample_Distinct() {
List<Integer> numbers = Arrays.asList(1, 1, 2, 6, 2, 3);
numbers.stream().distinct().forEach(System.out::print);
// 1263
}
Sorted Example
@Test
public void streamExample_Sorted() {
List<Integer> numbers = Arrays.asList(1, 1, 2, 6, 2, 3);
numbers.stream().sorted().forEach(System.out::print);
// 112236
}
Filter Example
@Test
public void streamExample_Filter() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
numbers.stream().filter(Test123::isOdd).forEach(System.out::print);
//137
}
@Test
public void sumOfOddNumbers_FunctionalProgramming() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
int sum = numbers.stream().filter(Test123::isOdd).reduce(0,
Integer::sum);
assertEquals(11, sum);
}
forEach is used to create a side effect. Print to Output. Store to database.
@Test
public void streamExample_Filter() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
numbers.stream().filter(Test123::isOdd).forEach(System.out::print);
//137
}
collect is used to group elements to a collection
@Test
public void streamExample_Collect() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
List<Integer> oddNumbers = numbers.stream().filter(Test123::isOdd)
.collect(Collectors.toList());
System.out.println(oddNumbers);
// [1, 3, 7]
}
@Test
public void lambdaExpression_simpleExample() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
numbers.stream().filter(Test123::isOdd).forEach(
number -> System.out.print(number));
// 137
}
Can you explain the relationship between Lambda Expression and Functional
Interfaces?
Look at the earlier example : Function we passed in is number -> System.out.print(number). Input to
this function is number. The function consumes it and prints it to the output.
forEach function has an interface - void java.util.stream.Stream.forEach(Consumer<T> action)
The JavaDoc for java.util.function.Consumer<T> reads - @FunctionalInterface : Represents an operation
that accepts a single input argument and returns no result. Unlike most other functional interfaces,
Consumer is expected to operate via side-effects.
10
7
What is a Predicate?
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
@Test
public void lambdaExpression_predicate() {
List<Integer> numbers = Arrays.asList(1, 3, 4, 6, 2, 7);
numbers.stream().filter((number) -> (number % 2 != 0)).forEach(
number -> System.out.print(number));
// 137
}
(number) -> (number % 2 != 0) is a Predicate. Takes an argument and returns true of false.
Signature of filter function : Stream<T> java.util.stream.Stream.filter(Predicate<? super T> predicate).
filter returns a stream consisting of the elements of this stream that match the given predicate.
What is a Consumer?
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
New Features
What are the new features in Java 5?
Generics
Enhanced for Loop
Autoboxing/Unboxing
Varargs
Static Import
Concurrent Collections
o Copy on Write
o Compare and Swap
Locks
Diamond Operator.
o Example : Map<String , List <Trade>> trades = new TreeMap <> ();
Using String in switch statements
Automatic resource management
o try(resources_to_be_cleant){ // your code }
Numeric literals with underscores
Improved exception handling
o Multiple catches in same block
o catch(ExceptionOne | ExceptionTwo | ExceptionThree e)
10
9