Java is a high-level programming language originally developed by Sun Microsystems and released in 1995.
Java runs on a variety of platforms, such as Windows, Mac OS, and the various versions of UNIX.
Java runs on a variety of platforms, such as Windows, Mac OS, and the various versions of UNIX/Linux like HP-Unix, Sun Solaris, Redhat Linux, Ubuntu, CentOS, etc.
In the past, most programs written in any language have had to be recompiled, and sometimes, rewritten for each computer platform. One of the biggest advantages of Java is that you only have to write and compile a program once. The Java on any platform will interpret the compiled bytecode into instructions understandable by the particular processor. However, the virtual machine handles one bytecode instruction at a time. Using the Java just-in-time compiler (really a second compiler) at the particular system platform compiles the bytecode into the particular system code (as though the program had been compiled initially on that platform). Once the code has been (re-)compiled by the JIT compiler, it will usually run more quickly in the computer.
The just-in-time compiler comes with the virtual machine and is used optionally. It compiles the bytecode into platform-specific executable code that is immediately executed. Sun Microsystems suggests that it's usually faster to select the JIT compiler option, especially if the method executable is repeatedly reused.
Object Oriented,
Platform Independent,
Robust,
Interpreted,
Multi-threaded
It’s compiler generates an architecture-neutral object file format, which makes the compiled code to be executable on many processors, with the presence of Java runtime system.
Java uses Just-In-Time compiler to enable high performance. Just-In-Time compiler is a program that turns Java bytecode, which is a program that contains instructions that must be interpreted into instructions that can be sent directly to the processor.
After you've written a Java program, the source language statements are compiled by the Java compiler into bytecode rather than into code that contains instructions that match a particular hardware platform's processor (for example, an Intel Pentium microprocessor or an IBM System/390 processor). The bytecode is platform-independent code that can be sent to any platform and run on that platform.
It is designed to adapt to an evolving environment. Java programs can carry extensive amount of run-time information that can be used to verify and resolve accesses to objects on run-time.
When Java is compiled, it is not compiled into platform specific machine, rather into platform independent byte code. This byte code is distributed over the web and interpreted by virtual Machine (JVM) on whichever platform it is being run.
Netbeans, Eclipse, Java Spring, IntelliJ
import, super, finally
Object is a runtime entity and it’s state is stored in fields and behavior is shown via methods. Methods operate on an object's internal state and serve as the primary mechanism for object-to-object communication.
POJO je običan Java objekat koji nije ograničen nekim specijalnim resktrikcijama.
JavaBean je POJO koji može da se serijalizuje, ima konstruktor bez argumenata i dozvoljava pristup atributima preko „Get“ i „Set“ metoda koje prate konvenciju jednostavnih naziva.
Normalna Java klasa je standardna klasa koju poznajemo.
JavaBean klasa sadrži neka ograničenja: da su svi atributi privatni - koriste se „Set“ i „Get“ metode kako bi se zaštitio neovlašćen pristup pormenljivama unutar klase, koristi se javni konstruktor bez argumenata, implementira se serializacija.
POJO klase ne sadrže nikakva dodatna ograničenja osim onih koje propisuje Java specifikacija jezika, tako da POJO ne bi trebalo da ima “Extend” prespecificiranih klasa, “Implement” prespecificiranijeh interfejsa i “Contain” prespecificiranih anotacija. Obično se koristi za klase koje nisu podklase nijedne druge, ne implementiraju ni jedan interfejs i ne prate specifične obrasce.
A class is a blueprint from which individual objects are created. A class can contain fields and methods to describe the behavior of an object.
A class consist of Local variable, instance variables and class variables.
Variables defined inside methods, constructors or blocks are called local variables. The variable will be declared and initialized within the method and it will be destroyed when the method has completed.
Instance variables are variables within a class but outside any method. These variables are instantiated when the class is loaded.
These are variables declared with in a class, outside any method, with the static keyword.
Singleton class control object creation, limiting the number to one but allowing the flexibility to create more objects if the situation changes.
Constructor gets invoked when a new object is created. Every class has a constructor. If we do not explicitly write a constructor for a class the java compiler builds a default constructor for that class.
An Object is first declared, then instantiated and then it is initialized.
The integral types are:
Byte - 8-bit
Short - 16-bit
Int - 32-bit
Long - 64-bit
Char – 2 bytes
String – 4 bytes
The values of the integral types are integers in the following ranges:
For byte, from -128 to 127, inclusive
For short, from -32768 to 32767, inclusive
For int, from -2147483648 to 2147483647, inclusive
For long, from -9223372036854775808 to 9223372036854775807, inclusive
For char, from '\u0000' to '\uffff' inclusive, that is, from 0 to 65535
Class variables also known as static variables are declared with the static keyword in a class, but outside a method, constructor or a block.
Java provides access modifiers to set access levels for classes, variables, methods and constructors.
A member has package or default accessibility when no accessibility modifier is specified.
Variables, methods and constructors which are declared protected in a superclass can be accessed only by the subclasses in other package or any class within the package of the protected members' class.
Java provides these modifiers for providing functionalities other than Access Modifiers, synchronized used to indicate that a method can be accessed by only one thread at a time.
Variables used in a switch statement can only be a string, enum, byte, short, int, or char.
This method is used to get the primitive data type of a certain String.
List in Java provides ordered and indexed collection which may contain duplicates.
ArrayList and LinkedList are two most popular used List implementation.
One key difference between List and Set is that List is an ordered collection, List's contract maintains insertion order or element.
So if you insert Object A before Object B then A will be stored at lower index than B.
List allows null elements and you can have many null objects in a List, because it also allowed duplicates.
Most popular implementations of List interface in Java are ArrayList, LinkedList and Vector class.
ArrayList is more general purpose and provides random access with index.
Complexity of functions
get(index) - O(1)
add(element) - O(n)
size - O(1)
isEmpty - O(1)
set, iterator, and listIterator - O(1)
The size, isEmpty, get, set, iterator, and listIterator operations run in constant time. The add operation runs in amortized constant time, that is, adding n elements requires O(n) time.All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation.
Accessing a particular index in an array is a constant time operation, because it involves getting the base memory address from the array object, and accessing the memory at base address + index multiplied by size of element type. Since all of the elements in between are skipped, the access time is bound by a constant.
LinkedList is more suitable for frequently adding and removing elements from List.
Binary tree is used instead of linked list to lift the worst case performance from O(n) to O(logN)
Complexity of functions
get(index) - O(n)
add(element) -
size - O(1)
isEmpty -
set, iterator, and listIterator -
In Java LinkedList, get(int) operation is O(N), and size() operation is O(1) complexity.
A Linked List would however have an O(n) get: it would have to step to the next element until the desired index is reached...
Vector
Vector is synchronized counterpart of ArrayList.
Vector vs. Array List
Common property of Vector and ArrayList in Java
1) Bother Vector and ArrayList are derived from AbstractList and implements List interface, which means both of them are ordered collection and allows duplicates.
2) Another similarity between Vector vs ArrayList is that both are index based Collection and you can use get(index) method to retrieve objects from Vector and ArrayList.
1) First and most common difference between Vector vs ArrayList is that Vector is synchronized and thread-safe while ArrayList is neither Synchronized nor thread-safe.
Now, What does that mean? It means if multiple thread try to access Vector same time they can do that without compromising Vector's internal state. Same is not true in case of ArrayList as methods like add(), remove() or get() is not synchronized.
2) Second major difference on Vector vs ArrayList is Speed, which is directly related to previous difference. Since Vector is synchronized, its slow and ArrayList is not synchronized its faster than Vector.
In Summary
Use ArrayList if you are using ArrayList in Single threaded environment and use Vector if you need a thread-safe collection.
ArrayList is anytime faster than Vector in case thread-safety is not a concern.
Set provides an un-ordered collection of unique objects, i.e. Set doesn't allow duplicates.
LinkedHashSet, TreeSet and HashSet are frequently used Set implementation.
Set is an unordered collection, you get no guarantee on which order element will be stored. Though some of the Set implementation e.g. LinkedHashSet maintains order. Also SortedSet and SortedMap e.g. TreeSet and TreeMap maintains a sorting order, imposed by using Comparator or Comparable.
Main difference between List and Set interface in Java is that List allows duplicates while Set doesn't allow duplicates. Duplication of Object is detected using equals() method.
So if two objects are equal using equals method, the later object will replace the former in Set if added using add() method, due to this reason only one null element is allowed inside Set.
Set is an UN-ordered collection it doesn't maintain any inserting order of element
Set just allow one null element as there is no duplicate permitted while in Map you can have null values and at most one null key.
Hashtable doesn't allow null key or values but HashMap allows null values and one null keys. This is also the main difference between these two popular implementation of Map interface, aka HashMap vs Hashtable.
Most popular implementations of Set interface are HashSet, LinkedHashSet and TreeSet.
SortedSet implementation of Set interface
you can have SortedSet which offers to sort functionality on top of Set interface and you can impose either natural order or Object or any custom order by using Comparator and Comparable while storing object inside Set.
It's also worth noting that in the case of SortedSet like TreeSet, compareTo method is used to compare object and decide whether an object is duplicate or not, two objects will be duplicate if their compareTo() method returns zero and that's why it's said that compareTo should be consistent with equals method in java.
HashSet implementation of Set interface
HashSet - general purpose Set which is backed by HashMap
It also doesn't provide any ordering guarantee.
HashSet is internally implemented using HashMap in Java
only way to get object from HashSet is via Iterator
Using HashSet in Java is very simple, don't think it is Map but think more like Collection i.e. add elements by using add() method, check its return value to see if object already existed in HashSet or not. Similarly use iterator for retrieving element from HashSet in Java. You can also use contains() method to check if any object already exists in HashSet or not. This method use equals() method for comparing object for matching. You can also use remove() method to remove object from HashSet. Since element of HashSet is used as key in backup HashMap, they must implement equals() and hashCode() method. Immutability is not requirement but if its immutable then you can assume that object will not be changed during its stay on set.
LinkedHashSet implementation of Set interface
LinkedHashSet does provides ordering along with uniqueness offered by Set interface.
TreeSet implementation of Set interface
TreeSet is also an implementation of SortedSet interface, hence it keep elements in a sorted order specified by compare() or compareTo() method.
List vs. Set
1) List maintains insertion order of elements while Set doesn't maintain any ordering.
2) The list allows duplicate objects while Set doesn't allow any duplicates.
ArrayList uses an array as data structure while HashSet uses hashing mechanism.
Map in Java
Map provides a data structure based on key value pair and hashing. All three List, Set and Map are interfaces in Java and there are many concrete implementation of them are available in Collection API.
Map holds two object per Entry e.g. key and value and It may contain duplicate values but keys are always unique.
most popular implementation of Map interface are HashMap, LinkedHashMap, Hashtable and TreeMap.
HashMap
Non synchronized general purpose Map implementation.
The HashMap class uses a hashtable to implement the Map interface. This allows the execution time of basic operations, such as get( ) and put( ), to remain constant even for large sets.
1) Two unequal objects may return the same hashcode.
2) When two objects are equal by equals(), they must have the same hashcode.
Here are steps, which happens, when you call get() method with key object to retrieve corresponding value from hash based collection
a) Key.hashCode() method is used to find the bucket location in backing array. (Remember HashMap is backed by array in Java) Though hashcode() is not used directly, but they are passed to internal hash() function.
b) In backing array or better known as the bucket, key and values are stored in the form of a nested class called Entry. If there is only one Entry at bucket location, then the value from that entry is returne
If multiple keys have the same hashCode, then during put() operation collision had occurred, which means multiple Entry objects stored in a bucket location. Each Entry keeps track of another Entry, forming a linked list data structure there.
if we need to retrieve value object in this situation, following steps will be followed :
1) Call hashCode() method of the key to finding bucket location.
2) Traverse thought linked list, comparing keys in each entries using keys.equals() until it returns true.
To je Spoljasnje ulancavanje sa lancanim listama jer se koristi dodatni proctor sa strane, unutrasnje je kada trazi prvo slobodno mesto tj. bucket I tu ga stavlja, tamo da ne koristi proctor sa strane samo unutra.
So, we use equals() method of a key object to find correct entry and then return value from that. Remember key.equals() method, and this is what Interviewer want to know. I have seen many programmers mentioning value.equals(), which may be due to interview nervousness, but that’s incorrect. Since you don't have value object passed to get() method, there is no question of calling equals and hashCode method on value object.
Remember to mention about key.hashCode() and key.equals(), whenever someone asks how to get method of HashMap or Hashtable works in Java. A value object is not used, it just exists in Entry so that get can return it.
LinkedHashMap
Provide ordering guarantee
Hashtable
Hashtable is its synchronized counterpart.
Though both Hashtable and HashMap are data-structure based upon hashing and implementation of Map interface, the main difference between them is that HashMap is not thread-safe but Hashtable is thread-safe. Which means you cannot use HashMap in multi-threaded Java application without external synchronization. Another difference is HashMap allows one null key and null values but Hashtable doesn't allow null key or values. Also, thread-safety of the hash table is achieved using internal synchronization, which makes it slower than HashMap
HashMap vs. HashTable
1.The HashMap class is roughly equivalent to Hashtable, except that it is non-synchronized and permits nulls. (HashMap allows null values as key and value whereas Hashtable doesn't allow nulls).
2. One of the major differences between HashMap and Hashtable is that HashMap is non-synchronized whereas Hashtable is synchronized, which means Hashtable is thread-safe and can be shared between multiple threads but HashMap can not be shared between multiple threads without proper synchronization. Java 5 introduces ConcurrentHashMap which is an alternative of Hashtable and provides better scalability than Hashtable in Java.
3. Another significant difference between HashMap vs Hashtable is that Iterator in the HashMap is a fail-fast iterator while the enumerator for the Hashtable is not and throw ConcurrentModificationException if any other Thread modifies the map structurally by adding or removing any element except Iterator's own remove() method.
4. One more notable difference between Hashtable and HashMap is that because of thread-safety and synchronization Hashtable is much slower than HashMap if used in Single threaded environment. So if you don't need synchronization and HashMap are only used by one thread, it outperforms Hashtable in Java.
5. HashMap does not guarantee that the order of the map will remain constant over time.
HashMap and Hashtable : note on Some Important Terms
1)Synchronized means only one Thread can modify a hash table at one point of time. Basically, it means that any thread before performing an update on a Hashtable will have to acquire a lock on the object while others will wait for the lock to be released.
2) Fail-safe is relevant from the context of iterators. If an Iterator or ListIterator has been created on a collection object and some other thread tries to modify the collection object "structurally", a concurrent modification exception will be thrown. It is possible for other threads though to invoke "set" method since it doesn't modify the collection "structurally". However, if prior to calling "set", the collection has been modified structurally, "IllegalArgumentException" will be thrown.
Difference between HashMap and Hashtable in Java
3) Structurally modification means deleting or inserting element which could effectively change the structure of the map.
HashMap can be synchronized by
Map m = Collections.synchronizeMap(hashMap);
In Summary, there are significant differences between Hashtable and HashMap in Java e.g. thread-safety and speed and based upon that only use Hashtable if you absolutely need thread-safety if you are running Java 5 consider using ConcurrentHashMap in Java.
TreeMap
TreeMap
TreeMap is also a sorted data structure and keeps keys in sorted order.
List vs. Set vs. Map interface
When to use List, Set and Map in Java
1) If you need to access elements frequently by using index, than List is a way to go. Its implementation e.g. ArrayList provides faster access if you know index.
2) If you want to store elements and want them to maintain an order on which they are inserted into collection then go for List again, as List is an ordered collection and maintain insertion order.
3) If you want to create collection of unique elements and don't want any duplicate than choose any Set implementation e.g. HashSet, LinkedHashSet or TreeSet. All Set implementation follow there general contract e.g. uniqueness but also add addition feature e.g. TreeSet is a SortedSet and elements stored on TreeSet can be sorted by using Comparator or Comparable in Java. LinkedHashSet also maintains insertion order.
4) If you store data in form of key and value than Map is the way to go. You can choose from Hashtable, HashMap, TreeMap based upon your subsequent need. In order to choose between first two see difference between HashSet and HashMap in Java.
Bucket Sort
Bucket Sort O(n+k)
This java program is a simple Bucket Sort Example:
public class BucketSort{
public static void sort(int[] a, int maxVal) {
int [] bucket=new int[maxVal+1];
for (int i=0; i<bucket.length; i++) {
bucket[i]=0;
}
for (int i=0; i<a.length; i++) {
bucket[a[i]]++;
}
int outPos=0;
for (int i=0; i<bucket.length; i++) {
for (int j=0; j<bucket[i]; j++) {
a[outPos++]=i;
}
}
}
public static void main(String[] args) {
int maxVal=5;
int [] data= {5,3,0,2,4,1,0,5,2,3,1,4};
System.out.println("Before: " + Arrays.toString(data));
sort(data,maxVal);
System.out.println("After: " + Arrays.toString(data));
}
}
Output:
# java BucketSort
Before: [5, 3, 0, 2, 4, 1, 0, 5, 2, 3, 1, 4]
After: [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
Counting Sort
Counting Sort O(n+k)
Counting sort is a sorting technique based on keys between a specific range. It works by counting the number of objects having distinct key values (kind of hashing). Then doing some arithmetic to calculate the position of each object in the output sequence.
Source: (CountingSort.java)
import java.util.*;
public class CountingSort{
public static int[] sort(int[] array) {
// array to be sorted in, this array is necessary
// when we sort object datatypes, if we don't,
// we can sort directly into the input array
int[] aux = new int[array.length];
// find the smallest and the largest value
int min = array[0];
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
} else if (array[i] > max) {
max = array[i];
}
}
// init array of frequencies
int[] counts = new int[max - min + 1];
// init the frequencies
for (int i = 0; i < array.length; i++) {
counts[array[i] - min]++;
}
// recalculate the array - create the array of occurences
counts[0]--;
for (int i = 1; i < counts.length; i++) {
counts[i] = counts[i] + counts[i-1];
}
/*
Sort the array right to the left
1) Look up in the array of occurences the last occurence of the given value
2) Place it into the sorted array
3) Decrement the index of the last occurence of the given value
4) Continue with the previous value of the input array (goto set1),
terminate if all values were already sorted
*/
for (int i = array.length - 1; i >= 0; i--) {
aux[counts[array[i] - min]--] = array[i];
}
return aux;
}
public static void main(String[] args) {
int [] unsorted = {5,3,0,2,4,1,0,5,2,3,1,4};
System.out.println("Before: " + Arrays.toString(unsorted));
int [] sorted = sort(unsorted);
System.out.println("After: " + Arrays.toString(sorted));
}
}
Output:
$ java CountingSort
Before: [5, 3, 0, 2, 4, 1, 0, 5, 2, 3, 1, 4]
After: [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
Insertion Sort
Insertion Sort O(n)
The insertion sort, unlike the other sorts, passes through the array only once. The insertion sort is commonly compared to organizing a handful of playing cards. You pick up the random cards one at a time. As you pick up each card, you insert it into its correct position in your hand of organized cards.
Source: (InsertionSort.java)
public class InsertionSort {
public static void main(String args[]) {
int[] array = {9,7,5,3,1,8,6,4,2,0};
System.out.print("Before: " );
for(int x: array) {
System.out.print(x + " ");
}
System.out.println(" ");
int tmp;
for (int i = 1; i < array.length; i++) {
for(int j = i ; j > 0 ; j--) {
if(array[j] < array[j-1]) {
tmp = array[j];
array[j] = array[j-1];
array[j-1] = tmp;
}
}
System.out.print("pass " + i + ": " );
for(int x: array) {
System.out.print(x + " ");
}
System.out.println(" ");
}
System.out.println("Done");
}
}
Output:
# java InsertionSort
Before: 9 7 5 3 1 8 6 4 2 0
pass 1: 7 9 5 3 1 8 6 4 2 0
pass 2: 5 7 9 3 1 8 6 4 2 0
pass 3: 3 5 7 9 1 8 6 4 2 0
pass 4: 1 3 5 7 9 8 6 4 2 0
pass 5: 1 3 5 7 8 9 6 4 2 0
pass 6: 1 3 5 6 7 8 9 4 2 0
pass 7: 1 3 4 5 6 7 8 9 2 0
pass 8: 1 2 3 4 5 6 7 8 9 0
pass 9: 0 1 2 3 4 5 6 7 8 9
Done
Parallel Sort
Parallel Sort
Arrays.parallelSort() uses the Fork/Join framework introduced in Java 7 to assign the sorting tasks to multiple threads available in the thread pool. This feature was introduced in Java 8.
Source: (ParallelSort.java)
import java.util.*;
public class ParallelSort {
public static void main(String[] args) {
// Create a list and populate it with random numbers
List<Integer> list = new ArrayList();
Random r = new Random();
for (int x = 0; x < 30000000; x++) {
list.add(r.nextInt(10000));
}
// Create two arrays for sorting.
Integer[] array1 = new Integer[list.size()];
Integer[] array2 = new Integer[list.size()];
array1 = list.toArray(array1);
array2 = list.toArray(array2);
// sort array
long start = System.currentTimeMillis();
Arrays.sort(array1);
long end = System.currentTimeMillis();
System.out.println("Sort Time: " + (end - start));
// sort array using parallel sort
start = System.currentTimeMillis();
Arrays.parallelSort(array2);
end = System.currentTimeMillis();
System.out.println("Parallel Sort Time: " + (end - start));
}
}
Output:
$ java -Xmx2048m ParallelSort
Sort Time: 28516
Parallel Sort Time: 15152
Pancake Sort
Pancake Sort
Pancake sorting is the colloquial term for the mathematical problem of sorting a disordered stack of pancakes in order of size when a spatula can be inserted at any point in the stack and used to flip all pancakes above it. - http://en.wikipedia.org/wiki/Pancake_sorting
Source: (PancakeSort.java)
import java.util.*;
import java.lang.*;
import java.io.*;
class PancakeSort {
public static void main(String[] args) {
int[] arr = {10,9,8,7,6,15,14,13,12,11,5,4,3,2,1};
System.out.println("Unsorted: " + Arrays.toString(arr));
pancakeSort(arr);
System.out.println("Sorted: " + Arrays.toString(arr));
}
public static void pancakeSort(int[] A){
int max = 0;
int j, index = 0;
for (int i = 0; i < A.length; i++) {
max = A[0];
index = 0;
for (j = 0; j < A.length - i; j++) {
if (A[j] > max) {
max = A[j];
index = j;
}
}
flip(A, index, A.length - 1 - i);
}
}
public static void flip(int[] A, int l, int r) {
while (l <= r) {
int temp = A[l];
A[l] = A[r];
A[r] = temp;
l++;
r--;
}
}
}
Output:
$ java PancakeSort
Unsorted: [10, 9, 8, 7, 6, 15, 14, 13, 12, 11, 5, 4, 3, 2, 1]
Sorted: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
Heap Sort
Heap Sort
This java example is an implementation of an array base heap sort.
Source: (HeapSort.java)
import java.util.*;
public class HeapSort {
private static int[] a;
private static int n;
private static int left;
private static int right;
private static int largest;
public static void buildheap(int []a) {
n = a.length-1;
for(int i=n/2; i>=0; i--){
maxheap(a,i);
}
}
public static void maxheap(int[] a, int i) {
left = 2*i;
right = 2*i+1;
if(left <= n && a[left] > a[i]){
largest=left;
} else {
largest=i;
}
if(right <= n && a[right] > a[largest]) {
largest=right;
}
if(largest!=i) {
exchange(i, largest);
maxheap(a, largest);
}
}
public static void exchange(int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
public static void sort(int[] myarray) {
a = myarray;
buildheap(a);
for(int i=n; i>0; i--) {
exchange(0, i);
n=n-1;
maxheap(a, 0);
}
}
public static void main(String[] args) {
int []numbers={55,2,93,1,23,10,66,12,7,54,3};
System.out.println(Arrays.toString(numbers));
sort(numbers);
System.out.println(Arrays.toString(numbers));
}
}
Output:
$ java HeapSort
[55, 2, 93, 1, 23, 10, 66, 12, 7, 54, 3]
[1, 2, 3, 7, 10, 12, 23, 54, 55, 66, 93]
final (keyword)
final (keyword)
The final keyword in java is used to restrict the user. The java final keyword can be used in many context. Final can be:
variable, method, class.
Java final variable
The final keyword can be applied with the variables, a final variable that have no value it is called blank final variable or uninitialized final variable.
It can be initialized in the constructor only.
The blank final variable can be static also which will be initialized in the static block only.
If you make any variable as final, you cannot change the value of final variable(It will be constant).
Example of final variable
There is a final variable speedlimit, we are going to change the value of this variable, but It can't be changed because final variable once assigned a value can never be changed.
class Bike9{
final int speedlimit=90;//final variable
void run(){
speedlimit=400; // this will make error
}
public static void main(String args[]){
Bike9 obj=new Bike9();
obj.run();
}
}//end of class
Java final class
If you make any class as final, you cannot extend it.
Example of final class
final class Bike{}
class Honda1 extends Bike{ //cannot inherit from final Bike,this will make error
void run(){System.out.println("running safely with 100kmph");}
public static void main(String args[]){
Honda1 honda= new Honda();
honda.run();
}
}
Java final method
If you make any method as final, you cannot override it.
Example of final method (run() in Honda cannot override run() in Bike)
class Bike{
final void run(){System.out.println("running");}
}
class Honda extends Bike{
void run(){System.out.println("running safely with 100kmph");}
public static void main(String args[]){
Honda honda= new Honda();
honda.run();
}
}
You are always allowed to initialize a final variable. The compiler makes sure that you can do it only once.
Note that calling methods on an object stored in a final variable has nothing to do with the semantics of final. In other words: final is only about the reference itself, and not about the contents of the referenced object.
Java has no concept of object immutability; this is achieved by carefully designing the object, and is a far-from-trivial endeavor.
Default Methods for Interfaces
Default Methods for Interfaces
Java 8 enables us to add non-abstract method implementations to interfaces by utilizing the default keyword. This feature is also known as Extension Methods. Here is our first example:
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Besides the abstract method calculate the interface Formula also defines the default method sqrt. Concrete classes only have to implement the abstract method calculate. The default method sqrt can be used out of the box.
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100); // 100.0
formula.sqrt(16); // 4.0
The formula is implemented as an anonymous object. The code is quite verbose: 6 lines of code for such a simple calucation of sqrt(a * 100). As we'll see in the next section, there's a much nicer way of implementing single method objects in Java 8.
Lambda - Sort a list of strings
Sort a list of strings in prior versions of Java
Let's start with a simple example of how to sort a list of strings in prior versions of Java:
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
The static utility method Collections.sort accepts a list and a comparator in order to sort the elements of the given list. You often find yourself creating anonymous comparators and pass them to the sort method.
Sort a list of strings in Java 8
Instead of creating anonymous objects all day long, Java 8 comes with a much shorter syntax, lambda expressions:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
As you can see the code is much shorter and easier to read. But it gets even shorter:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
For one line method bodies you can skip both the braces {} and the return keyword. But it gets even more shorter:
Collections.sort(names, (a, b) -> b.compareTo(a));
The java compiler is aware of the parameter types so you can skip them as well. Let's dive deeper into how lambda expressions can be used in the wild.
Addition with lambda
//with type declaration
MathOperation addition = (int a, int b) -> a + b;
//without type declaration
MathOperation subtraction = (a, b) -> a - b;
Multiplication with lambda
//with return statement along with curly braces
MathOperation multiplication = (int a, int b) -> { return a * b; };
//without return statement and without curly braces
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
//with parenthesis
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
//without parenthesis
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);
greetService1.sayMessage("Mahesh");
greetService2.sayMessage("Suresh");
}
interface MathOperation {
int operation(int a, int b);
}
interface GreetingService {
void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
Lambda - sum
Sum function with lambda expession
(int x, int y) -> x + y // takes two integer arguments, named x and y, and returns their sum
Lambda - comparing Strings
Compare Strings
it is often unnecessary to repeat them
Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2);
Compare Strings
the target type is simply the type being assigned to or returned:
Comparator<String> c;
c = (String s1, String s2) -> s1.compareToIgnoreCase(s2);
Optional
Optional in Java 8
We can get rid of all those null checks by utilizing the Java 8 Optional type. The method mapaccepts a lambda expression of type Function and automatically wraps each function result into an Optional. That enables us to pipe multiple map operations in a row. Null checks are automatically handled under the hood.
Optional.of(new Outer())
.map(Outer::getNested)
.map(Nested::getInner)
.map(Inner::getFoo)
.ifPresent(System.out::println);
An alternative way to achieve the same behavior is by utilizing a supplier function to resolve the nested path:
Outer obj = new Outer();
resolve(() -> obj.getNested().getInner().getFoo());
.ifPresent(System.out::println);
Calling obj.getNested().getInner().getFoo()) might throw a NullPointerException. In this case the exception will be caught and the method returns Optional.empty().
Java Stream
A stream represents a sequence of elements and supports different kind of operations to perform computations upon those elements:
List<String> myList =
Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
// C1
// C2
Stream operations are either intermediate or terminal.
Intermediate operations return a stream so we can chain multiple intermediate operations without using semicolons.
Terminal operations are either void or return a non-stream result. In the above example filter, map and sorted are intermediate operations whereas forEach is a terminal operation. Such a chain of stream operations as seen in the example above is also known as operation pipeline.
A function is non-interfering when it does not modify the underlying data source of the stream, e.g. in the above example no lambda expression does modify myList by adding or removing elements from the collection.
A function is stateless when the execution of the operation is deterministic, e.g. in the above example no lambda expression depends on any mutable variables or states from the outer scope which might change during execution.
Different kind of streams
Streams can be created from various data sources, especially collections. Lists and Sets support new methods stream() and parallelStream() to either create a sequential or a parallel stream. Parallel streams are capable of operating on multiple threads and will be covered in a later section of this tutorial. We focus on sequential streams for now:
Arrays.asList("a1", "a2", "a3")
.stream()
.findFirst()
.ifPresent(System.out::println); // a1
Calling the method stream() on a list of objects returns a regular object stream. But we don't have to create collections in order to work with streams as we see in the next code sample:
Stream.of("a1", "a2", "a3")
.findFirst()
.ifPresent(System.out::println); // a1
Just use Stream.of() to create a stream from a bunch of object references.
Besides regular object streams Java 8 ships with special kinds of streams for working with the primitive data types int, long and double. As you might have guessed it's IntStream, LongStream and DoubleStream.
IntStreams
IntStreams can replace the regular for-loop utilizing IntStream.range():
IntStream.range(1, 4)
.forEach(System.out::println);
// 1
// 2
// 3
As you might have guessed it's IntStream, LongStream and DoubleStream.
All those primitive streams work just like regular object streams with the following differences: Primitive streams use specialized lambda expressions, e.g. IntFunction instead of Function or IntPredicate instead of Predicate. And primitive streams support the additional terminal aggregate operations sum() and average():
Arrays.stream(new int[] {1, 2, 3})
.map(n -> 2 * n + 1)
.average()
.ifPresent(System.out::println); // 5.0
Sometimes it's useful to transform a regular object stream to a primitive stream or vice versa. For that purpose object streams support the special mapping operations mapToInt(), mapToLong() and mapToDouble:
Stream.of("a1", "a2", "a3")
.map(s -> s.substring(1))
.mapToInt(Integer::parseInt)
.max()
.ifPresent(System.out::println); // 3
Primitive streams can be transformed to object streams via mapToObj():
IntStream.range(1, 4)
.mapToObj(i -> "a" + i)
.forEach(System.out::println);
// a1
// a2
// a3
Here's a combined example: the stream of doubles is first mapped to an int stream and than mapped to an object stream of strings:
Stream.of(1.0, 2.0, 3.0)
.mapToInt(Double::intValue)
.mapToObj(i -> "a" + i)
.forEach(System.out::println);
// a1
// a2
// a3
Question
Answer
Question
Answer
Question
Answer
Question
Answer
Question
Answer
Question
Answer