Collections

  • The java collections Framework is a set of classes and interface.
  • These classes and interface implement the collection data structures.
  • For Example : list, stack, queue or maps.
  • The collection framework was designed and developed primarily by Joshua Bloch
  • It was introduced in JDK 1.2
  • Why to use these collections?
    • We don’t have to implement every algorithm and data structure from the scratch, its already written into java.
    • It is already been tested.
  • Almost all Collections are derived from the java.utils.Collection interface
  • toArray() method can transform any collection into one dimensional array.
  • The Collection interface extends the java.lang.Iterable interface, this is why we can use for-each loop.

We write for each loop like below example :

for(String fruits : listOfFruits){
   System.out.println(fruits);
}

After compilation of .java file, .class file contains below code :

for (Iterator<String> i = listOfFruits.iterator(); i.hasNext();) {
   String fruits = i.next();
   System.out.println(fruits);
}

Enum

If we want to represent a Group Named Constants then we should go for enum

Example of Enum

enum Month{
JAN,FEB,MAR;
}
  • Semicolon (;) is optional
  • enum concept was introduced in 1.5 Version
  • The main objective of enum is to Define our own Data Types(Enumerated Data Types)
  • When compared with other languages enum, java enum is more powerful

Internally Implementation of enum :

  • Every enum Internally implemented by using Class Concept.
  • Every enum Constant is Always public static final.
  • Every enum Constant Represents an Object of the Type enum.

Example of enum :

enum Month{
JAN,FEB,MAR;
}

Internal Implementation of enum

class Month{
public static final Month JAN = new Month();
public static final Month FEB = new Month();
public static final Month MAR = new Month();
}

A Tree structure using enum

package com.enumTest;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

public class Demo {
	enum Month{
		JAN(1,"january",Climate.WINTER),FEB(2,"Februrary",Climate.WINTER),MAR(3,"March",Climate.SUMMER),APR(4,"April",Climate.SUMMER),
		MAY(5,"May",Climate.SUMMER),JUN(6,"June",Climate.RAINY),JUL(7,"July",Climate.RAINY),AUG(8,"August",Climate.RAINY),SEP(9,"September",Climate.RAINY),
		OCT(10,"October",Climate.WINTER),NOV(11,"November",Climate.WINTER),DEC(12,"December",Climate.WINTER);
		int width;
		String name;
		Climate climate;
		Month(int width,String name, Climate climate ){
			this.width=width;
			this.name=name;
			this.climate=climate;
		}
		public int getWidth() {
			return width;
		}
		public void setWidth(int width) {
			this.width = width;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public Climate getClimate() {
			return climate;
		}
		enum Climate{
			SUMMER,WINTER,RAINY;
			int totalWidth;
			public int getTotalWidth() {
				return totalWidth;
			}
			enum Decade{
				Decade;
			}
		}
	} 
	public static void main(String[] args) {
		int grandTotal;
		List<Month> temp =  new ArrayList<>();
		temp.add(Month.JAN);
		temp.add(Month.FEB);
		temp.add(Month.MAR);
		temp.add(Month.APR);
		temp.forEach(month -> month.climate.totalWidth=month.climate.totalWidth+month.width);
		EnumSet.allOf(Month.Climate.class).forEach(climate -> System.out.println(climate.totalWidth));
		grandTotal = temp.stream().mapToInt(Month::getWidth).sum();
		
		
	}
}

Type Erasure

  • In order to implement generics, java uses type erasure.
  • Replace all type parameters in generic types with their bounds or objects.
  • If the type parameters are unbounded then the final bytecode will contain plain java objects/classes.
  • Uses type casts if necessary.
  • Sometimes java generates extra methods so called bridge methods in order to maintain polymorphism with generics type.

Example of Code conversion :

List<Integer> list = new ArrayList<>();
list.add(3);
Integer num = list.get(0);

Above code is converted into bytecode i.e class file which looks like below :

List list = new ArrayList();
list.add(3);
Integer num = (Integer) list.get(0);

Now lets see how type T is converted in below code:

public class Demo<T> {
	private T item;

	public T getItem() {
		return item;
	}

	public void setItem(T item) {
		this.item = item;
	}
}

Above code is converted into

public class Demo {
	private Object item;

	public Object getItem() {
		return item;
	}

	public void setItem(Object item) {
		this.item = item;
	}
}

Increase Performance of Eclipse

  1. Window Menu -> Preference -> Validation ->Disable All
    You can also search Validation in preference and disable the things you don’t need
  2. Window Menu -> Preference -> General -> StartUp and Shutdown (Uncheck all plugins activated at startup)
  3. Window Menu -> Preference -> General -> Appearances -> Classic
  4. General -> Editors -> Text Editors -> Spelling -> Disable spell checking
  5. Window > Customize Perspective > Remove the tool bars and menus that you don’t use or want
  6. To open xml files and other files faster(change to xml editor)
    Windows -> Preferences -> General->Editor -> File associations
  7. Windows -> Preference -> General (Check show Heap status checkbox)

Add below lines in eclipse.ini file

  • -Xverify:none
     It will cut down your eclipse startup time considerably. This will tell the JVM not to validate all the .class files it is loading. This means JVM won’t be able to detect the authenticity of the class files you are using. This poses a security threat if the byte code have been altered.
  • To increase permanent generation space (where new objects are allocated) add,-XX:PermSize=512m
    -XX:MaxPermSize=512m
  • To increase minimum and maximum heap size (which includes young and tenured generations) add,
    -Xmx2048m
    -Xms1024m
    Note: You should always allocate size less than your original RAM size.
  • Use XX:+UseParallelGC
    This indicates which garbage collector strategy to use. This strategy minimizes the garbage collection pause, meaning the time spent garbage collecting is reduced as much as possible. Read more (http://www.javaperformancetuning.com/news/qotm026.shtml).
  • -Xquickstart
    You can use -Xquickstart for initial compilation at a lower optimization level than in default mode. Later, depending on sampling results, you can recompile to the level of the initial compile in default mode. Use -Xquickstart for applications where early moderate speed is more important than long run throughput. In some debug scenarios, test harnesses and short-running tools, you can improve startup time between 15-20%.

Unbounded Wildcard

  • The question mark (?), represents the wildcard, stands for unknown type in generics.
  • There may be times when any object can be used when a method can be implemented using functionality provided in the Object class or When the code is independent of the type parameter.
  • To declare a Unbounded Wildcard parameter, list the ? only.

Example

package com.test.unbounded;

import java.util.Arrays;
import java.util.List;

public class UnboundedDemo {
	public static void printList(List<?> list) {
		System.out.println();
	      for (Object item : list)
	         System.out.print(item + " --> ");
	   }

	   public static void main(String args[]) {
	      printList(Arrays.asList(1, 2, 3));
	      printList(Arrays.asList(1.2, 2.3, 3.5));
	      printList(Arrays.asList("Tyson","Justin","Martin"));
	   }
}

Upper Bounded WildCards

  • The question mark (?), represents the wildcard, stands for unknown type in generics.
  • There may be times when you’ll want to restrict the kinds of types that are allowed to be passed to a type parameter.
  • For example, a method that operates on numbers might only want to accept instances of Number or its subclasses.
  • To declare a upper bounded Wildcard parameter, list the ?, followed by the extends keyword, followed by its upper bound.
  • If we want to read values from a collection then it is better to use extends
package com.test.unbounded;

import java.util.Arrays;
import java.util.List;

public class UpperBoundDemo {
	public static double sum(List<? extends Number> numberlist) {
		double sum = 0.0;
		for (Number n : numberlist)
			sum += n.doubleValue();
		return sum;
	}

	public static void main(String args[]) {
		System.out.println("sum = " + sum(Arrays.asList(1, 2, 3)));
		System.out.println("sum = " + sum(Arrays.asList(1.2, 2.3, 3.5)));
		//Below will throw a compile time error
		//System.out.println("sum = " + sum(Arrays.asList("Tyson","justin","Martin")));
	}
}

Lower Bound WildCards

  • The question mark (?), represents the wildcard, stands for unknown type in generics.
  • There may be times when you’ll want to restrict the kinds of types that are allowed to be passed to a type parameter.
  • For example, a method that operates on numbers might only want to accept instances of Integer or its superclasses like Number.
  • To declare a lower bounded Wildcard parameter, list the ?, followed by the super keyword, followed by its lower bound.
  • If we want to add values to the collection it is better if we use super

Example :

package com.test.unbounded;

import java.util.ArrayList;
import java.util.List;

public class LowerBoundDemo {
	 public static void addCat(List<? super Cat> catList) {
	      catList.add(new RedCat());
	      System.out.println("Cat Added");
	   }

	   public static void main(String[] args) {
	      List<Animal> animalList= new ArrayList<Animal>();
	      List<Cat> catList= new ArrayList<Cat>();
	      List<RedCat> redCatList= new ArrayList<RedCat>();
	      List<Dog> dogList= new ArrayList<Dog>();

	      //add list of super class Animal of Cat class
	      addCat(animalList);

	      //add list of Cat class
	      addCat(catList);

	      //compile time error
	      //can not add list of subclass RedCat of Cat class
	      //addCat(redCatList);

	      //compile time error
	      //can not add list of subclass Dog of Superclass Animal of Cat class
	      //addCat.addMethod(dogList); 
	   }
}
class Animal {}

class Cat extends Animal {}

class RedCat extends Cat {}

class Dog extends Animal {}

Note : Producer and Consumer problem can be implemented using the upper and lower bound wild cards.Extends

Type Inference and Type Witness

What is Type Inference in java?

Type inference is a Java compiler’s ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable.

List<String> list1 = new ArrayList<>();

In the above example, ArrayList<> the diamond operator is empty but during compilation java automatically determines the Type as String using Type inference.Note this functionality is only available after java 1.7

What is Type Witness in java?

You can stop compiler from automatically inference and ask the compiler to take a specific type while calling a method, that is called type inference

ClassName.<Type>.methodCall(type_reference);
package com.test;

import java.util.ArrayList;
import java.util.List;

public class App {
	public static <T> void addToList(T t,List<Bucket<T>> list){
		Bucket<T> bucket = new Bucket<>();
		bucket.setItem(t);
		list.add(bucket);
		System.out.println(t.toString()+" has been added to the list");
	}
	public static void main(String[] args) {
		//Type Inference
		//on Right Side ArrayList has empty diamond operator, it is automatically inference
		List<Bucket<Integer>> list = new ArrayList<>();
		//Type Witness
		//Ask Compiler to consider the T as passed in the diamond operator
		App.<Integer>addToList(10,list);
	}
}
class Bucket<T>{
	private T item;

	public T getItem() {
		return item;
	}

	public void setItem(T item) {
		this.item = item;
	}
}

Bounded Type Parameter

  • There are many cases in which the developer does not want certain input type as a parameter, hence developer can restrict the types by using Bounded Type Parameter.
  • When you declare the Type in class or a method declaration using <T> diamond operator you can extend an Interface here <T extends Number> so tell the Type that you are expecting only those type(classes) which implements the Number interface.

Example1 : Bounded Type Method

public class BoundedTypeDemo1 {
	public static <T extends Comparable<T>> T findMin(T t1, T t2) {
		if(t1.compareTo(t2) > 0) {
			return t2;
		}else {
			return t1;
		}
	}
	public static void main(String[] args) {
		System.out.println(findMin(10,20));
		System.out.println(findMin("Hello","World"));
		System.out.println(findMin(44.3,22.4));
	}
}

Example2 : Bounded Type Class

package com.test;

public class BoundedTypeDemo2 {
	public static void main(String[] args) {
		new CalcNumber<Integer>(10,20).printSum();
		new CalcNumber<Double>(10d,20d).printSum();
	}
}

class CalcNumber<T extends Number> {
	T input1;
	T input2;

	CalcNumber(T input1, T input2) {
		this.input1 = input1;
		this.input2 = input2;
	}

	public void printSum() {
		if (input1.getClass().equals(Double.class)) {
			System.out.println(input1.doubleValue() + input2.doubleValue());
		}else if (input1.getClass().equals(Integer.class)) {
			System.out.println(input1.intValue() + input2.intValue());
		}
	}
}

Note : A Type can extend a class as well as an Interface, in Example1 Type extends an interface but in Example2 Type extends a class

Multiple Bounds

A Type parameter can have multiple Bounds

Syntax :

public static <T extends Class &amp; Interface<T>> return_type method_name(T x, T y, T z)

Example :

public static <T extends Number &amp; Comparable<T>> T maximum(T x, T y, T z)

maximum – Is the name of the generic method
T – is a generic parameter

  • The T type should be a class that extends class Number and implement Comparable interface
  • In case a class is passed as bound, it should be passed first before interface otherwise compile time error will occur.

Generic Method

  • If you are going to use generic in a method then you need to specify all the generics used in that method inside a diamond operator, this diamond operator will come right after the access modifier of the method.
  • You need to mention the type used inside the method after the class name.

Example :

class GenericMethodDemo{
	public <T1,T2> String genericToString(T1 t1, T2 t2){
		return t1.toString()+" -- "+t2.toString();
	}
}
  • By using generic method the reuse-ability of the method increases
  • Method becomes type safe, instead of using Object datatype and casting to our need at runtime can runtime exceptions, instead by using generic we know before hand what datatype is going to be referred in future.
  • And thus overhead of casting the object is also removed.
  • Array of Generic type can also be created using Generic, example below

public class GenericArray {
	public static <T> void printArray(T[] array) {
		System.out.println();
		for(T input : array) {
			System.out.print(input+" --> ");
		}
	}
	public static void main(String[] args) {
		Integer[] arr1 = new Integer[]{10,20,30};
		String[] arr2 = new String[]{"Tyson","Justin","Martin"};
		printArray(arr1);
		printArray(arr2);
	}
}

Data Structure

What is a Data Structure?

  • Data Structure can be defined as the group of data elements which provides an efficient way of storing and organising data in the computer so that it can be used efficiently. 
  • Data Structures are the main part of many computer science algorithms as they enable the programmers to handle the data in an efficient way. 
  • It plays a vitle role in enhancing the performance of a software or a program as the main function of the software is to store and retrieve the user’s data as fast as possible

Why to use data structure?

  • Searching of data for a large data set can cause huge amount of time to find result but using the correct data structure will help to get result in least amount of time.
  • Storing large amount of data a huge processing speed is required, using the proper data structure will help reduce it.
  • Handling a large amount of request will be difficult, but by using proper data structure you can tackle it efficiently.

What all operations can be performed on a data structure?

  • Traversal
  • Insertion
  • Deletion
  • Searching
  • Sorting
  • Merging
DS Introduction