Thursday, 22 September 2016

Object Copying in Java using Shallow Copy

Copying an object in java means creating a new object of same type and copying each of the attributes of your object to this newly created object.
When your class has only primitive types as its attributes then copy is shallow or deep it does not matter. But when your class contains objects of another classes as one of its members then it makes difference.

Lets see how an object can be copied using shallow copy method.

Following code has two classes - Engine and Car. Car class contains Engine object as one of its members. Car class has a static method createShallowCopy() which will be used to create a copy of Car object passed to it.


*******************************************************
class Engine {
    private String engineLocation;
   
    Engine(){
    }

    Engine(String engineLocation){
        this.engineLocation=engineLocation;
    }
   
    public void setEngineLocation(String engineLocation){
        this.engineLocation=engineLocation;
    }
  
    public String getEngineLocation(){
        return engineLocation;
    }
}

public class Car {

    private String make;
    private Engine engine;   /*Reference to Engine Object*/

  Car(){
  }

  Car(String make,Engine engine){
     this.make=make;
     this.engine=engine;
  }

  /*Creating a copy of Car object*/
  public static Car createShallowCopy(Car anotherCar){
     Car car =new Car();
     car.make=anotherCar.make;
    /*Shallow Copy: Copying a reference variable only, not the attributes of Engine Object */
     car.engine=anotherCar.engine;  
     return car;
  }

  public void setMake(String make){
        this.make=make;
  }
 
  public String getMake(){
        return make;
  }
 
  public void setEngine(Engine engine){
        this.engine=engine;
  }
 
  public Engine getEngine(){
        return engine;
  }


public static void main(String args[]){

    Engine engine= new Engine("Front");
    Car car1 = new Car("Maruti",engine);

   /*Creating shallow copy*/
   Car car2= Car.createShallowCopy(car1);

   System.out.println("Car 1 Details:");
   System.out.println("Make="+car1.getMake());
   System.out.println("****Engine Details****");
   System.out.println("    Engine Location="+car1.getEngine().getEngineLocation());

   System.out.println("Car 2 Details:");

   System.out.println("Make="+car2.getMake());
   System.out.println("****Engine Details****");

   System.out.println("    Engine Location="+car2.getEngine().getEngineLocation());

  }   

}
***********************************************************************

Output:
Car 1 Details:
Make=Maruti
****Engine Details****
        Engine Location=Front
Car 2 Details:
Make=Maruti
****Engine Details****
        Engine Location=Front

The above program creates a Car instance , then creates its copy using createShallowCopy() nethod and prints both cars details.

Now while creating a copy of Car object you are copying each attribute of car object (passed as argument to createShallowCopy() method) to the newly created car instance.

Note the statement:


car.engine = anotherCar.engine;

In the above statement you are copying a reference variable instead of a primitive type variable.

Here instead of copying each attribute of engine (of anotherCar) to the attributes of engine( of car), you are just copying a reference variable.

As a result both reference variables engine(of car) and engine(of anotherCar) contains same value and now points to same Engine object. Thus now both cars shares same engine ( an unrealistic situation though ! :-) ). If you change the engine in one car it will be reflected in other car.

Due to this our Car objects - car1 and car2 are not independent.


This is shallow copy. In Shallow copy you do not copy each attribute of the component classes but only copy their reference variables.





Side Effect of Shallow Copy

Now suppose we want to change the location of engine in one of our car object from "front" to "back" as:


main() (changed):


public static void main(String args[]){
   Engine engine= new Engine("Front");
   Car car1 = new Car("Maruti",engine);

   /*Creating shallow copy*/
  Car car2= Car.createShallowCopy(car1);

  System.out.println("Car 1 Details:");
  System.out.println("Make="+car1.getMake());
  System.out.println("****Engine Details****");
  System.out.println("    Engine Location="+car1.getEngine().getEngineLocation());

  System.out.println("Car 2 Details:");
  System.out.println("Make="+car2.getMake());
  System.out.println("****Engine Details****");

  System.out.println("    Engine Location="+car2.getEngine().getEngineLocation());

  /*Changing Engine Location of car2*/
  car2.getEngine().setEngineLocation("Back");

 System.out.println("*******************After Change****************************");

 System.out.println("Car 1 Details:");
 System.out.println("Make="+car1.getMake());
 System.out.println("****Engine Details****");
 System.out.println("    Engine Location="+car1.getEngine().getEngineLocation());

 System.out.println("Car 2 Details:");
 System.out.println("Make="+car2.getMake());
 System.out.println("****Engine Details****");
 System.out.println("    Engine Location="+car2.getEngine().getEngineLocation());

}   


Output:

Car 1 Details:
Make=Maruti
****Engine Details****
        Engine Location=Front
Car 2 Details:
Make=Maruti
****Engine Details****
        Engine Location=Front
*******************After Change*******************************
Car 1 Details:
Make=Maruti
****Engine Details****
        Engine Location=Back
Car 2 Details:
Make=Maruti
****Engine Details****
        Engine Location=Back

Note the output. Engine location of both car1 and car2 got changed to Back.

You have changed the location of engine of car2 but both engines ( of car1 and car2) got changed. This is because engine in both objects are pointing to same Engine object.

Friday, 26 August 2016

Common reasons of java.lang.ArrayIndexOutOfBoundsException in Java

Reasons of java.lang.ArrayIndexOutOfBoundsException 

java.lang.ArrayIndexOutOfBoundsExcepiton is one of the most common errors in Java program. It occurs when Java program tries to access an invalid index e.g. an index which is not positive or greater than the length of an array. For example, if you have an array of String e.g. String[] name = {"abc"} then trying to access name[1] will give java.lang.ArrayIndexOutOfBoundsException: length=1; index=1 error because index 1 is invalid here. Why? because index in Java array starts with zero rather than 1, hence in an array of just one element the only valid index is index zero.  This was one of the most common scenarios which cause several million of ArrayIndexOutOfBoundsException daily. Sometimes it just a plain programming error but sometimes if an array is populated outside and if there is an error on feed than also you get java.lang.ArrayIndexOutOfBoundsException in Java.

In this article, I will share with you some of the common reasons of ArrayIndexOutOfBoundsExcpetion and their solution. This will give you enough experience to deal with this error in future.

In order to solve ArrayIndexOutOfBoundsException, just remember following key details about array in Java:

1) The array index in Java starts at zero and goes to length - 1, for example in an integer array int[] primes = new int[10], the first index would be zero and last index out be 9 (10 -1)

2) Array index cannot be negative, hence prime[-1] will throw java.lang.ArrayIndexOutOfBoundsException.

3) The maximum array index can be Integer.MAX_VALUE -1 because the data type of index is int in Java and the maximum value of int primitive is Integer.MAX_VALUE. See Big Java: Early Objects, 5th edition by Cay S. Horstmann to learn more about array data structure in Java. 

Now, let's see some of the common examples of ArrayIndexOutOfBoundsException in Java

java.lang.ArrayIndexOutOfBoundsException

length=0 index=0

This is the classic case of accessing an empty array. Since length is zero it means the array is empty and the index is zero means we are trying to access the first element of the array. This happens when you try to access an array without checking its length, as shown below.
public class Test {

  public static void main(String[] args) {

    int[] array = new int[0];

    // bad code
    int number = array[0];

    // good code
    if (array.length > 0) {
      number = array[0];
    }
  }

}

When you run this program you will get following error:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Test.main(Main.java:15)

A solution to this problem is to always access array after checking array length, as shown in the good code snippet.





java.lang.ArrayIndexOutOfBoundsException: length=1; index=1

This the second most popular reason of ArrayIndexOutOfBoundsException in Java. Here you are trying to access an array by its length. If you remember, the maximum valid index in the array is length -1 but if you somehow try to access index = length then you get this error. This usually happens when you use <= or >= sign in for loop while looping over an array in Java.
public class ABC {

  public static void main(String[] args) {

    int[] array = new int[10];
    int sum = 0;

    // bad code
    for (int i = 0; i <= array.length; i++) {
      sum = sum + array[i];
    }

    // good code
    for (int i = 0; i < array.length; i++) {
      sum = sum + array[i];
    }
  }

}

If you run this code, you will get following error :

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10
at ABC.main(Main.java:16)

This is because 10 is not a valid index for an array of length 10. The valid index is only from 0 to 9. See a good data structure book e.g. Introduction to Algorithm to learn more about array data structure in general.



java.lang.ArrayIndexOutOfBoundsException length=12 index=-1
This is the third common reasons of millions of ArrayIndexOutOfBoundsException. In this case, you are trying to access the array using a negative index. There could be different reasons why index becomes negative but the bottom line is you should not access an array with the negative index.

That's all about 3 examples of ArrayIndexOutOfBoundsException in Java. You can solve this error very easily If you remember the key details about array implementation in Java e.g. array index starting at zero and no negative indexes are allowed. You should also know that the maximum an index can go up to Integer.MAX_VALUE value because the data type of index is int in Java.

Thursday, 25 August 2016

How to replace an element of ArrayList in Java

You can use the set() method of java.util.ArrayList class to replace an existing element of ArrayList in Java. The set(int index, E element) method takes two parameters, first is the index of an element you want to replace and second is the new value you want to insert. 

You can use this method as long as your ArrayList is not immutable e.g. not created using Collections.unmodifiableList(), 
in such case the set() method throws java.lang.UnsupportedOperationExcepiton. 

Though, you can also use the set() method with the List returned by Arrays.asList() method as oppose to add() and remove() which is not supported there. You just need to be careful with the index of elements. For example, if you want to replace the first element then you need to call set(0, newValue) because similar to an array, ArrayList index is also zero based.

Now, the questions come why do you want to replace an element in the ArrayList? Why not just remove the element and insert a new one? Well, obviously the remove and insert will take more time than replace. The java.util.ArrayList provides O(1) time performance for replacement, similar to size(), isEmpty(), get(), iterator(), and listIterator() operations which runs in constant time.

Now, you may wonder that why set() gives O(1) performance but add() gives O(n) performance, because it could trigger resizing of array, which involves creating a new array and copying elements from old array to new array.  See  Core Java Volume 1 - Fundamentals to learn more about implementation and working of ArrayList in Java.

Replacing an existing object in ArrayList
Here is an example of replacing an existing value from ArrayList in Java. In this example, I have an ArrayList of String which contains names of some of the most popular and useful books for Java programmers. Our example replaces the 2nd element of the ArrayList by calling the ArrayList.set(1, "Introduction to Algorithms") because the index of the array starts from zero. You should read a comprehensive book like "Big Java Early Object" by Cay S. Horstmann to learn more about useful collection classes in Java, including ArrayList.





Java Program to replace elements in ArrayList
import java.util.ArrayList;
import java.util.List;

/*
 * Java Program to demonstrate how to replace existing value in 
 * ArrayList.
 */

public class ArrayListSetDemo {

  public static void main(String[] args) {

    // let's create a list first
    List<String> top5Books = new ArrayList<String>();
    top5Books.add("Clean Code");
    top5Books.add("Clean Coder");
    top5Books.add("Effective Java");
    top5Books.add("Head First Java");
    top5Books.add("Head First Design patterns");

    // now, suppose you want to replace "Clean Coder" with
    // "Introduction to Algorithms"
    System.out.println("ArrayList before replace: " + top5Books);

    top5Books.set(1, "Introductoin to Algorithms");

    System.out.println("ArrayList after replace: " + top5Books);
  }

}

Output
ArrayList before replace: [Clean Code, Clean Coder, Effective Java, 
Head First Java, Head First Design patterns]
ArrayList after replace: [Clean Code, Introduction to Algorithms, 
Effective Java, Head First Java, Head First Design patterns]

You can see that initially, we have a list of 5 books and we have replaced the second element by calling set(1, value) method, hence in the output, the second book which was "Clean Coder" was replaced by "Introduction to Algorithms".


That's all about how to replace existing elements of ArrayList in Java. The set() method is perfect to replace existing value just make sure that List you are using is not immutable. You can also use this method with any other List type e.g. LinkedList. The time complexity is O(n) because we are doing index based access to the element.

10 Essential JVM Options for a Java Production System

This is a brief guide of important JVM options which you will often see with production Java systems. As a Java developer, you should know what these JVM options means and their importance. You will find that most of the JVM options are related to heap memory settings, garbage collection and to log some details e.g. heap dump, necessary for troubleshooting any issue e.g. memory leak or excessive memory consumption. It's ok if you don't know them yet but you should know them and that's the objective of this article. How do you find the JVM options your application is using? Well, you can see the startup scripts through which your application is started. Alternatively, if your application is running on Linux you can do ps -ef | grep java to find the Java process and see the JVM options printed as process arguments. If more than one Java process is running on the system then you may need to search with a keyword which is unique to your Java application.

Remember, your process might not catch with ps -ef, if the argument list is too long, so you can also try using ps -auxww command, which shows the process with a long argument list as well. Once you have that list of JVM flags, you can understand certain behaviors of any Java application e.g. Tomcat, particularly how much memory is left to grow etc.

Btw, this is not the guide for JVM performance tuning, it will just let you familiar with essential JVM options from Java developer's perspective. You should refer Java Performance The Definitive Guide By Scott Oaks for a comprehensive learning on JVM internals and Java performance tuning.
 Must Know JVM options for Java Developers
 
Here is my list of essential JVM options which are must for any productions system and I strongly believe that every Java developer should be familiar with these Java virtual machine flags. The list is not big and it just include the most popular options. It doesn't include JVM options related to 32-bit or 64-bit or something like -XX:UseCompressedOOP, which is quite important for 64-bit Java virtual machine. For a more comprehensive list of JVM options, you can see this list.


1) -Xms
This option is to specify starting heap size for JVM e.g. -Xms2048m means initial heap size of JVM is 2GB. When JVM will start the heap memory will be this big. This is done to prevent resizing during startup and improve the startup time of JVM.


2) -Xmx
This option is to specify maximum heap size of JVM e.g. -Xmx2048m means maximum heap size of JVM will be 2GB. You will almost always see -Xms and -Xmx together. Their ration is also important, the ration of 1:1 or 1:1.5 is found to be more efficient. You must specify sufficient heap space for your Java application to avoid java.lang.OutOfMemoryError: Java Heap space, which comes if there is not enough memory to create new objects or arrays.


3) -XX:PermSize
Earlier JVM options specify the size of heap memory but this one is to specify the size of PermGen space, where string pool and class metadata is stored. This option is very important for the web server like Tomcat which often loads classes of the web application during deployment. It's worth knowing that PermGen space is replaced by MetaSpace in Java 8 and this option is not relevant if you are running with JRE 8 JVM. See Java Performance Companion by Charlie Hunt to learn more about Java 8 changes and their performance impact. It is the most up-to-date book in Java performance till date and help you to squeeze the best performance with JDK 8 in any application.



4) -XX:MaxPermSize
This is the counterpart of earlier JVM option and used to specify the maximum size of permanent generation of JVM. The permgen will expand until it reaches this value, It cannot expand beyond this. If the permanent generation of JVM is full then you will get java.lang.OutOfMemoryError: PermGen space. So, this option is very important to avoid that error.


5) -verbose:gc
This JVM option is used to enable Garbage collection logging in your Java application. It will show you whether it's major or minor garbage collection, which kind of garbage collector is used, how much memory is reclaimed and how much time it took etc.


6) -XX:+PrintGCTimeStamps
This JVM option will prepend record with timestamp since Java application start, so you can see that at which state of your application GC activity peaks.


7) -XX:+PrintGCDetails 
Prints some more garabage collections details


8) -Xloggc:[path to gc log file]
You can log all garbage collection details into a log file for future analysis using this JVM option. You can later use tools like GCViewer to analyze the logs files.

Essential JVM options for Java production application

9) -Dsun.net.inetaddr.ttl=
This is an essential JVM option if your Java program connects to database or any other Java processor web server via a load balancer e.g. in which hostname can be routed to the different IP address in case of failover. This option specifies the number of seconds during which DNS record will be cached in JVM. This is even more important with Java 6 virtual machine which caches the IP address forever. In that case, you don't have other option but to restart your Java application if upstream or database switched to the secondary node, not the most elegant option.


10) -XX:+HeapDumpOnOutOfMemoryError
This JVM option creates a heap dump when your JVM dies with OutOfMemory Error. There is no overhead involved unless an OOM actually occurs. This flag is a must for production systems as it is often the only way to further analyze the problem. The heap dump will be generated in the "current directory" of the JVM by default. If you want to create heap dumps on specific directory then use -XX:HeapDumpPath=[path-to-heap-dump-directory] e.g. -XX:HeapDumpPath=/dsk3/dumps.

Remember that the heap dump file can be huge, up to Gigabytes, so ensure that the target file system has enough space. You can also refer Java Performance Companion 1st edition by Charlie Hunt to learn more about analyzing heap dump and thread dump in Java.


That's all in the least of essential JVM options must for a Java production system. As I said, every Java developer should familiar with these options and should not put the Java application into production without having these JVM options. You may need to put more JVM option e.g. to select a garbage collector e.g. ConcurrentMarkSweep or G1 and other network related parameters but this is a bare minimum set of JVM option for any production Java system.

How to read a text file in Java - BufferedReader Method

There are multiple ways to read a file in Java e.g. you can use a Scanner as we have seen in the last example, or you can use the BufferedReader class. The advantage of using a BufferedReader to read a text file is speed. It allows faster reading because of internal buffering provided by BufferedReader. Other Reader classes e.g. FileReader access the file or disk everytime you call the read() method but BufferedReader keeps 8KB worth of data in its internal buffer which you can read it without accessing file multiple times. It's loaded when you access the file first time for a subsequent read. The BufferedReader class is also a good example of Decorator design pattern because it decorates existing readers e.g. FileReader to provide buffering, remember, the reading from file functionality still comes from the FileReader class.
One more advantage of using the BufferedReader for reading a text file is its ability to read file line by line. It provides a readLine() method which can be used to read a text file line by line in Java.


The java.io.BufferedReader class provides 4 versions of the read() method to read data from a text file

read() - to read a single character, this method return an int, so you need to cast that to a character
read(char[] cbuf) - to read characters into an array. This method will block until some input is available, an I/O error occurs, or the end of the stream is reached. This method either return number of characters read or -1 if the end of file has been reached. The method comes from the Reader class.
read(CharBuffer cbuffer) - to read characters into a CharBuffer, this is similar to the previous method except that it reads characters into a CharBuffer object instead of the array. This method also returns a total number of characters read or -1 if the end of file has been reached. This method also belongs to java.io.Reader class.
 
read(char[] cbuf, int off, int len) - to read characters into an array but gives you control where to store the characters read from a file. You can specify offset i.e. the indices to start and length, how many characters to store.

readLine() - to read a Line of text. You can use this method to read a file line by line in Java. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed. This method returns a String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached. Many Java developer uses BufferedReader class just for this method.

Btw, from Java 8 onwards there are many ways to read a file line by line in Java e.g. you can use Files.lines() method to get all lines as Stream in Java and then you cannot only read them line by line but also you can also use Stream operations e.g. map(), flatMap(), filter() etc to perform useful operations.


Java Program to read a text file using BufferedReader

Here is our sample Java program to read a plain text file using BufferedReader. In this program, I have shown two examples of BufferedReader class, the first one reads file content into a character array and the second one reads the text file line by line.

If you notice carefully, while converting the character array to String, we have correctly used the offset and length because it might be possible that the array which you are using for storing content, may content dirty data from the previous read, as we are not cleaning it up after every read. That's the advantage of using offset and length, you don't need to clear or clean the array. See Core Java Volume 1 - Fundamentals to learn more about file reading in Java.



Java BufferedReader Example
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/*
 * Java Program read a text file using BufferedReader.
 * It allows you to read file line by line or directly
 * into a character array. 
 */
public class BufferedReaderDemo {

  public static void main(String[] args) throws Exception {
    String filename = "newfile.txt";

    // reading text file into array
    try {
      FileReader textFileReader = new FileReader(filename);
      BufferedReader bufReader = new BufferedReader(textFileReader);

      char[] buffer = new char[8096];

      int numberOfCharsRead = bufReader.read(buffer); // read will be from
      // memory
      while (numberOfCharsRead != -1) {
        System.out.println(String.valueOf(buffer, 0, numberOfCharsRead));
        numberOfCharsRead = textFileReader.read(buffer);
      }

      bufReader.close();

    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    // reading file line by line using BufferedReader
    try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
      String line = br.readLine();
      while (line != null) {
        System.out.println(line);
        line = br.readLine();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }

  }
}

Output
[first line] hello
[second line] bye
[first line] hello
[second line] bye

You can see from the output that we have successfully read the text file. In the second example, since we have used the try-with-resource construct, you don't need to manually call the close() method of BufferedReader, it will automatically be called by Java. The catch clause is there to catch the IOException thrown by the close() method.


That's all about how to read a text file using BufferedReader in Java. As I said, there are two main reasons to use the BufferedReader class, first the buffering it provides which makes reading efficient, and second the readLine() method it gives, which allows you to read the text file line by line. If you running in Java 8, you can also use streams to lazily read the file content by using Files.lines() method which returns a Stream of String from a text file. You can then perform operations like map() and filter() on file content.

Difference between HashMap vs IdentityHashMap in Java

The IdentityHashMap is one of the lesser known Map implementation from JDK. Unlike general purposes Map implementations like HashMap and LinkedHashMap, it is very special and it's internal working is quite different than HashMap. The main difference between IdentityHashMap and HashMap in Java is that former uses equality operator (==) instead of equals() method to compare keys. Which means you need the same key object to retrieve the value from IdentityHashMap, you cannot retrieve values by using another key which is logically equal to previous key. Another important difference between HashMap and IdentityHashMap is that IdentityHashMap doesn't use hashCode() method instead it uses System.identityHashCode() method. This is a significant difference because now you can use mutable objects as key in Map whose hash code are likely to change when the mapping is stored inside IdentityHashMap.
Other Map implementation which uses equals() and hashCode() doesn't work well with mutable keys. For example, if you store a mapping in HashMap and then went on to change the key object the hashCode generated by key later will not be the same as before. Even if you return same, the equals() method will not return true when you compare key object from entry to given key object.

So, that's the basic difference between IdentityHashMap and a HashMap in Java, let's see a couple of more and some code to understand this concept better.
\


IdentityHashMap vs HashMap in Java

As I said, IdentityHashMap is a lesser known class from JDK, you might never use this class in your project but a good chance is that someone else might have already used. Since most of the programmers spend more time reading code than writing, it's important to know what  is IdentityHashMap in Java, what it does, how it works, and when to use this class in your Java application.

Once you understand the difference between IdentityHashMap and HashMap, you will automatically learn how to make the best use of this class.

1) The first and foremost difference is that IdentityHashMap internally uses == operator instead of equals() method, which means you can store a String object into IdentityHashMap and later call the contains() method to check if it exists in the Map, it will only return true if both objects is same in heap space. It will return false even if both objects has same content, as shown below:


import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

public class HashMapVsIdentityHashMap {

  public static void main(String[] args) {

    Map<String, Integer> idMap = new IdentityHashMap<>();
    Map<String, Integer> hashMap = new HashMap<>();

    String str = new String("Java");

    idMap.put(str, 1);
    hashMap.put(str, 1);

    boolean isExist = idMap.containsKey("Java"); // false
    boolean isPresent = hashMap.containsKey("Java"); // true

    System.out.println("Does Java exists in IdentityHashmap? : " + isExist);
    System.out.println("Does Java exists in Hashmap? : " + isPresent);

  }

}

Output:
Does Java exist in IdentityHashmap? : false
Does Java exist in Hashmap? : true



You need JDK 7 to run this program because we have used diamond operator (<>) to shorten the Generic code, though nothing stops you from being running it on Java SE 6 once you remove the diamond operator and specify the types on right side of initialization as well e.g.
instead of
Map<String, Integer> idMap = new IdentityHashMap<>();
use this
Map<String, Integer> idMap = new IdentityHashMap<String, Integer>();

2) Another significant difference between HashMap and IdentityHashMap is that later uses System.identityHashCode() instead of hashCode() method of key object. This means you can also use a mutable object as a key in IdentityHashMap, which is not supported by HashMap in Java. I mean there won't be any compilation error but it will not work as expected i.e. you will not be able to retrieve object back once you modified it state because its hashCode also got changed. Let's see how this work in IdentityHashMap with an example.

Let's assume we have a class called CreditCard, which has a field called expiry, which is nothing but a formatted date in String format. Later we change the CreditCard object by changing it's expiry and see if you can find it out again from both IdentityHashMap and HashMap or not.

Java Program to show difference between HashMap vs IdentityHashMap

import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

public class sds {

  public static void main(String[] args) {

    CreditCard visa = new CreditCard("VISA", "04/12/2019");
    CreditCard master = new CreditCard("Master", "04/11/2020");
    CreditCard amex = new CreditCard("American Express", "04/10/2021");
    
    Map<CreditCard, String> cardToExpiry = new HashMap<>();
    Map<CreditCard, String> cardToExpiryIdenity = new IdentityHashMap<>();
    
    // inserting objects to HashMap
    cardToExpiry.put(visa, visa.getExpiryDate());
    cardToExpiry.put(master, master.getExpiryDate());
    cardToExpiry.put(amex, amex.getExpiryDate());
    
    // inserting objects to IdentityHashMap
    cardToExpiryIdenity.put(visa, visa.getExpiryDate());
    cardToExpiryIdenity.put(master, master.getExpiryDate());
    cardToExpiryIdenity.put(amex, amex.getExpiryDate());
    
    
    System.out.println("before modifying keys");
    String result = cardToExpiry.get(visa) != null? "Yes" : "No";
    System.out.println("Does VISA card exists in HashMap? " + result);
    
    result = cardToExpiryIdenity.get(visa) != null? "Yes" : "No";
    System.out.println("Does VISA card exists in IdenityHashMap? " + result);
    
    // modifying value object
    visa.setExpiryDate("02/11/2030");
    
    System.out.println("after modifying keys");
    result = cardToExpiry.get(visa) != null? "Yes" : "No";
    System.out.println("Does VISA card exists in HashMap? " + result);
    
    result = cardToExpiryIdenity.get(visa) != null? "Yes" : "No";
    System.out.println("Does VISA card exists in IdenityHashMap? " + result);
  }


}

class CreditCard{
  private String issuer;
  private String expiryDate;
  
  
  public CreditCard(String issuer, String expiryDate) {
    this.issuer = issuer;
    this.expiryDate = expiryDate;
  }


  public String getIssuer() {
    return issuer;
  }


  public String getExpiryDate() {
    return expiryDate;
  }
  
  public void setExpiryDate(String expiry){
    this.expiryDate = expiry;
  }


  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
        + ((expiryDate == null) ? 0 : expiryDate.hashCode());
    result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
    return result;
  }


  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    CreditCard other = (CreditCard) obj;
    if (expiryDate == null) {
      if (other.expiryDate != null)
        return false;
    } else if (!expiryDate.equals(other.expiryDate))
      return false;
    if (issuer == null) {
      if (other.issuer != null)
        return false;
    } else if (!issuer.equals(other.issuer))
      return false;
    return true;
  }
  
  
}

Output
before modifying keys
Does VISA card exists in HashMap? Yes
Does VISA card exists in IdenityHashMap? Yes
after modifying keys
Does VISA card exists in HashMap? No
Does VISA card exists in IdenityHashMap? Yes

From the output you can see that once you changed the CreditCard object, which is key in both HashMap and IdentityHashMap, you are not able to retrieve object in case of HashMap but you able to retrieve when you use IdentityHashMap because former uses equals() method which return different value once expiry date changed and later uses == operator which return true because in both cases the object is the same in heap.
You can also read Core Java Volume 1 - Fundamentals by Cay S. Horstmann to learn more about IdentityHashMap class in Java.
Here are some more important points about IdenityHashMap in Java:
  1. It uses identity methods i.e. equals and hashCode to retrieve values.
  2. It uses reference equality instead of equals() method i.e. object1 == object2 instead of object1.equals(object2).
  3. For hashing, it uses System.identityHashCode(key) instead of key.hashCode() as used by other Map implementations.
  4. The java.util.IdenityHashMap class is used in Serialization and deep copying, where your key is "Class" object or interned String. 

HashMap vs IdenityHashMap in Java


That's all about the difference between IdentityHashMap and HashMap in Java. There are rare cases where you want to use the IdentifyHashMap but it's good to know about it.


How to read a text file as String in Java

There was no easy way to read a text file as String in Java until JDK 7, which released NIO 2. This API now provides a couple of utility methods which you can use to read entire file as String e.g. Files.readAllBytes() returns a byte array of the entire text file. You can convert that byte array to String to have a whole text file as String inside your Java program. If you need all lines of files as List of String e.g. into an ArrayList, you can use Files.readAllLines() method. This return a List of String, where each String represents a single line of the file. Prior to these API changes, I used to use the BufferedReader and StringBuilder to read the entire text file as String. You iterate through the file, reading one line at a time using readLine() method and appending them into a StringBuilder until you reach the end of the file. You can still use this method if you are running on Java SE 6 or lower version.
In this article, we'll look at a couple of examples to demonstrate how to read a text file as String, or get a List of lines as String from a text file. I'll also show the BufferedReader way, which you can use in Java SE 6 and earlier version.



Reading Text File as String in Java 7

This is the standard way to read the whole file as String in Java. Just make sure the file is a small or medium size and you have enough heap space to hold the text from a file into memory. If you don't have enough memory, the below code can throw java.lang.OutOfMemoryError: Java heap space, so beware of that.
 Here is the method to read a file as String in Java 7:
public static String readFileAsString(String fileName) {
    String text = "";
    try {
      text = new String(Files.readAllBytes(Paths.get("file.txt")));
    } catch (IOException e) {
      e.printStackTrace();
    }

    return text;
  }

You should also be careful with character encoding. Above code assumes that file and platform's default character encoding is same. If that's not the case then use the correct character encoding while converting byte array to String in Java.

Reading Text File as String in Java 6

This was the old way to reading a file as String in Java. You can see that it require almost 8 to 10 lines of code, which can now effectively be done in just one line in Java 7. It uses the readLine() method to read the file line by line and then joined them together using StringBuilder's append() method.

    BufferedReader br = new BufferedReader(new FileReader("file.txt"));
    StringBuilder sb = new StringBuilder();

    String line = br.readLine();
    while (line != null) {
      sb.append(line).append("\n");
      line = br.readLine();
    }

    String fileAsString = sb.toString();

Don't forget to append the \n character to insert the line break, otherwise, all lines will be joined together and all text from the file will come as just one big line.

Java Program to read a text file as String

Here is the complete Java program to read a text file as String, it includes both JDK 6 and JDK 7 approach to reading the content of the file in a String variable.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

/*
 * Java Program read a text file as String 
 * first by using the JDK 7 utility method Files.readAllBytes()
 * and second by using BufferedReader and StringBuilder.
 */

public class ReadFileAsString {

  public static void main(String[] args) throws Exception {

    // read whole file as String in JDK 7
    String data = "";
    try {
      data = new String(Files.readAllBytes(Paths.get("file.txt")));
    } catch (IOException e) {
      e.printStackTrace();
    }
    System.out.println("Text file as String in Java");
    System.out.println(data);

    // read file as String in Java SE 6 and lower version
    BufferedReader br = new BufferedReader(new FileReader("file.txt"));
    StringBuilder sb = new StringBuilder();

    String line = br.readLine();
    while (line != null) {
      sb.append(line).append("\n");
      line = br.readLine();
    }

    String fileAsString = sb.toString();
    System.out
        .println("whole file as String using BufferedReader and StringBuilder");
    System.out.println(fileAsString);

    br.close();
  }
}

Output
Text file as String in Java
Effective Java is the best book for senior Developers.
Clean code is the best book for Junior Developers.
whole file as String using BufferedReader and StringBuilder
Effective Java is the best book for senior Developers.
Clean code is the best book for Junior Developers.

In the second example, don't forget to append the "\n" or "\r\n" depending upon whether you are running on Windows or UNIX, otherwise all lines of files are concatenated into just one line. Also, don't forget to close the BufferedReader to prevent resource leak, especially when you are not using automatic resource management feature of Java 7.


That's all about how to read a text file as String in Java. You can use the new way if your program is running on JRE 7 and old way if you are using Java 6 or lower versions. Pay attention to character encoding of the file if you are not sure whether both file and platform's default character encoding (the machine where your Java program is running) is not same.