JDK vs JRE

Today one of my juniors had this doubt whether she should install JRE or JDK on her system so I thought to share the difference on the same.

JRE: Java Runtime Environment , as the name suggests it provides required environment with its java libraries and java virtual machine(JVM) to run java programs. If you only need to run java programs then JRE is the only thing that you need on your system.

However, with JRE you can only run compiled java programs, it cannot compile java programs as it doesnt contain java compiler i.e javac to do the same. If you look into the bin folder of a JRE you wont find any javac.

JDK: Java Development Kit, it is a development kit that contains complete JRE alongwith other java development tools like java compiler i.e javac , a documentation generator i.e javadoc , java debugger. Using JDK, you compile .java files to .class files that contain bytecodes understandable by the JVM.

Internal working of HashMap in java

Basically HashMap is an array of Entry class, a static inner class defined in HashMap is as below:

static class Entry implements Map.Entry {
final K key;
V value;
Entry next;
final int hash;

//getters and setters

}

Each element in a Hashmap stores in it a key, its value, reference to next entry in case hashvalue is same for two entries in that case a linked list will be formed.

Default initial capacity of a HashMap is 16 i.e a HashMap is initialized with a default 16 sized array.

Now, lets see what happens when we put an element into HashMap.
Following is the code for put method in hashmap:

public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

modCount++;
addEntry(hash, key, value, i);
return null;
}

private V putForNullKey(V value) {
for (Entry e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}

Lets decode the above lines of code;
1)As the HashMap allows values to be stored with null keys in the map, firstly we check if key is null or not.
2)If key is null,putForNullKey method is called and null key value is placed at 0th position of array.
for (Entry e = table[0]; e != null; e = e.next) {//As each element with same hashvalue forms linked list in a hashmap array, we iterate the element using a for loop.If e==null, we add the new element.

3)If key is not null, we need to find the index in the array where we will store our element and this is done using hashing.
int hash = hash(key.hashCode());//We calculate a unique hash corresponding to each element.

int i = indexFor(hash, table.length);//Passing the hash and array length we find the position in array to store the element.

static int indexFor(int h, int length) {
return h & (length-1);
}

As you can see we do & operation between array length and hash value and thus a location is found from 1to16, so suppose hash value is 00000000 00010000 & 00000000 00010000, will give an index of 16.

4)Next we check if an element entry exists at above found index if it doesnt exist we add the new element entry but if an entry element already exists at the index position , here comes the linkedlist into the picture.

5)In the if condition if (e.hash == hash && ((k = e.key) == key || key.equals(k))) , we compare the hash value and a comparison with the equals method written for the object or for the same references.

6)If above condition is true, old value is replaced with new value.
7)If 5th condition is false, we iterate the linked list till we find the exact key location and put the entry element.

Implementing two interfaces with same default methods.

In java8 , a new concept is introduced wherein we can provide implementation for methods in an interface using default keyword. But what will happen if a class implements two interfaces with same default methods , which method the implementing class will inherit. Let us see this in the following working example.

I have one interface, TestInterface1 with a default method test()

package com.test;

public interface TestInterface1 {

public default void test() {
System.out.println(“hi”);
}
}

An another interface, TestInterface2 too has implementation for method test()

package com.test;

public interface TestInterface2 {

default public void test() {
System.out.println(“hello”);
}
}

Now, if I have a class Test that implements above two interfaces , the compiler gives me an error “Duplicate default methods named test with the parameters () and () are inherited from the types TestInterface2 and TestInterface1”

package com.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.util.stream.Collectors.*;

import java.lang.reflect.Method;

public class Test implements TestInterface1,TestInterface2{

public static void main(String[] args) {
Test test=new Test();
test.test();

}

However, I can remove the above error by providing the compiler which interface method implementation I need in my implementation class.

package com.test;

public class Test implements TestInterface1,TestInterface2{

public static void main(String[] args) {
Test test=new Test();
test.test();

}

@Override
public void test() {
// TODO Auto-generated method stub
TestInterface1.super.test(); }
}

So, as shown above in my implementation class method I need to call the method with the interface name whose method implementation I need.

Behaviour of static variable in inheritance

Parent and child instances share a same copy of static variable. This I concluded running the following example.

package com.test;

public class Fruit {

static int count=0;

Fruit(){
count++;
}

public static void main(String[] args) {
Chickoo chickoo=new Chickoo();
System.out.println(chickoo.count);
Fruit fruit=new Fruit();
System.out.println(fruit.count);

}
}

class Chickoo extends Fruit{
Chickoo(){
count++;
}
}

The above code prints value of count as “2” and “3”.

Deep vs Shallow Copy

package com.test;
public class User implements Cloneable{
private String name;
private Integer age;
private Address address;

public User(String name, Integer age, Address address) {
super();
this.name = name;
this.age = age;
this.address = address;
}
@Override
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public static void main(String[] args) {
Address add=new Address(“243″,”Ghaziabad road”,”Gujarat”);
User user=new User(“sunita”,50,add);
User userClone=null;
try {
userClone=(User)user.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(“Original user address–“+user.getAddress());
System.out.println(“Cloned user address–“+userClone.getAddress());

}
}

Output for above sysouts:
Original user address–com.test.Address@15db9742
Cloned user address–com.test.Address@15db9742

As you can see above in a shallow copy, userclone creates a copy of name and age primitive attributes, however for address it reuses the same address object for userclone. So, now the clone object has a copy of primitive values but the object references refer to the same objects as the original copy.

Shallow Copies have a significant drawback. As we saw above, cloned object and original copy refer to the same address object. Any change that cloned object makes in address object will also be reflected in original copy, which is an unwanted behaviour. What we really wanted is two separate copies of user object. Deep copying comes to our rescue for this kind of situation.

Deep copying not just clones the primitive values, it also creates copies of object references.

user and userClone have their own instances of empAddress. Any change done to user’s address will not have any affect on userClone’s address and vice-a-versa.

To implement deep copying – User will still need to implement Cloneable, and it will still override Object.clone() method. But inside the overridden clone() method, instead of calling super.clone(), a clone of an User object is constructed step-by-step using custom code as shown in the code below –

@Override
public Object clone() throws CloneNotSupportedException {
User userClone = (User) super.clone();
Address addressClone = new Address(this.address.getHouseNo(),
this.address.getStreet(),
this.address.getCity());
userClone.address(addressClone);
return userClone;
}

Unexpected results for TreeMap with inconsistent compareTO and equals.

If two objects are considered equal by compareTo() and not by equals() or vice-versa, then TreeSet and TreeMap may produce different output.

public class Employee implements Comparable <<>>
{
int empNo;
String empName;

@Override
public int hashCode() { return empNo; }

@Override
public boolean equals(Object obj)
{
Employee other = (Employee) obj;
if (empNo == other.empNo && empName.equals(other.empName))
return true;
return false;
}

@Override
public int compareTo(Employee other)
{
return (empNo – other.empNo);
}

@Override
public String toString() { return “[” + empNo + “, ” + empName + “]”; }

public Employee(int empNo, String empName)
{
this.empNo = empNo;
this.empName = empName;
}

public static void main(String[] args)
{
Employee employees[] = new Employee[5];
employees[0] = new Employee(1, “Grima”);
employees[1] = new Employee(2, “Krishma”);
employees[2] = new Employee(2, “Krishma”);
employees[3] = new Employee(4, “Krishma”);
employees[4] = new Employee(2, “Gurav”);

HashSet set = new HashSet();
set.addAll(Arrays.asList(employees));
System.out.println(set.toString());

TreeSet treeSet = new TreeSet();
treeSet.addAll(Arrays.asList(employees));
System.out.println(treeSet.toString());
}
}

[[1, Grima], [2, Krishma], [2, Gurav], [4, Krishma]] // HashSet
[[1, Grima], [2, Krishma], [4, Krishma]] //TreeSet

Now as per the “equals” method in Employee two employee objects will be equal if their empNo and empName are equal while “compareTo” method says that two employee objects will be equal if two employee objects have same empNo.

So the output of the hashset is expected, employees with different empNo. and empName are added to set, but if we look at output of TreeSet, employees only with different empNo are added.

Thus we can conclude that TreeMap does not use hashCode() or equals() and it uses the compareTo() method.
This could result in a serious application error where two objects considered equal by equals() return different values from TreeMap.

Summary: All 3 methods – compareTo, equals and hashCode should be consistent with each other.

Java 8 streams filter

package com.test;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Customer {

private String firstName;

private String lastName;

private int orderNo;

public Customer(String firstName, String lastName, int orderNo) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.orderNo = orderNo;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public int getOrderNo() {
return orderNo;
}

public void setOrderNo(int orderNo) {
this.orderNo = orderNo;
}

public static void main(String[] args) {
List customers=new ArrayList();
customers.add(new Customer(“garima”,”pandey”,1));
customers.add(new Customer(“ashu”,”dikshit”,2));
customers.add(new Customer(“gaurav”,”dixit”,3));

//1)Filter and foreach
//The following basically streams the collection and on a stream you can have multiple operations performed
//The stream has three parts, first is the source which in our case is customers collection, second part is all the operations that need to be performed on that stream, so below is a filter operation that is performed on the stream and finally we have a terminal operation that is the end condition, below for each is the end condition

customers.stream().filter(c->c.getLastName().startsWith("d")).forEach(c->System.out.println(c.getFirstName()));// output-->ashu,gaurav

//2)Filter and collect
//stream.filter() lets you to filter a list and collect() to convert stream into a list.

List collected=customers.stream().filter(c->c.getFirstName().startsWith("g")).collect(Collectors.toList());
collected.forEach(c->System.out.println(c.getFirstName()));//output-->garima,gaurav

//3)filter and .findAny().orElse(null)

Customer cust=customers.stream().filter(c->c.getFirstName().contains("garima")).findAny().orElse(null);
System.out.println(cust.getFirstName());//output-->garima

//4)filter and .findAny().orElse(null)

Customer custNull=customers.stream().filter(c->c.getFirstName().contains("test")).findAny().orElse(null);
System.out.println(custNull);//output-->null

//5)filter and map
//map function can be used to perform some operation on all of it’s elements.

customers.stream().filter(c->c.getFirstName().startsWith("g")).map(Customer::getFirstName).collect(Collectors.toList()).forEach(System.out::println);//output->garima,gaurav

}
}

String,String constant pool in java

String grima = “grima”;
String gri = “grima”;
if (grima == gri)
System.out.println(“grima == gri”); // The message is displayed

Both grima,grima references refer to same “grima” in string constant pool.

String pndey = “pandey”;
String pan = “pande”;
pan = pan + “y”; // The value for pan will be resolved during runtime.
if (pndey == pan)
System.out.println(“pndey == pan”); // The 2 references are different

Now in the second case if i change

pan = pan + “y”;this line to –>pan=”pande” +”y”, System.out.println(“pndey == pan”); message will be displayed because the compiler resolves the literal during compilation time itself.

Now as per java docs on string:

•Literal strings within the same class (§8 (Classes)) in the same package (§7 (Packages)) represent references to the same String object (§4.3.1).

•Literal strings within different classes in the same package represent references to the same String object.

•Literal strings within different classes in different packages likewise represent references to the same String object.

•Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.

•Strings computed by concatenation at run time are newly created and therefore distinct.

•The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.

Runtime exception over checked exception in java

When should you create a custom runtime exception??

You can create unchecked exceptions by subclassing RuntimeException whenever your method needs to signal a programming error.

For example there is some method which takes an int argument,performs some operation using that argument and returns. Now it is always a good practice to throw an IllegalArgumentException in the beginning of the method for method arguments that shouldnt be null , so that later you dont have to traverse the method to look what went wrong. Now this exception IllegalArgumentException should be a runtime exception as this is a programming error , user cannot do anything about it and you dont want to write a try catch in every other method where you throw this exception .

Business exceptions should be declared as checked exception as the user can always come out of that exception , like suppose a user tries to book a train ticket and somehow the booking fails in that scenario you wont give user an application error page but will ask to try after some time, such exceptions can be checked exceptions.

Kindly let me know your views on this by posting comments. Thanks 🙂

Hashcode() and equals() for StringBuilder and StringBuffer

StringBuilder and StringBuffer classes doesnt override equals and hashcode() methods in java.

As String class is immutable in java, mutable StringBuilder and StringBuffer were introduced in java to contruct Strings.

equals() and hashcode() method is mainly overridden to support collections so that if i use a map like hashmap i can retrieve my object that i saved using correct key on basis of hashcode() and equals() method.

A key is preferred to be a mutable one so that anytime i can recover my value for that key, now stringbuilder and stringbuffer being mutable are not preferred as keys and hence there is no point of overriding equals() and hashcode() method for them as they shouldnt be used as a candidate for key in collections.