Spring Version 4

  1. Spring Framework 4.0 provides support for several Java 8 features
  2. Java EE version 6 or above with the JPA 2.0 and Servlet 3.0 specifications
  3. Groovy Bean Definition DSL- external bean configuration using a Groovy DSL
  4. Core Container Improvements
    1. The @Lazy annotation can now be used on injection points, as well as on @Bean definitions.
    2. The @Description annotation has been introduced for developers using Java-based configuration
    3. Using generics as autowiring qualifiers
    4. Beans can now be ordered when they are autowired into lists and arrays. Both the @Order annotation and Ordered interface are supported.
    5. A generalized model for conditionally filtering beans has been added via the @Conditional annotation

Spring Version 5

  1. Functional programming with Kotlin
  2. Reactive Programming Model.The Reactive Streams API is officially part of Java 9. In Java 8, you will need to include a dependency for the Reactive Streams API specification.
  3. @Nullable and @NotNull annotations will explicitly mark nullable arguments and return values. This enables dealing null values at compile time rather than throwing NullPointerExceptions at runtime.
  4. Spring Framework 5.0 now supports candidate component index as an alternative to classpath scanning..Reading entities from the index rather than scanning the classpath.Loading the component index is cheap. Therefore the startup time with the index remains constant as the number of classes increase. While for a compoent scan the startup time increases significantly.
  5. requires Java 8 as a minimum JDK version.Spring 5 is fully compatible with Java 9.
  6. Servlet 3.1,JMS 2.0,JPA 2.1,Hibernate5,JAX-RS 2.0,Bean Validation 1.1,JUnit 5

Java 7 Features:

  1. Usage of Strings in Switch Statement
  2. Diamond Operator – the diamond operator allows you to write more compact (and readable) code by saving repeated type arguments
  3. Try with Resources
  4. Multiple Exception Handling
  5. Suppressed Exceptions
  6. Allows Binay Literals – Binary Literal are expressing Integer Values in terms of Binary Value by adding the prefix 0b or 0B to the integral value.For more on BinayLiteral click here

Java 8 Features:

  1. Lambda Expressions
  2. Java Stream API for Bulk Data Operations on Collections.
  3. Static and Default method in Functional Interfaces
  4. forEach() method in Iterable interface
  5. Functional Interfaces
  6. Collection API improvements

Java 9 Features:

  1. Factory Methods for Immutable List, Set, Map and Map.Entry
  2. Private methods in Interfaces
  3. Reactive Streams
  4. JShell: the interactive Java REPL

Java 10 Features:

  1. Local-Variable Type Inference
  2. Application Class-Data Sharing
  3. default set of root Certification Authority (CA) certificates in the JDK
  4. Garbage Collector Interface

Java 11 Features:

  1. Java 11 JDK is not free for usage on commercial purpose
  2. No need to compile.typing >>Java in command prompt will compile and run java
  3. Remove the Java EE and CORBA Modules –
  4. Java String Methods – isBlank(), lines(), strip(), stripLeading(), stripTrailing()

Java 17 Features:

  1. LTS support and licenses Java 17 LTS is the latest long-term support release for the Java SE platform
  2. Pattern matching for the switch case
  3. Sealed classes and interfaces. Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them.
    sealed class Human permits Manish, Vartika, Anjali 
    {    
        public void printName() 
        { 
            System.out.println("Default"); 
        } 
    } 
    
    non-sealed class Manish extends Human 
    { 
        public void printName() 
        { 
            System.out.println("Manish Sharma"); 
        } 
    } 
    

Why Lambda Expressions

Now Lets Iterate through the simple ArrayList

Without Lambda Expressions

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

for (int number : numbers) 
{
    System.out.println(number);
}

We iterate the collection externally, explicitly pulling out and processing the items one by one. Now through Lambda Expressions, we are using an internal iteration the JIT compiler could optimize it processing the items in parallel or in a different order. These optimizations are impossible if we iterate the collection externally as we are used to doing in Java and more in general with the imperative programming.

With Lambda Expressions

numbers.forEach((Integer value) -> System.out.println(value));

(or)

numbers.forEach(value -> System.out.println(value));

Apart from the above reason Lambdas allows us to

  • Enable to treat functionality as a method argument, or code as data.
  • A function that can be created without belonging to any class.
  • A lambda expression can be passed around as if it was an object and executed on demand.
  • It reduces the line of code.
  • It Supports Sequential and Parallel execution by passing behavior in methods with collection stream API
  • Using Stream API and lambda expression we can achieve higher efficiency (parallel execution) in the case of bulk operations on collections

Java 8 Lambda uses JVM Opcode – invokedynamic

The Following code will result in Anonymous class being created when you compile the code.
So if you have 10 anonymous classes then it would be 10 more classes like(ClassName$1.class,ClassName$2.class….ClassName$10.class) in the final jar.

AccountService accountServiceAnonymous = new AccountService(){
    public void createAccount(){
        Account account = new Account();
        save(account);
    }
};

But Java 8 lambda uses invokedynamic to call lambdas thus if you have 10 lambdas it will not result in any anonymous classes thus reducing the final jar size.

AccountService accountServiceLambda = () -> {
    Account account = new Account();
    save(account);
}

Below is a code example of CustomClass Loader which Servers use internally for HotCode Swap without restarting the server.When you change the Quote in ServerImpl.java file the file should be reloaded by selecting the RELOAD option while running Client.java

IServer.java

public interface IServer {
	public String getQuote();
}

ServerImpl.java

public class ServerImpl implements IServer{
	@Override
    public String getQuote() {
        return "Its Working Man";
    }
}

Client.java

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Client {
    static ClassLoader cl;
    static IServer server;

    public static void reloadServer() throws Exception {
        URL[] urls = new URL[]{new URL("file:///D:/java/HotDeplyment/appclasses")};
        System.out.println("Reloaded.....");
        cl = new URLClassLoader(urls);
        server  = (IServer) cl.loadClass("com.mugil.org.ServerImpl").newInstance();
    }

    public static void main(String [] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        reloadServer();
        while (true) {
            System.out.print("Enter QUOTE, RELOAD, or QUIT: ");
            String cmdRead = br.readLine();
            String cmd = cmdRead.toUpperCase();
            if (cmd.equals("QUIT")) {
                return;
            } else if (cmd.equals("QUOTE")) {
                System.out.println( server.getQuote());
            } else if (cmd.equals("RELOAD")) {
            	reloadServer();
            }
        }
    }
}

The Above code is not working as windows is not clearing cached .class files or JAR files. So the alternative is to try with the below Custom Class Loader(MyURLClassLoader) which in turn extends URLClassLoader again.

MyURLClassLoader.java

import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.jar.JarFile;

public class MyURLClassLoader extends URLClassLoader {

	public MyURLClassLoader(URL[] urls, ClassLoader parent) {
	    super(urls, parent);
	}

    /**
     * Closes all open jar files
     */
    public void close() {
        try {
            Class clazz = java.net.URLClassLoader.class;
            Field ucp = clazz.getDeclaredField("ucp");
            ucp.setAccessible(true);
            Object sunMiscURLClassPath = ucp.get(this);
            Field loaders = sunMiscURLClassPath.getClass().getDeclaredField("loaders");
            loaders.setAccessible(true);
            Object collection = loaders.get(sunMiscURLClassPath);
            for (Object sunMiscURLClassPathJarLoader : ((Collection) collection).toArray()) {
                try {
                    Field loader = sunMiscURLClassPathJarLoader.getClass().getDeclaredField("jar");
                    loader.setAccessible(true);
                    Object jarFile = loader.get(sunMiscURLClassPathJarLoader);
                    ((JarFile) jarFile).close();
                } catch (Throwable t) {
                    // if we got this far, this is probably not a JAR loader so skip it
                }
            }
        } catch (Throwable t) {
            // probably not a SUN VM
        }
        return;
    }
}

In the below code the CustomClass Loader is called to load the classes which inturn calls the Super Class loader which is again Loaders from URL Class Loader.Once it is done we have defined a custom close method which closes the JAR files or .class files which is loaded by class loader.

TestClassLoader.java

package com.mugil.org;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;

public class TestClassLoader {
	static ClassLoader cl;
    static IServer server;
	
	public static void main(String[] args) throws Exception {
		
		while(true) {
			try {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			TestClassLoader obj = new TestClassLoader();
			obj.loadAndInstantiate();			
			System.out.println(server.getQuote());			
			}
			catch (Exception e){
				
			}
			finally {
				try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
			}
		}    
	}
	
	void loadAndInstantiate() throws Exception {
	    MyURLClassLoader cl = null;
	    try {	    	
	        File file = new File("D:\\java\\HotDeplyment\\bin\\Sample.jar");
	        String classToLoad = "com.mugil.org.ServerImpl";
	        URL jarUrl = new URL("file:" + file.getAbsolutePath());
	        cl = new MyURLClassLoader(new URL[] {jarUrl}, getClass().getClassLoader());
	        Class loadedClass = cl.loadClass(classToLoad);
	        Object o = loadedClass.getConstructor().newInstance();
	        server  = (IServer) o;
	        
	    } finally {
	        if(cl != null)
	            cl.close();
	    } 
	}
}

Since the infinite while loop is called indefinitely with the thread sleep interval of every 3 seconds we replace the JAR file in the middle which takes the class from the new JAR file loaded.You need to change the ServerImpl.java file and build the JDK before you want to see the changes

Output

.
.
Its Working Man
Its Working Man
Its Working Man
Its Working Man
Its Working 
Its Working 
Its Working 
.
.

The Above code is not working either

Why Tomcat Server does not needs restart if changes are done in servlet and JSP?
Tomcat is capable of adding/modifying classpath to Web Application classloader at runtime. Tomcat will be having their custom Classloader implementation which allows them to add the classpaths at runtime.a new classloader is created for the Servlet/JSP with Application classloader as parent classloader. And the new classloader will load the modified class again.

It is always best to reload the entire application incase changes are done to servlet. If you were simply to reload one class, in isolation, you might break dependencies or miss some initialization steps. Therefore, it’s much safer to reload the entire application clicking deploy option in tomcat server.JSPs on the other hand, when properly coded, shouldn’t have anything in them by markup text. So reloading a single JSP, without reloading the entire app, should be safe. By default, tomcat is started in development mode, which means JSP-derived servlets recompiled when a change is detected.

In the web.xml you need to set the below config

<servlet>
   .
   .
    <!-- Add the following init-param -->
    <init-param>
        <param-name>development</param-name>
        <param-value>true</param-value>
    </init-param>
   .
   .
   .
</servlet>

In the Server.xml reloadable should be set to true

<Context path="/simple" docBase="webapps/simple"  debug="0" reloadable="true" ></Context>

More on how CustomClass loader works for Hot Deployment here

Class Loaders
Let’s take two simple Java Files as below

Helper.java

package com.mugil.org;
public class Helper {
	public String getMessage()
	{
		return "Helper Method";
	}
}

TestHelper.java

package com.mugil.org;
public class TestHelper {
	public static void main(String[] args) {
		Helper objHelper = new Helper();
		System.out.println(objHelper.getMessage());
	}
}

How to Compile class in Command Prompt
Normally when you compile Java class the class files would be created in bin folder with
the folder structure same as package name bin->com->mugil->org.
When you want the .class to be created in a specific folder then use the below command

D:\java\ClassLoaders>javac -d classes -sourcepath src src\com\mugil\org\Helper.java

Classes folder should be created manually or it’s going to throw
javac: directory not found: classes

Before Running the code the Classpath needs to be set which could be done either globally
by adding to the System classPath or locally at the application level

To Set globally the following should be run in Command Prompt

D:\java\ClassLoaders>set CLASSPATH=classes

After this, the Java code can be run as below

D:\java\ClassLoaders>java com.mugil.org.TestHelper
Helper Method

Setting Globally is not a good idea as other applications Classpath would be affected.If you
have set classpath globally chances are you may end up running wrong JAR file in the Classpath
The Better option is to set classpath while running the application itself

D:\java\ClassLoaders>java -cp classes com.mugil.org.TestHelper
Helper Method

Now let’s see how to take .class files in some other folder or .class files in JAR folder to

To run the .class file in other folders along with the one we are running adding the .class files separated by semicolon would be an easy way
as below

D:\java\ClassLoaders>java -cp D:\java\ClassLoaders\classes;D:\class1; com.mugil.org.TestHelper
Helper Method

The Helper.class is moved to D:\class1 folder and TestHelper.class is in D:\java\ClassLoaders\classes folder
TestHelper.class needs Helper.class to run.

Now how about JAR Files

D:\class1>jar cvf helper.jar com\mugil\org\Helper.class
added manifest
adding: com/mugil/org/Helper.class(in = 296) (out= 227)(deflated 23%)

To run the classes in the JAR Files the same command applies.D:\class1 is the location where the JAR’s are located(helper.jar).

D:\java\ClassLoaders>java -cp D:\java\ClassLoaders\classes;D:\class1; com.mugil.org.TestHelper
Helper Method

Once the JAR is created the .class files can be deleted and added to lib folder

While Creating JAR make sure you maintain the folder structure.Creating JAR file without adding com\mugil\org folder will result in classNotFound Exception

D:\java\ClassLoaders>java -cp D:\java\ClassLoaders\classes\lib\Helper.jar;D:\java\ClassLoaders\classes\; com.mugil.org.TestHelper

Class loaders are the part of the Java Runtime Environment that dynamically loads Java classes into the Java virtual machine. It is responsible for locating libraries, reading content and loading the classes contained within the libraries. When JVM is started three class loaders are used

How ClassLoaders works

  1. When JVM requests for a class, it invokes loadClass function of the ClassLoader by passing the fully classified name of the Class.
  2. loadClass function calls for findLoadedClass() method to check that the class has been already loaded or not. It’s required to avoid loading the class multiple times.
  3. If the Class is not already loaded then it will delegate the request to parent ClassLoader to load the class.
  4. If the parent ClassLoader is not finding the Class then it will invoke findClass() method to look for the classes in the file system.

1. Bootstrap class loader (Written in C)
2. Extensions class loader (Written in Java)
3. System or Application class loader (Written in Java)

Apart from CLASSPATH java looks into two other locations to load the JAR Folder
C:\Program Files\Java\jdk1.8.0_111\jre\lib in JRE installation Folder
C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext

Bootstrap class loader
It loads JDK internal classes, typically loads rt.jar and other core classes for example java.lang.* package classes

rt.jar is one of the JAR files in JRE Folder. You can see the content in rt.jar by renaming it into rt.jar.
rt.jar is loaded by the bootstrap class loader.

Extensions class loader
It loads classes from the JDK extensions directory, usually $JAVA_HOME/lib/ext directory.
You can add your JAR files like DB Connection JAR in the EXT folder and would be available to all application which runs on JVM

helper.jar added to ext folder

D:\java\ClassLoaders>java -cp D:\java\ClassLoaders\classes;D:\class1; com.mugil.org.TestHelper
Helper Method

D:\java\ClassLoaders>java -cp D:\java\ClassLoaders\classes; com.mugil.org.TestHelper
Helper Method

Note:In the second statement the D:\class1 is missing which has the JAR files which is now moved to EXT folder.No need to specify the JAR files as JAR files in EXT are loaded by default

System (or) Application class loader
System or Application class loader and it is responsible for loading application specific classes from CLASSPATH environment variable, -classpath or -cp command line option, Class-Path attribute of Manifest file inside JAR.

Delegation of Classes

  1. Delegation Classes are classes which delegates the call to its Parent Class which inturn Delegates to its Parent
  2. Each class loader has a parent. Class Loaders may delegate to its Parent. Parent may or may not load the class
  3. Loaded classes are always cached
  4. Application loader asks the Extension Class loader which inturn asks Bootstap loader
  5. If Bootstap loader couldnt find the class it will send fail message which makes the Extension Class loader to search for classes within
  6. If Extension loader couldnt find the class it will send fail message to Application Class Loader and makes to search for classes within
  7. If Application Class loader couldnt find the class NoClassDefinition Error would be Displayed

import java.net.URLClassLoader;

public class Delegation 
{
	public static void main(String[] args) 
	{
		URLClassLoader classloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
		
		do {
			System.out.println(classloader);
		} while ((classloader = (URLClassLoader)classloader.getParent()) != null);
		
		System.out.println("Bootstrap ClassLoader");
	}
}

Output

sun.misc.Launcher$AppClassLoader@1497b7b1
sun.misc.Launcher$ExtClassLoader@749cd006
Bootstrap ClassLoader

To See the location of the Class Files loaded you can use the below code

.
.
do {
			System.out.println(classloader);
			
			for(URL url : classloader.getURLs())		
			 System.out.println("\t %s"+ url.getPath());
			
		} while ((classloader = (URLClassLoader)classloader.getParent()) != null);
.
.

Output

sun.misc.Launcher$AppClassLoader@1497b7b1
	 %s/D:/java/ClassLoaders/bin/
sun.misc.Launcher$ExtClassLoader@749cd006
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/access-bridge-64.jar
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/dnsns.jar
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/jaccess.jar
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/localedata.jar
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/sunec.jar
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/sunjce_provider.jar
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/sunmscapi.jar
	 %s/C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/zipfs.jar
Bootstrap ClassLoader

In the above Output, you can see the Application Class Loaders loads the Java class from the Project Directory and EXT jars from the EXT C:/Program%20Files/Java/jdk1.7.0_45/jre/lib/ext/ Folder

Why we need Custom ClassLoader?
Whenever a class is referenced in a java program it is loaded using JVM’s bootstrap class loader. This often becomes a problem when two different classes with same name and same package declaration are to be loaded. For example relying on JVM’s class loader one cannot load two different versions of the same JDBC driver. The work around to this problem is lies in making a custom class loader and loading classes directly from JAR archives.

Other Reasons

  1. Better Memory Management Unused modules can be removed which unloads the classes used by that module, which cleans up memory.
  2. Load classes from anywhere Classes can be loaded from anywhere, for ex, Database, Networks, or even define it on the fly.
  3. Runtime Reloading Modified Classes Allows you to reload a class or classes runtime by creating a child class loader to the actual class loader, which contains the modified classes.Hot Deployment
  4. Provides Modular architecture Allows to define multiple class loader allowing modular architecture.
  5. Support Versioning Supports different versions of class within same VM for different modules. Multiple Version Support
  6. Avoiding conflicts Clearly defines the scope of the class to within the class loader.
  7. Class loading mechanism forms the basis of Inversion of Control

Simple URL Class Loader
In the below example we are using URL Class Loading method to load the Classes from the JAR file.We can load Classes from File Based URL or Network Based URL
We can also load class from DB

SimpleClassLoader.java

public class SimpleClassLoader {
	public static void main(String[] args) {
		URL url;
        try {
            url = new URL("file:///D:/jars/helper.jar");
            URLClassLoader ucl = new URLClassLoader(new URL[]{url});
            Class clazz = ucl.loadClass("com.mugil.org.Helper");
            Object o = clazz.newInstance();
            Helper objHelper = (Helper)o;
            System.out.println(o.toString());
    		System.out.println(objHelper.getMessage());            
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
	}
}

Output

Helper Method
com.mugil.org.Helper@4631c43f

Note: In the above example you can see the Typecasting from Object to Helper which again makes the code tightly coupled and defeats the purpose of the class loader dynamically loads Java classes into the Java Virtual Machine. To resolve this issue we can use Interface which is loaded by application class loader with the implementing class loaded by our own class loader.

Account.java

public interface Account {
	public Integer getInterestRate(); 
}

SavingsAccount.java

public class SavingsAccount implements Account {
	@Override
	public Integer getInterestRate() {
		return 10;
	}
}

Implementation classes added to our JAR so it can be loaded by our Class Loader

D:\java\ClassLoaders\bin> jar cvf Accounts.jar com\mugil\org\SavingsAccount.class
added manifest
adding: com/mugil/org/SavingsAccount.class(in = 496) (out= 301)(deflated 39%)

CalculateInterest.java

public class CalculateInterest {
	public static void main(String[] args) 
	{
		URL url;
        try {
            url = new URL("file:///D:/jars/Accounts.jar");
            URLClassLoader ucl = new URLClassLoader(new URL[]{url});
            Class clazz = ucl.loadClass("com.mugil.org.SavingsAccount");
            Account o = (Account)clazz.newInstance();            
            System.out.println(o.toString());
    		System.out.println(o.getInterestRate());            
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
	}
}	

In the above code I can change the logic interest is calculated in the SavingsAccount and redeploy the JAR without taking effect in other parts of the program.

The above jar file could be loaded accross network by giving URL as below

.
.
URL url = new URL("http://localhost:8080/Accounts.jar");
.
.

Multiple version Support of Same JAR

Java bytecode is universal across platforms, you can use it to instrument classes on any system: a measure which methods are called, suppress security-critical calls, divert System.out accesses to your own custom logging routines, or perform advanced dynamic bug-testing routines.

	public static void main(String[] args) {
		try { 
            URL url1 = new URL("file:///D:/jars/Accounts1.jar"); 
            URLClassLoader ucl1 = new URLClassLoader(new URL[]{url1}); 
            Class clazz1 = Class.forName("com.mugil.org.SavingsAccount", true, ucl1);
            Account quote1 = (Account) clazz1.newInstance();

            URL url3 = new URL("file:///D:/jars/Accounts.jar");
            URLClassLoader ucl3 = new URLClassLoader(new URL[]{url3});
            Class clazz2 = Class.forName("com.mugil.org.SavingsAccount", true, ucl3);
            Account quote2 = (Account) clazz2.newInstance();

            System.out.printf("clazz1 == clazz2? %b\n", clazz1 == clazz2);
            System.out.printf("quote1.class == quote2.class? %b\n", quote1.getClass() == quote2.getClass());

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
	}

Output

clazz1 == clazz2? false
quote1.class == quote2.class? false

Functional interfaces have a single functionality to exhibit. For example, a Comparable interface with a single method compareTo is used for comparison purpose
Functional Interface is an interface which has one and only one abstract method. Apart from abstract method, it can have any number of default and static methods which have an implementation and are not abstract and overridden method from Object.These interfaces are also called Single Abstract Method Interfaces. Few Functional Interfaces are Comparable, Runnable and etc.

Example of Functional Interface

@FunctionalInterface
public interface MyFunctionalInterface 
{
	public void MethodOne(int i, double d);
} 
@FunctionalInterface
public interface MyFunctionalInterface 
{
	public void MethodOne(int i, double d);
	
	default boolean methodTwo(String value) 
	{
        return true;
  }
} 

@FunctionalInterface annotation is used to mark an interface as Functional Interface
not mandatory to use it. If the interface is annotated with @FunctionalInterface annotation and when we
try to have more than one abstract method, it throws the compiler error.

There are two ways the abstract method definition in the functional interface could be done

One is by Anonymous Inner class and other is by Lambda Expression

For example in Java, if we have to instantiate runnable interface anonymously, then our code looks like below. It’s bulky

Anonymous Inner class way of method definion for Functional Interface

Runnable r = new Runnable(){
 @Override
 public void run() 
 {
	System.out.println("My Runnable");
 }};

lambda expressions for the above method implementation is

Lambda Expressions way of method definion for Functional Interface

Runnable r1 = () -> {
 System.out.println("My Runnable");
};

Functional interface with abstract method(oneMethod) and default(getMulty), static methods(getSum) which have an implementation and are not abstract and methods overridden from Object Class(toString and equals).

@FunctionalInterface
public interface MyFunctionalInterface 
{
	public void oneMethod(int i, double d);
	public String toString();
	public boolean equals(Object o);

	public static int getSum(int a,int b)
        {// valid->method static
		return a+b;
	}

	public default int getMulty(int c,int d)
        {//valid->method default
		return c+d;
        }
}

Functional Interface could be classified into the following 5 Types based on the parameters and the way the abstract method behaves

  1. Supplier
  2. Consumer
  3. Predicate
  4. Function
  5. Operator
Functional Interface Parameter Types Return Type Abstract Method Name Description
Runnable none void run Runs an action without arguments or return value
Supplier
none T get Supplies a value of type T
Consumer
T void accept Consumes a value of type T
BiConsumer
T, U void accept Consumes values of types T and U
Function
T R apply A function with argument of type T
BiFunction
T, U R apply A function with arguments of types T and U
UnaryOperator
T T apply A unary operator on the type T
BinaryOperator
T, T T apply A binary operator on the type T
Predicate
T boolean test A Boolean-valued function
BiPredicate
T, U boolean test A Boolean-valued function with two arguments

What is need for Default Method in Functional Interface?

  1. If we want to add additional methods in the interfaces, it will require change in all the implementing classes.
  2. As interface grows old, the number of classes implementing it might grow to an extent that its not possible to extend interfaces.
  3. That’s why when designing an application, most of the frameworks provide a base implementation class and then we extend it and override methods that are applicable for our application.
  4. “Default Method” or Virtual extension methods or Defender methods feature, which allows the developer to add new methods to the interfaces without breaking their existing implementation. It provides the flexibility to allow interface to define implementation which will use as the default in a situation where a concrete class fails to provide an implementation for that method.

Lets Imagine we have UserDevices which later wants to provide support for blackberry devices at later part of Software release. You cannot have a abstract method for blackberrySupport and make the implementing classes to do method definition.Instead of that I am writing as default method in interface which prevents all the implementing classes to write its own method definition.

public interface UserDevices {
    default void blackberrySupport(){
       System.out.println("Support for Blackberry Devices");
    }
}

public class Device implements UserDevices {
}

What if the class implements two interfaces and both those interfaces define a default method with the same signature?

public interface UserDevices1 {
    default void blackberrySupport(){
       System.out.println("Support for Blackberry Devices1");
    }
}

public interface UserDevices2 {
    default void blackberrySupport(){
       System.out.println("Support for Blackberry Devices2");
    }
}

public class Device implements UserDevices1 , UserDevices2 {
}

This code fails to compile with the following result:

java: class Device inherits unrelated defaults for blackberrySupport() from types UserDevices1 and UserDevices2 

In this case we have to resolve it manually by overriding the conflicting method

public class Device implements UserDevices1, UserDevices2  {
    public void blackberrySupport(){
       UserDevices1.super.blackberrySupport();
    }
}

The Best Example of Default Method is addition of foreach method in java.util.List Interface.

When Memory Leaks happen in Java

Objects inaccessible by running code but still stored in memory

Class allocates a large chunk of memory (e.g. new byte[1000000]), stores a strong reference to it in a static field, and then stores a reference to itself in a ThreadLocal. Allocating the extra memory is optional (leaking the Class instance is enough), but it will make the leak work that much faster.

Static field holding object reference

class MemorableClass 
{
    static final ArrayList list = new ArrayList(100);
}

Calling String.intern() on lengthy String

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you can't remove
str.intern();

Unclosed open streams ( file , network etc… )

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Unclosed connections

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

The thread clears all references to the custom class or the ClassLoader it was loaded from.

When the clone method is invoked upon an array, it returns a reference to a new array which contains (or references) the same elements as the source array.

So in your example, int[] a is a separate object instance created on the heap and int[] b is a separate object instance created on the heap. (Remember all arrays are objects).

    int[] a = {1,2,3};
    int[] b = a.clone();

    System.out.println(a == b ? "Same Instance":"Different Instance");
    //Outputs different instance

If were to modify int[] b the changes would not be reflected on int[] a since the two are separate object instances.

b[0] = 5;
    System.out.println(a[0]);
    System.out.println(b[0]);
    //Outputs: 1
    //         5

This becomes slightly more complicated when the source array contains objects. The clone method will return a reference to a new array, which references the same objects as the source array.

class Dog{

        private String name;

        public Dog(String name) {
            super();
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

    }

Lets create and populate an array of type Dog

Dog[] myDogs = new Dog[4];

    myDogs[0] = new Dog("Wolf");
    myDogs[1] = new Dog("Pepper");
    myDogs[2] = new Dog("Bullet");
    myDogs[3] = new Dog("Sadie");

Clone dog

    Dog[] myDogsClone = myDogs.clone();


System.out.println(myDogs[0] == myDogsClone[0] ? "Same":"Different");
    System.out.println(myDogs[1] == myDogsClone[1] ? "Same":"Different");
    System.out.println(myDogs[2] == myDogsClone[2] ? "Same":"Different");
    System.out.println(myDogs[3] == myDogsClone[3] ? "Same":"Different");

This means if we modify an object accessed through the cloned array, the changes will be reflected when we access the same object in the source array, since they point to the same reference.

myDogsClone[0].setName("Ruff"); 
    System.out.println(myDogs[0].getName());
    //Outputs Ruff

changes to the array itself will only affect that array.

myDogsClone[1] = new Dog("Spot");
    System.out.println(myDogsClone[1].getName());
    System.out.println(myDogs[1].getName());
    //Outputs Spot
    //Pepper

As you see above the change in the child by assigning a new Dog does not have any impact on the parent because the reference itself is changed instead of change in the reference value.

Object cloning refers to creation of shallow copy of an object.

Why we Need Clone?

// Java program to demonstrate that assignment
// operator only creates a new reference to same
// object.
import java.io.*;
 
// A test class whose objects are cloned
class Test
{
    int x, y;
    Test()
    {
        x = 10;
        y = 20;
    }
}
 
// Driver Class
class Main
{
    public static void main(String[] args)
    {
         Test ob1 = new Test();
 
         System.out.println(ob1.x + " " + ob1.y);
 
         // Creating a new reference variable ob2
         // pointing to same address as ob1
         Test ob2 = ob1;
 
         // Any change made in ob2 will be reflected
         // in ob1
         ob2.x = 100;
 
         System.out.println(ob1.x+" "+ob1.y);
         System.out.println(ob2.x+" "+ob2.y);
    }
}

output

10 20
100 20
100 20

In Java, we can create only copy of reference variable and not the object.

How to Use Clone?

  1. class that implements clone() should call super.clone() to obtain the cloned object reference
  2. the class must also implement java.lang.Cloneable interface whose object clone we want to create otherwise it will throw CloneNotSupportedException when clone method is called on that class’s object.
  3.   protected Object clone() throws CloneNotSupportedException
    
// A Java program to demonstrate shallow copy
// using clone()
import java.util.ArrayList;
 
// An object reference of this class is
// contained by Test2
class Test
{
    int x, y;
}
 
// Contains a reference of Test and implements
// clone with shallow copy.
class Test2 implements Cloneable
{
    int a;
    int b;
    Test c = new Test();
    public Object clone() throws
                   CloneNotSupportedException
    {
        return super.clone();
    }
}
 
// Driver class
public class Main
{
    public static void main(String args[]) throws
                          CloneNotSupportedException
    {
       Test2 t1 = new Test2();
       t1.a = 10;
       t1.b = 20;
       t1.c.x = 30;
       t1.c.y = 40;
 
       Test2 t2 = (Test2)t1.clone();
 
       // Creating a copy of object t1 and passing
       //  it to t2
       t2.a = 100;
 
       // Change in primitive type of t2 will not
       // be reflected in t1 field
       t2.c.x = 300;
 
       // Change in object type field will be
       // reflected in both t2 and t1(shallow copy)
       System.out.println(t1.a + " " + t1.b + " " +
                          t1.c.x + " " + t1.c.y);
       System.out.println(t2.a + " " + t2.b + " " +
                          t2.c.x + " " + t2.c.y);
    }
}

output

10 20 300 40
100 20 300 40

How to Achieve Deep Copy

// A Java program to demonstrate deep copy
// using clone()
import java.util.ArrayList;
 
// An object reference of this class is
// contained by Test2
class Test
{
    int x, y;
}
 
 
// Contains a reference of Test and implements
// clone with deep copy.
class Test2 implements Cloneable
{
    int a, b;
 
    Test c = new Test();
 
    public Object clone() throws
                CloneNotSupportedException
    {
        // Assign the shallow copy to new refernce variable t
        Test2 t = (Test2)super.clone();
 
        t.c = new Test();
 
        // Create a new object for the field c
        // and assign it to shallow copy obtained,
        // to make it a deep copy
        return t;
    }
}
 
public class Main
{
    public static void main(String args[]) throws
                             CloneNotSupportedException
    {
       Test2 t1 = new Test2();
       t1.a = 10;
       t1.b = 20;
       t1.c.x = 30;
       t1.c.y = 40;
 
       Test2 t3 = (Test2)t1.clone();
       t3.a = 100;
 
       // Change in primitive type of t2 will not
       // be reflected in t1 field
       t3.c.x = 300;
 
       // Change in object type field of t2 will not
       // be reflected in t1(deep copy)
       System.out.println(t1.a + " " + t1.b + " " +
                          t1.c.x + " " + t1.c.y);
       System.out.println(t3.a + " " + t3.b + " " +
                          t3.c.x + " " + t3.c.y);
    }
}

output

10 20 30 40
100 20 300 0

When to use Clone?

  1. We should use clone to copy arrays because that’s generally the fastest way to do it.

Disadvantages of Clone Method

  1. Cloneable interface lacks the clone() method. Actually, Cloneable is a marker interface and doesn’t have any methods in it, and we still need to implement it just to tell the JVM that we can perform clone() on our object.
  2. Object.clone() is protected, so we have to provide our own clone() and indirectly call Object.clone() from it.
  3. If we are writing a clone method in a child class, e.g. Person, then all of its superclasses should define the clone() method in them or inherit it from another parent class. Otherwise, the super.clone() chain will fail.
  4. We can not manipulate final fields in Object.clone() because final fields can only be changed through constructors. In our case, if we want every Person object to be unique by id, we will get the duplicate object if we use Object.clone() because Object.clone() will not call the constructor, and final id field can’t be modified from Person.clone().

There are two effective ways to create copy of object

  1. Copy Constructor – Refer here
  2. Serialization- Refer Here

Even copy constructor has its disadvantage since working with the internal object(Child Objects) may make it inconsistent and fragile