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.

String concatenation in java

String concatenation using + operator::


String sunita="sunita"
String pndey="pandey";
String sunitapandey=sunita+pndey;

Under the covers what does a compiler do:


String sunitapandey=new StringBuilder(String.valueOf(sunita)).append(pndey).toString();

ByteCode for the same—-

0 ldc [16]
2 astore_1 [sunita]
3 ldc [18]
5 astore_2 [pndey]
6 new java.lang.StringBuilder [20]
9 dup
10 aload_1 [sunita]
11 invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [22]
14 invokespecial java.lang.StringBuilder(java.lang.String) [28]
17 aload_2 [pndey]
18 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [31]
21 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [35]
24 astore_3 [sunitapandey]

//.toString method in Stringbuilder

@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}

the above concatenation will create a new StringBuilder with one char[] buffer with 16 size and at last .toString() method creates a new String object with a copy of StringBuilder buffer.

Suppose you are concatenating using + operator in a loop then imagine the number of temporary objects will be created.

so instead of doing like


String concat="";
for(int i=0;i<100;i++){
concat=concat+"abc";
}

one can efficiently do like

StringBuilder concat=new StringBuilder();
for(inti=0;i<100;i++){
concat.append("abc");
}
String con=concat.toString();

However ,one point to be noted here is , if i use “+” operator for a concatenation and if the result is resolved during compilation time itself then a new StringBuilder instance is not created , stringBuilder conversion is only done for those strings whose value is computed during runtime . Look at following example and their generated bytecode.


String grima="garima"+"pandey";

Bytecode for the same—
0 ldc [16]
2 astore_1 [grima]
3 return
Line numbers:
[pc: 0, line: 8]
[pc: 3, line: 9]
Local variable table:
[pc: 0, pc: 4] local: n index: 0 type: java.lang.String[]
[pc: 3, pc: 4] local: grima index: 1 type: java.lang.String

 Note–Whenever possible prefer .append(char[] str) or .append(char c) methods of StringBuilder over .append(String str) method of StringBuilder as its fast.