Pages

Sunday 22 September 2019

Optional

Q.What is the alternative to null in Java?
Java 8 introduces a new class called java.util.Optional<T> that’s inspired by the ideas of Haskell and Scala. It’s a class that encapsulates an optional value.


Q.How do you model the absence of a value?
Imagine you have the following nested object structure for a person owning a car and having car insurance.
The Person / Car / Insurance data model
If you design your classes like below
  1. class Person{
  2.     private Car car;
  3.     public Car getCar() {
  4.         return car;
  5.     }
  6. }
  1. class Car{
  2.     private Insurance insurance;
  3.     public Insurance getInsurance() {
  4.         return insurance;
  5.     }
  6. }
  1. class Insurance {
  2.     private String name;
  3.     public String getName() {
  4.         return name;
  5.     }
  6. }
  1. class Test {
  2.     public String getCarInsuranceName(Person person) {
  3.         return person.getCar().getInsurance().getName();
  4.     }
  5. public static void main(String[] args) {
  6.     Test t = new Test();
  7.     t.getCarInsuranceName(new Person());
  8. }
Problems with null
  • It’s a source of error. NullPointerException is by far the most common exception in Java.
  • It bloats your code. It worsens readability by making it necessary to fill your code with often deeply nested null checks.
  • It’s meaningless. It doesn’t have any semantic meaning, and in particular, it represents the wrong way to model the absence of a value in a statically typed language.
  • It breaks Java philosophy. Java always hides pointers from developers except in one case: the null pointer.
  • It creates a hole in the type system. null carries no type or other information, meaning it can be assigned to any reference type. This is a problem because, when it’s propagated to another part of the system, you have no idea what that null was initially supposed to be.

I argue that using null to represent the absence of a value is the wrong approach.
What you need is a better way to model the absence and presence of a value.

Redefining the Person / Car / Insurance data model using Optional
  1. class Person {
  2.     private Optional<Car> car;
  3.     public Optional<Car> getCar() {
  4.         return car;
  5.     }
  6. }
  1. class Car {
  2.     private Optional<Insurance> insurance;
  3.     public Optional<Insurance> getInsurance() {
  4.         return insurance;
  5.     }
  6. }
  1. class Insurance {
  2.     private String name;
  3.     public String getName() {
  4.         return name;
  5.     }
  6. }
  1. class OptionalVersion {
  2. public String getCarInsurance(Optional<Person1> person) {
  3.     return person.flatMap(Person1::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unknow");
  4. }
  5.     public static void main(String[] args) {
  6.         OptionalVersion t = new OptionalVersion();
  7.         Optional<Person> p = Optional.empty();
  8.         System.out.println(t.getCarInsurance(p));;
  9.     }

  10. }

Creating Optional objects
There are several ways to create  Optional objects.
Empty optional:
Optional<Car> optCar = Optional.empty();
Optional from a non-null value:
Optional<Car> optCar = Optional.of(car);
If car were null, a NullPointerException would be immediately thrown (rather than getting a
latent error once you try to access properties of the car).
Optional from null:
Optional<Car> optCar = Optional.ofNullable(car);
If car were null, the resulting Optional object would be empty

The methods of the Optional class

Method Description
empty Returns an empty Optional instance
filter If the value is present and matches the given predicate, returns this Optional; otherwise
returns the empty one
flatMap If a value is present, returns the Optional resulting from the application of the provided
mapping function to it; otherwise returns the empty Optional
get Returns the value wrapped by this Optional if present, otherwise throws a NoSuchElementException
ifPresent If a value is present, invokes the specified consumer with the value; otherwise does nothing
isPresent Returns true if there is a value present; otherwise false
map If a value is present, applies the provided mapping function to it
of Returns an Optional wrapping the given value or throws a NullPointerException if this value
is null
ofNullable Returns an Optional wrapping the given value or the empty Optional if this value is null
orElse Returns the value if present or the given default value otherwise
orElseGet Returns the value if present or the one provided by the given Supplier otherwise
orElseThrow Returns the value if present or throws the exception created by the given Supplier otherwise

Saturday 21 September 2019

Double colon operator


Method and Constructor reference by using "::" operator

  • The functional interface method can be mapped to our specified method by using "::" operator. This is called method reference.
  • Our specified method can be either a static or instance method.
  • The functional interface method and our specified method should have the same argument types except for return-type, method-name, modifiers, etc are not required to match.


Syntax
If our specified method is a static method.
Class-name::method-name

If the method is an instance method
Object-reference::method-name

Constructor references
We also can use ":: "operator to refer constructors
Syntax
Class-name::new

Example:

  1. class Student{
  2. private String name;
  3. Student(String name){
  4. this.name=name;
  5. }
  6. }
  7. interface A{
  8. public Student getName(String name);
  9. }
  10. class Test{
  11. public static void main(String[] args){
  12. A a= s-> new Sample(s);
  13. a.getName("Anu");
  14. A a1 = Student::new;
  15. a1.getName("Kalawati");
  16. }
  17. }
Note: In method and constructor references compulsory the argument types must be matched.

Java 8 in built functions

IN BUILT FUNCTIONS
Consumer,Supplier,Function and Predicate all are available under java.util.function package.

Comparison  of in built functions
Properties Consumer Supplier Function Predicate
Purpose To consume some input and perform required operation.It won’t return anything To supply some value base on requirement To take some input and perform the required operation and return the result. To some input and perform some conditional checks
Interface Declaration interface Consumer<T>{} interface Supplier<R>{} interface Function<T,R>{} interface Predicate<T>{}
Single abstract method public void accept(T t); public R get(); public R apply(T t); public boolean test(T t);
Default method andThen() NA andThen(),
compose()
and(),or(),
negate()
Static method



identify() isEqual()

How to call in built functions? 
  1. import java.util.function.Consumer;
  2. import java.util.function.Function;
  3. import java.util.function.Predicate;
  4. import java.util.function.Supplier;
  5. public class Test {
  6.     public static void main(String[] args) {
  7.      //void accept(T t);
  8.     Consumer<String> consumer1 = (String s)->{System.out.println(s);};
  9.     Consumer<String> consumer2=(s)->{System.out.println(s);};
  10.     Consumer<String> consumer3=s->System.out.println(s);
  11.       consumer3.accept("Amit");

  12.     //  T get();
  13.       Supplier<Integer> supplier1 = ()->10;
  14.       System.out.println(supplier1.get());

  15.       //R apply(T t);
  16.       Function<String, Integer> function1 = (String s)->{return 20;};
  17.       Function<String, Integer> function2 = (s)->{return 20;};
  18.       Function<String, Integer> function3 = (s)-> 20;
  19.       Function<String, Integer> function4 = s->20;
  20.       System.out.println(function4.apply("Kalawati"));

  21. //  boolean test(T t);
  22.       Predicate<Integer> predicate1=(Integer i)->{return i%2==0;};
  23.       Predicate<Integer> predicate2=(i)->{return i%2==0;};
  24.       Predicate<Integer> predicate3=(i)->i%2==0;
  25.       Predicate<Integer> predicate4=i-> i%2==0;
  26.       System.out.println(predicate4.test(20));
  27.       System.out.println(predicate4.test(15));       
  28.     }
  29. }
Predicate chaining
It is possible to combine predicates into a single predicate by using the following methods.
  • and()
  • or()
  • negate()
  • These are exactly same as logical AND, OR, complement operator
Function chaining
It is also possible to combine functions into a single function by using the following methods
  • andThen()
  • compose()
Consumer chaining
It is also possible to combine consumers into a single consumer by using andThen() method.

Example
  1. import java.util.function.Consumer;
  2. import java.util.function.Function;
  3. import java.util.function.Predicate;
  4. public class FunctionChaining {
  5.     public static void main(String[] args) {
  6.         //Predicate  chaining
  7.         Predicate<Integer> p1 = i->i%2==0;
  8.         Predicate<Integer> p2 = i->i%3==0;
  9.         System.out.println(p1.negate().test(10));//false
  10.         System.out.println(p1.or(p2).test(15));//true
  11.         System.out.println(p1.or(p2).test(7));//false
  12.         System.out.println(p1.and(p2).test(12));//true
  13.         System.out.println(p1.and(p2).test(10));//false
  14.        
  15.         //Function chaining
  16.         Function<Integer, Integer> f1= i-> i+2;
  17.         Function<Integer,Integer> f2= i->i*3;
  18.         System.out.println(f1.andThen(f2).apply(4));//18
  19.         //Note in andThen() f1 will apply first then f2
  20.         System.out.println(f1.compose(f2).apply(4));//14
  21.         //Note in compose() f2 will apply first and then f2.

  22.         //Consumer chaining
  23.         Consumer<Integer> c1 = i->System.out.print(i+2);
  24.         Consumer<Integer> c2= i->System.out.print(i*2);
  25.         c1.andThen(c2).accept(4);//68
  26.     }
  27. }

Friday 20 September 2019

Default method

Default Methods
  1. In Java 1.8v onwards, you can also define the default method inside the interface.
  2. You can define the default method using the keyword default.
  3. Default methods are by default available to all implementation classes. Based on our business requirement implementation class can use these default methods directly or override.
  4. You can't override object class methods as default methods inside interface otherwise you will get a compilation error. Because you know Object class methods are by default available to each class/interface hence it is not required to override.
  5. If you try to override Object class methods in the interface, you will get compiler error.
Note: You can't define the default method inside the concrete class and abstract class, otherwise compilation error.

Let's understand the above concept through examples.
Example1:
  1. public default void methodOne(){
  2. System.out.println("methodOne");
  3. }
  4. public default int methodOne(int a){
  5. return 10;
  6. }
Example2:
  1. interface InterA{
  2. public default int add(int a, int b){
  3. return a+b;
  4. }
  5. }
  6. class Test implements InterA{
  7. public static void main(String[] args){
  8. Test t = new Test();
  9. t.add(10,20);
  10. }
  11. }
Example3:
  1. interface InterA{
  2. public default void methodOne(){
  3. System.out.println("methodOne of InterA");
  4. }
  5. }
  6. class Test implements InterA{
  7. public void methodOne(){
  8. System.out.println("methodOne of Test");
  9. }
  10. public static void main(String[] args){
  11. Test t = new Test();
  12. t.methodOne();//methodOne of Test
  13. }
  14. }
Example4:
  1. interface InterA{
  2. public default String toString(){
  3. return null;// compilation error, you can't override Object class methods.
  4. }
  5. }
Default method w.r.t Inheritance
If two interfaces contain default method with same method signature then you will get ambiguity problem(diamond problem) in implementation class.To overcome this problem compulsory you should override default method in the implementation class otherwise you will get compilation error.

Example:
  1. interface A{
  2. default void methodOne(){
  3. System.out.println("Interface A default method");
  4. }
  5. }
  6. interface B{
  7. default void methodOne(){
  8. System.out.println("Interface A default method");
  9. }
  10. }
  11. class Test implements A,B{}//compilation error
Q. How to override default method?
In the implementation class, you can override the default method by removing keyword default and abide by overriding rules.

Example:
  1. class Test implements A,B{
  2. public void methodOne(){
  3. System.out.println("Override default method");
  4. //You can also do as below
  5. A.super.methodOne();
  6. B.super.methodOne();
  7. }
  8. public static void main(String args){
  9. Test t = new Test();
  10. t.methodOne();
  11. }
  12. }

Tuesday 17 September 2019

Generic concept

Agenda
Introduction
The generic concept is introduced in Java 1.5v
To resolve two problems of collection.
Type safety
ClassCastException
ArrayList list = new ArrayList();//Non generic a.k.a raw type version till java 1.4
ArrayList<String> list = new ArrayList<String>();//Generic Type
In Java 1.7 diamond operator <> is introuduce to improve code readability
ArrayList<String> list = new ArrayList<>();//Generic Type,valid from java 1.7 onwards
Here you can't add elements other than String type othewise you will get compilation error.
Example:
list.add("Anu");//valid
list.add(10);// invalid
Note1: Polymorphism concept is applicable only for the base type,not for parameter type.
Note2: Parameter type must not be primitive types. It should be any class or interface
Example
ArrayList<int> list = new ArrayList<>();// invalid

Generic Classes

Until Java 1.4v ArrayList class is defined as follows.
Example
class ArrayList{
public boolean add(Object o){}
public Object get(int index){}

}
add() method can take Object as the argument and hence we can add any type of the object to the ArrayList. Due to this, we are not getting type of safety.
The return type of get() method is object hence at the time of retrieval compulsory we should perform typecasting. But in Java 1.5v a generic version of ArrayList class is defined as follows.
Generic
Example: class ArrayList<E>{
public boolen add(E data){}
public E get(int index){}
}
Based on our requirement E will be replaced with our provided type.
To hold only String type of objects we can create ArrayList object as follow.
Example
ArrayList<String> list = new ArrayList<>():
For this requirement compiler considered ArrayList class is
Example
class ArrayList<String>{
public boolen add(String data){}
public String get(int index){}
}
add() method can take only String type as argument hence we can add only String type of objects to the List.Hence through generics, we are getting type safety.
At the time of retrieval, it is not required to perform any typecasting.

How can we create a custom generic class?
class Student<T>{}

Bonded Types
We can bound the type parameter for a particular range by using the extends keyword. such types are called bounded types.
Example
class Test<T>{}
Test<Integer> t1 = new Test<>();
Test<String> t2 = new Test<>();
As the type parameter we can pass any type there is no restriction hence it is unbounded type.
Example
class Test<T extends X>{}
If X is a class then as the type parameter we can pass either X or its child classes.
If X is an interface then as the type parameter we can pass either X or its implementation classes.
Example
class Test<T extends Number>{}
class Test1{
public static void main(String[] args){
Test<Integer> t1 = new Test<>();
Test<String> t1 = new Test<>();// Compilation Error
}
}
Example
class Test<T extends Runnable>{}
class Test1{
public static void main(String[] args){
Test<Thread> t1 = new Test<>();// Thread class is implementation class of Runnable interface.
Test<String> t1 = new Test<>();// Compilation Error
}
We can't define bounded types by using implements and super keyword.
Example
class Test<T implements Runnable>{}//invalid
class Test<T super String>{}//invalid
But implements keyword purpose we can replace with extends keyword.
As the type parameter, we can use any valid java identifier but it is recommended to use
T for Type
E for Element
K for Key
V for Value
Example
class Test<X>{}//valid
class Test<Anu>{}//valid
We can pass any number of type parameters, there is no restriction at all.
Example
class Map<K,V>{}
class Test<A,B,C,D,E....>{}
We can also define bounded types in combination.
Example
class Test<T extends Number & Runnable>{}//valid
As the type parameter, we can pass any type which extends Number class and implements Runnable interface.
class Test<T extends Number & String>{}// invalid, we can't extend more than one class at a time.
class Test<T extends Runnable & Comparable>{}//valid
class Test<T extends Runnable & Number>{}//invalid, we have to take 1st class followed by interface.

Generic methods and wild card character(?)
public void methodOne(ArrayList<String> list){
list.add("Anu");
list.add(null);
list.add(10);// invalid, only string type and null is allowed.}

public void methodOne(ArrayList<?> list){};We can use this method for ArrayList of any type but within method we can't
add anything except null.
Example
list.add(null);//valid
list.add("Anu");// invalid
list.add(10);//invalid
This method is useful whenever we are performing only read operation.

public void method(ArrayList<? extends X> list):
  • If X is a class then this method is applicable for ArrayList of either X type or its child classes.
  • If X is an interface then this method is applicable for ArrayList of either X type or its implementation classes.
  • Within the method we can add only null value.

public void methodOne(ArrayList<? super X> list):
  • If X is a class then this method is applicable for ArrayList of either X type or its super-types.
  • If X is an interface then this method is applicable for ArrayList of either X type or its super-types.
  • But within the method, we can add X type objects and null to the List.
  • If X is a class then within the method we can add only X type or its sub-types.
  • If X is an interface then within the method we can add only implementation classes of X.
Below example will help you to understand the above concept.
class A{}
class B extends A{}
class C extends B{}
class D extends C{}
interface X{}
interface Y extends X{}
class P  implements Q, Y{}
interface Q {}
class R extends P{}
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. class GenericAtMethod {
  4. public static  void m1(List<? extends B> list) {
  5. // We can add only null value
  6. list.add(null);
  7. }
  8. public static  void m2(List<? extends Y> list) {
  9. //we can add only null value
  10. list.add(null);
  11. }
  12. public static  void m3(List<? super B> list) {
  13. // we can add only either B type or its sub-types(C,D) or null
  14. list.add(null);
  15. list.add(new C());
  16. list.add(new D());
  17. }
  18. public static  void m4(List<? super Y> list) {
  19. //we can add only either implementation classes of Y(P,R) or null
  20. list.add(null);
  21. list.add(new P());
  22. list.add(new R());
  23. }
  24. public static void main(String[] args) {
  25. //method m1() will accept only B type or its sub-types(C,D)
  26. List<A> l1= new ArrayList<>();
  27. List<B> l2= new ArrayList<>();
  28. List<C> l3=new ArrayList<>();
  29. List<D> l10=new ArrayList<>();
  30. List<Object> l9=new ArrayList<>();
  31. //m1(l1); invalid because A is super type of B
  32. m1(l2);
  33. m1(l3);
  34. m1(l10);
  35. //method m2() will accept only Y type or its implementation classes(P,R)
  36. List<Y> l4 = new ArrayList<>();
  37. List<P> l5 = new ArrayList<>();
  38. List<R> l6 = new ArrayList<>();
  39. List<X> l7 = new ArrayList<>();
  40. List<Q> l8 = new ArrayList<>();
  41. m2(l4);
  42. m2(l5);
  43. m2(l6);
  44. // m2(l7) invalid
  45. // m2(l8); invalid
  46. //method m3() will accept only List of either B type or its super-types(A,Object)
  47. m3(l1);
  48. m3(l2);
  49. m3(l9);
  50. //m3(l3); invalid
  51. //m3(l10); invalid
  52. //method m4() will accept only List of either Y type or its super types(Y,Object)
  53. m4(l4);
  54. m4(l7 );
  55. m4(l9);
  56. }
  57. }
Which of the following declarations are valid?
ArrayList<String> l1 = new ArrayList<String>();//valid
ArrayList<String> l2= new ArrayList<>();//valid
ArrayList<?> l3 = new ArrayList<Integer>();//valid
ArrayList<?> l4 = new ArrayList<String>();//valid
ArrayList<? extends Number> l5 = new ArrayList<Integer>();//valid
ArrayList<? extends Number> l6 = new ArrayList<String>();// invalid
ArrayList<?> l7 = new ArrayList<? extends Number>();// invalid
ArrayList<?> l8 = new ArrayList<?>();// invalid

We can declare the type parameter either at the class level or method level.
Declaring type parameter at class level:
class Test<T>{
//we can use T anywhere
}

Declaring type parameter at the method level
We must declare just before return type.
Example
public <T> void methodOne(T t){};//valid
public <T extends Number> void methodOne(T t){};//valid
public <T extends Number & Runnable> void method(T t){};//valid
public <T extends Number & Runnable & Comparable> void methodOne(T t){}//valid
public <T extends Number & Thread> void methodOne(T t){}//invalid
public <T extends Runnable & Thread> void methodOne(T t){}//invalid

Conclusion
The generic concept is applicable only at compile time.Hence the following declarations are equal
ArrayList<String> list = new ArrayList<>();
ArrayList<Integer> list1 = new ArrayList<I>();

You will get compiler Error, because method methodOne have same erasure type.
public void methodOne(ArrayList<String> l){}
public void methodOne(ArrayList<Integer> l){}

How compiler works w.r.t Generic code.
  • The compiler first checks type and value is added the same type or not. If not give you Compilation Error.
  • If the type and added values are of the same type, then it erasure the type and again validate the source file, if found any violation then give you Compilation Error.
Limitation of Generic Type
1.You cannot instantiate a generic type using a new operator. For example,
T  t = new T(); //compiler error

2.You cannot instantiate an array of a generic type. For example,
T[] t = new T[3];  //compiler error

3.You can declare instance fields of type T, but not of static fields of type T. For example,
Class A<T>{
T t;
static T t1; //compiler error
}

4.It is not possible to have generic exception classes. For example,
Class GenericException<T> extends Throwable{} // compiler error

5.You cannot instantiate a generic type with primitive types. For example,
List<int> list; // compiler error.

Exception handling

Agenda
  • Exception
  • Exception Handling
  • Benefits of Exception Handling
  • Hierarchy of Exception
  • Keywords related to exception
  • Default exception handling in java
  • The possible combination of try, catch and finally
  • Multi-catch block
  • Try-with resources
  • Custom Exception
  • Assertions
Exception
An event that disturbs the normal flow of the program is called an exception.
Examples:
NullPointerException
ArrayIndexOutOfBoundException
FileNotFoundException
IOException
If an exception raised at any particular line, then the program will terminate abnormally. This means the remaining lines of the program will not be executed.

Q. How can you stop abnormal termination of the program?
Ans: Exception Handling mechanism, using keywords try, catch.

Exception Handling
Put the risky codes inside a try block and handle it in the catch block.
Risky codes are those which cause the abnormal termination of the program.
Example:
  1. public class Test {
  2. public static void print() {
  3. int a=10;
  4. int b=0;
  5. System.out.println(a/b);// This is risky  code, cause it will throw ArithmeticException         
  6. }
  7. public static void main(String[] args) {
  8. print();
  9. }
  10. }

To solve the above problem put the risky code in a try block and handle it in a catch block like below.
  1. class Solution{
  2. public static void print() {
  3. int a=10;
  4. int b=0;
  5. try {
  6. System.out.println(a/b);
  7. }catch(ArithmeticException e) {
  8. System.out.println("Denominator must not be zero");
  9. }
  10. }
  11. public static void main(String[] args) {
  12. print();
  13. }
  14. }
Benefits Of Exception Handling
Abnormal termination of the program is solved.

Exception: It is caused by our program and these are recoverable.
Error: It is not caused by our program, these are due to lack of system resources and these are not recoverable.

Hierarchy of Exception




Checked vs Unchecked Exceptions
The exceptions which are checked by the compiler  are called checked exceptions
Example:
FileNotFoundException
IOException
InterruptedException
The exceptions which are not checked by the compiler are called unchecked exception.
Example:
NullPointerException
ArrayIndexOutOfBoundException

Note 1: RuntimeException and its child classed, Error and its child classes are unchecked and all the remaining are checked exceptions
Note 2: Whether the exception is checked or unchecked compulsory it should occur at runtime only. There is no chance of occurring any exception at compile time.

Keywords related to exception handling: 
try: Put all risky code inside the try block.
catch: Handle exception inside the catch block.
finally: Put resource clean up code inside finally block
throw: To handover our created exception object to the JVM manually.
throws: To delegate the responsibility of exception handling to the caller method.

Default exception handling in java
1. If an exception is raised inside any method then the method is responsible to create an Exception object with the following information.
                                Name of the exception
                                Description of the exception
                                Location of the exception
2. After creating the exception object the method handovers the object to the JVM.
3.JVM checks whether the method contains any exception handling code or not. If the method won't contain any exception handling code then JVM terminates that method abnormally and remove the corresponding entry from the stack.
4.JVM identifies the caller method and checks whether the caller method contains any handling code or not. If the caller method also not contain any exception handling code then JVM terminates that caller also abnormally and removes the corresponding entry from the stack. This process will continue until the main() method. If the main() method also doesn't contain any exception handling code then JVM terminates main() method and removes the corresponding entry from the stack.
5. Then JVM handovers the responsibility to exception handling to the default exception handler.
6.Default exception handler print exception information to the console in the following formats and terminates the program abnormally.
                             Name of the exception: description
                             Location of exception(stack trace)

The possible combination of try, catch and finally

import java.io.FileNotFoundException;
public class PossibleCombination {
public void method() {
try {}catch(NullPointerException e) {}
try {}catch(RuntimeException e) {}
try {}catch(Error e) {}
try {}catch(Exception e) {}
try {}catch(Throwable e) {}
try {}catch(FileNotFoundException e) {}//CE For checked exception it must be raised in the try block then only you can handle it.
try {}catch(RuntimeException e) {}catch(Exception e) {}
try {}catch(NullPointerException e) {}catch(NullPointerException e) {}//CE you can't handle same exception two times.
try{}catch(Exception e) {}finally{}
try{}finally{}catch(Exception e) {}//CE in catch, finally series finally block should be the last block.
try {}catch(RuntimeException e) {}catch(NullPointerException e) {}//CE if there is a relation between the exceptions then first child exception should be handled first then parent.
try {}catch(NullPointerException e) {}catch(RuntimeException e) {}
try {}finally {}
try {}finally {}finally {}//CE atmost one finally block is  allowed. 
}
}

Multi-catch block
In a multi-catch block, you cannot combine catch handlers for two exceptions that share a parent-child relationship. You can only combine catch handlers for exceptions that don't share the parent-child relationship between them.
For example:
try {
throw new FileNotFoundException();
}catch(FileNotFoundException |IOException ex) {
}

Try with Resources
Until 1.6v, it is a programmer nagging to close all open resources(BufferReader, Connection) explicitly.
What's happen, If the programmer will forget to close the resources, It causes a memory leak and therefore effects the performance of the application.
To overcome this problem Java people introduce try-with resource
concept in 1.7v which closes all the open resources automatically. But only those resources which are the child of AutoCloseable or Closeable interface.
All resoure reference variables should be final or effectively final, therfore we can't do reassignment within the try block like below
try(BufferReader br = new BufferReader(new FileReader("test.txt"))){
br = new BufferReader(new FileReader("test.txt"));// invalid, CE
}
Note: We can declare any number of resources but all these resources must be separeted with ";" and finally block is not required . Like below
      try(Resource1;Resource2;Resource3){}

Try-with Resources enhancement
Until 1.8v, the resource reference variables which are created outside of the try block can't be used directly in try-with-resources like below
BufferReader br = new BufferReader(new FileReader("test.txt"))
try(br){
// invalid until 1.8v, Resource reference variables must be local to try block
}

But valid in Java 1.8v onwards
try(BufferReader br1=br){
// valid in 1.8v or higher version
}

But in Java 1.9v onwards
try(br){
// valid in 1.9v or higher version, but make sure resources should be either final or effectively final, means we should not perform reassignment.
}

Custom Exception
You can create a custom exception by extending Exception or RuntimeException as per your business requirement.
If you want to force the caller to handle it, then create your custom exception by extending Exception otherwise create custom exception using RuntimeException.
You can also create by extending Throwable but it is not recommended.

Example
class RecordNotFoundException extends Exception{}
or
class RecordNotFoundException extends RuntimeException{}

Assertions
When creating application programs, you assume many things. However, often it happens that assumptions don't hold, resulting in an erroneous condition.
The assert statement is used to check your assumptions about the program. If assumption test gets fail then JVM will throw AssertionError
For Example:
public class AssertionExample {
public static void main(String[] args) {
int i=Integer.MIN_VALUE;
if(i<0) {
//If negative value, convert into positive value
i=-i;
}
System.out.println("the value of i is :"+i);
assert(i>=0):"impossible i is negative!";
}
}
Note: You have to enable assertion before executing the above program like  below
java -ea AssertionExample
the value of i is :-2147483648
Exception in thread "main" java.lang.AssertionError: impossible i is negative!
        at AssertionExample.main(AssertionExample.java:9)