June 30, 2022

Java Multithreading Interview Questions And Answers

In this post there is a collection of Java multi-threading interview questions and answers which'll be helpful for interview preparation.

Java multi-threading interview questions

  1. What is multithreading?

    A program can have more than one sub-tasks running independently, these sub-tasks are known as threads and a program can have many such threads running making it a multi-threaded program. Java has built-in support for multi-threaded programming.

    Read more about Multithreading here.

  2. What are the advantages of multithreading?

    In a program you can have a task that waits for some resource or event, rather than making your whole program tied to that task and make the whole program unresponsive, you can create a separate thread for that task so that it can independently. That is one of the advantages of multi-threading.

    By having multiple thread running concurrently CPU usage is optimum and the performance of the application is improved.

    Since threads are light-weight and share heap memory, any time taking task can be performed by multiple threads rather than a single thread to increase the throughput by sharing CPU cycle and without using much memory.

    Read more about Multithreading here.

  3. How is thread created in Java?

    Thread in Java can be created by-

    • By implementing Runnable interface.
    • By Extending Thread class.

    Whichever of these two ways is chosen by you to create a thread in Java you need to override run() method and provide the code that will run in that thread.

    Read more about how to create thread in Java here.
  4. What is the process for running a created thread?

    Once you have the instance of the created thread-

    • Call start method on the created thread object - thread.start();
    • Once the thread is started run method will be executed.

    Read more about how to create and start thread in Java here.

  5. Difference between thread and process in Java?

    In concurrent programming there are two types of multitasking-

    • Process based multitasking.
    • Thread based multitasking.

    A process has a self-contained execution environment. A process has its own run-time resources like memory space. Threads exist within a process — every process has at least one. Threads share the process’s resources, including memory and open files.

    Processes are heavyweight tasks running in their own allocated memory space. Threads are lightweight spawned with in a process and share its memory.

    Read more about difference between thread and process in Java here.

  6. What is the preferred way to create thread – Extending Thread class or implementing Runnable?

    Though both of these methods are equal in the way that thread created by using one way is no different from the thread created using the other way but one thing that you have to keep in mind is that Java does not support multiple inheritance i.e. any Java class can extend at most one class.

    If your class extend Thread class to create a thread then the class can’t extend any other class. That is one of the disadvantages of using Thread class to create a thread.

  7. What is the thread life cycle or Different thread states in Java?

    Once you create a thread in Java a thread can be in one of the following states-

    • NEW- A thread in Java is in new state when it is created but not yet started
    • RUNNABLE- A thread transitions to a runnable state when start() method is called on the thread object.
    • BLOCKED- A running thread can change state to blocked state and become temporarily inactive when it is waiting for a monitor lock.
    • WAITING- A running thread may move to waiting state by calling either Object.wait() or Thread.join() method.
    • TIMED_WAITING- A thread is in timed waiting state when it calls sleep, wait or join method with a timed out parameter.
    • TERMINATED- A thread that has completed execution goes into terminated state.

    Read more about thread cycle in Java here.

  8. How can you get thread state in Java code?

    You can get thread state in Java by calling getState() method on the thread instance which returns a Thread.State enum.

    Read more about different thread states in Java here.

  9. What is thread priority in Java?

    Every thread in Java has a priority assigned to it. When you create a thread in Java it inherits the priority of the thread that created it.

    In a multi-threaded environment, the order in which threads will get CPU cycle is decided by the thread scheduler and it uses thread priority to decide that order.

    Read more about different thread priorities in Java here.

  10. What is the thread priority range in Java?

    Java thread priority is in the range 1 to 10 where 1 being the lowest and 10 being the highest thread priority in Java. In Java Thread class there are three static int fields defining min, max and default priority of a thread.

    • MAX_PRIORITY– The maximum priority that a thread can have. Its value is 10.
    • MIN_PRIORITY– The minimum priority that a thread can have. Value of this field is 1.
    • NORM_PRIORITY– The default priority that is assigned to a thread. Its value is 5.

    Read more about different thread priorities in Java here.

  11. How to change the thread's priority and check the thread's priority in Java?

    Thread’s priority can be changed at any time after its creation using the setPriority() method of the Thread class. If you want to check the thread’s priority you can check it using getPriority() method of the Thread class.

  12. When you start any Java application which is the first thread to start?

    When a Java program starts one thread starts running immediately that thread is known as main thread in Java.

    Additional threads spawned in your program will inherit some of the properties from the main thread like thread priority, created thread is a daemon thread or not.

    Read more about main thread in Java here.

  13. What is a daemon thread in Java?

    Daemon thread in Java is a thread that runs in background to perform some tasks for the program as long as the program is running.

    Read more about daemon thread in Java here.

  14. How is daemon thread created in Java?

    Any thread created by a daemon thread is automatically a daemon thread.If you want to mark a thread as a daemon thread that can be done using setDaemon(boolean on) method of the Thread class in Java. By calling setDaemon(true); on a thread instance you can make that thread a daemon thread.

    Read more about daemon thread in Java here.

  15. Is it possible to start a thread twice in Java?

    A Thread can only be started once, trying to start the same thread again in Java will throw IllegalThreadStateException.

    Read more about can we start a thread twice in Java here.

  16. What if run() method of the thread is called directly instead of calling start() method?

    If run method is called directly on a thread then no new thread will actually be started. The logic you have written in the run() method will be executed with in the context of the current thread.

    Read more about Can we directly call run() method instead of calling start() method in Java here.

  17. Can we override the start() method in Java?

    Yes start() method can be overridden in Java if you have some logic to be executed before calling the run() method.

    One condition is that you should always call super.start() method from your overridden start() method. Failing to call super.start() will mean run() method won’t be called.

    Read more about Can we override start() method in Java here.

  18. What is context switching in multi-threading?

    Context switching in terms of multi-threading is the switching of CPU from one thread to another.

    When a thread is preempted to execute another thread, thread state of the preempted thread has to be stored where as the thread which is getting executed has to restore its state.

  19. How does inter-thread communication happens in Java multi-threading?

    In Java multi-threading there are 3 methods for facilitating communication among multiple threads.

    • wait() method- wait() method causes the current thread, holding the object's lock, to place itself into waiting state.
    • notify() method- Wakes up a single thread that is waiting on this object’s monitor.
    • notifyAll() method- Wakes up all threads that are waiting on this object’s monitor rather than a single thread.

    Read more about wait(), notify() and notifyAll() methods in Java here.

  20. What is a spurious wakeup?

    A waiting thread can wake up without being notified, interrupted, or timing out this is known as spurious wakeup. Applications must guard against it by putting a call to wait() within a loop that checks the condition on which the thread is waiting.

    synchronized (obj) {
      while ( and ) {
        long timeout = ... ; // recompute timeout values
        int nanos = ... ;
        obj.wait(timeout, nanos);
      }
      ... // Perform action appropriate to condition or timeout
    }
    
  21. Write Producer-consumer program in Java using wait-notify methods.

    See Producer-consumer program in Java using wait-notify methods here.

  22. Why wait(), notify() and notifyAll() methods are in Object class?

    These methods wait(), notify() and notifyAll() work with the lock (monitor) which is associated with the object. The object whose lock is held is used for the communication among the threads.

    That's why wait(), notify() and notifyAll() methods are in Object class.

    See detailed explanation of Why wait(), notify() and notifyAll() methods are in Object class here.

  23. why wait(), notify() and notifyAll() methods in Java must be called from a synchronized method or block?

    wait() method causes the current thread to give up monitor and go into waiting state. Thread acquires Object's lock only when it is executing in a synchronized context. That is why wait() method has to be used only in synchronized context.When object's notify() or notifyAll() method is called it is a signal for a single thread or all the threads to wake up and contend for the monitor. So notify and notifyAll methods can only be called from a place where the thread is leaving the lock on the object and again that place is synchronized method or block.

    See detailed explanation of why wait(), notify() and notifyAll() methods in Java must be called from a synchronized method or block here.

  24. What does synchronized keyword in Java do?

    In a multi-threaded environment if you have a critical section in you code where you are modifying a shared resource you would like the access to that critical section restricted so that at any given time only a single thread can access the critical section code and use the shared resource. The process by which you can achieve this is called synchronization in Java and you will use synchronized keyword in Java for synchronization.

    Read more about synchronized keyword in Java here.

  25. How does synchronization in Java works?

    Every object in Java has a single lock (also called monitor) associated with it. When a thread enters a synchronized method or synchronized block it acquires that lock. All other threads attempting to execute the same code (in synchronized method or synchronized block) have to wait for the first thread to finish and release the lock.

    Read more about how synchronization works in Java here.

  26. What is synchronized statement or synchronized block in Java?

    Rather than synchronizing the whole method you can only synchronize the statements (critical section) in the method that are modifying the shared resource. That helps in improving the performance as threads can only execute the code with in synchronized context sequentially. By minimizing the code with in synchronized context you reduce the possibility of sequential execution of the threads.

    Read more about synchronized block in Java here.

  27. What is static synchronization in Java?

    If there are more than one object of the same class then two separate threads can acquire locks of these two objects and enter the synchronized method or synchronized block with those separate locks at the same time. If that is not what you want then you need static synchronization in Java where synchronization happens at the class level not at instance level.

    Read more about static synchronization in Java here.

  28. How can you ensure that you start execution of the main thread only after execution of the other threads started from the main thread finishes?

    That can be done by calling join() method on the threads that are started.

    join() method waits until the thread on which it is called terminates.

    Read more about join() method in Java here.

  29. How can you check if the thread is still alive or not?

    By using isAlive() method. This method tests if this thread is alive. Method returns true if thread is alive otherwise it returns false.

    Read more about isAlive() method in Java here.

  30. What is thread group in Java?

    All threads in Java belong to a thread group. When a thread is created it is put into a thread group specified either by you or to the same group as the thread that created it if no thread group is explicitly specified.

    When the main thread is started for the Java application, it is put into a group called main.

    Read more about thread group in Java here.

  31. How can you interrupt a thread?

    In Java Thread class there is a method interrupt() which interrupts the calling thread.

    Read more about thread interruption in Java here.

  32. How can you pause a running thread?

    You can pause a running thread by using sleep() method. Thread.sleep method in Java causes the currently executing thread to suspend execution for a specified period.

    Read more about sleep method in Java here.

  33. If sleep() method is called with in the synchronized context does the sleeping thread release the lock?

    No the lock held by the thread is not released.

  34. What is race condition in multi-threading?

    Race condition in Java may occur when two or more threads try to access a shared object. If all the threads are just reading a shared object that poses no problem but modifying or writing a value may lead to incorrect results because of race condition.

    Read more about race condition in Java here.

  35. How to avoid race condition in Java?

    You need to restrict access to the critical section for that you can synchronize the access to the critical section by using synchronized method or block. You can also use implementations of lock provided in concurrency package.

    Read more about race condition in Java here.

  36. What is deadlock in multi-threading?

    In a multi-threaded environment there may come a situation when one thread is waiting for a resource that is locked by another thread, which in turn is waiting for another thread and so on until this dependency loops back to the first waiting thread. Thus all the threads are waiting for each other to release the resources to make any further progress and blocked forever in the process. This scenario is called deadlock in multi-threading.

    Read more about deadlock in Java here.

  37. Write a Java program to create deadlock?

    See a Java program to create deadlock here.

  38. How to detect deadlock in Java or How to get thread dump in Java?

    For detecting deadlock in your code you can get a thread dump of the application and analyze it.

    You can use jstack utility to get a thread dump by providing the pid of the Java application. That pid can be obtained by running jps command.

    See example of getting a thread dump and analyzing it for deadlock here.

  39. What is yield() method in Java?

    yield() method is just a hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler can ignore this hint too.

    Read more about yield() method in Java here.

  40. What is ThreadLocal class in Java?

    ThreadLocal class in Java provides thread local variables where each thread has its own, independently initialized copy of the variable.

    That way you can avoid sharing of data and avoid using synchronization.

    Read more about ThreadLocal class in Java here.

  41. What is volatile keyword in Java?

    Declaring a variable as volatile ensures that value of the variable is always read from the main memory and not cached. This ensures that thread don't have a stale value cached by the processor and always get the correct value from the main memory.

    Read more about volatile keyword in Java here.

  42. What is thread starvation in multi-threading?

    If a thread is unable to gain regular access to shared resources and is unable to make progress it is called thread starvation in multi-threading.

    There may be a scenario that other threads are gaining access to the synchronized method or block by getting the monitor where as few threads are not able to get the lock thus the access to shared resource.

    Read more about thread starvation in Java here.

  43. What is livelock in multi-threading?

    If two or more threads are busy responding to the action of each other and unable to make further progress in the process that is known as livelock in multi-threading.

    In case of livelock threads are not blocked as in the case of deadlock. Threads are active but they are busy responding to each other thus not making any progress.

    Read more about livelock in Java here.

That's all for the topic Java Multithreading Interview Questions And Answers. If something is missing or you have something to share about the topic please write a comment.


You may also like

HashSet Vs LinkedHashSet Vs TreeSet in Java

If you have to store only unique elements i.e no duplicates in your Java application you’d probably choose to use one of the Set implementation in Java; HashSet, TreeSet or LinkedHashSet. Though all these Set implementations store unique elements but they do differ on the points like ordering of elements, performance they offer, null value permitted or not. In this post we’ll see the differences among HashSet, LinkedHashSet and TreeSet in Java which will help you to decide which Set implementation serves your purpose in a better way.

HashSet Vs LinkedHashSet Vs TreeSet in Java

1- Ordering of the Element-

HashSet- HashSet is an unordered collection. Element is stored based on the hash value calculated for the element.

LinkedHashSet- In LinkedHashSet insertion order of the elements is maintained.

TreeSet- TreeSet stores its element in sorted order. By default elements are sorted in natural ordering but you can provide a Comparator if you want different ordering.

2- Internal implementation-

HashSet- Internally HashSet uses a HashMap to store is element.

LinkedHashSet- Internally LinkedHashSet is backed by a LinkedHashMap instance.

TreeSet- Internally TreeSet uses a TreeMap to store its elements.

3- Permitting null value-

HashSet- HashSet allows one null value.

LinkedHashSet- LinkedHashSet allows one null value.

TreeSet- In TreeSet null is not permitted. NullPointerException is thrown if you try to add null to a TreeSet.

4- Element comparison-

HashSet- In order to compare elements so that no duplicate elements are added HashSet uses equals() and hashCode() methods.

LinkedHashSet- LinkedHashSet also uses equals() and hashCode() methods.

TreeSet- TreeSet instance performs all element comparisons using its compareTo (or compare) method.

5- Performance-

HashSet- HashSet is the fastest among the three as it doesn’t have the added functionality of maintaining insertion order or sorting. HashSet offers constant time performance O(1) for the basic operations like add, remove, contains and size assuming the hash function disperses the elements properly among the buckets. If HashCode is not proper and the elements are not dispersed properly then the performance may degrade to O(n) in worst case.

LinkedHashSet- Performance of LinkedHashSet is just slightly below that of HashSet. It is because of the fact that LinkedHashSet maintains a doubly linked list running through all of its entries. This linked list defines the iteration ordering.

TreeSet- TreeSet is slow as it has to keep its element sorted. It uses a tree based structure for the same and because of that TreeSet provides guaranteed log(n) time cost for the basic operations (add, remove and contains).

That's all for the topic HashSet Vs LinkedHashSet Vs TreeSet in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

UEFI Compatibilty for Ubuntu Installation

UEFI (Unified Extensible Firmware Interface) is a firmware, just like BIOS, that starts when you switch on your PC before booting the Operating System. UEFI is getting traction now and recent systems come with UEFI. It is developed as a replacement to traditional BIOS and provides support for-

  1. Using larger disks (over 2 TB)
  2. CPU independent architecture
  3. Faster boot time (UEFI switched to Boot Manager rather than using boot sector as used by BIOS).

This post is more about checking UEFI compatibility for Windows and Ubuntu dual boot system and why and when to use UEFI mode.

Which mode to use while installing Ubuntu

Most of the current computers provide support for both UEFI and BIOS mode, which boot mode should be used depends on following factors-

  1. Matching boot mode for dual boot– If you are installing Ubuntu as dual boot with another OS then the boot mode should match for both Operating Systems.
    As Example– If you are installing Ubuntu on a system where Windows is already installed, you can check the boot mode for Windows. One of the way to check that is as follows -Go to RUN dialog and type msinfo32, press enter. For System Summary look for “BIOS Mode” in the right pane. Check for its value if it is “UEFI” or “Legacy”
  2. Hardware support– Some hardware devices are better supported in one mode than another. But UEFI is the future and now mostly UEFI support is there so that is not a big problem going forward.

UEFI mode or not

While installing Ubuntu you may want to go with UEFI mode when you are single booting, as UEFI is the way going forward and latest Ubuntu versions (After 11.10) come with UEFI support or you are dual booting with another operating system which is already installed in this mode.

  1. If you have another operating system in your system (Winodws 8, 10, Linux) already installed in UEFI mode then you must install Ubuntu in that mode too.
  2. If your system has another OS which is installed in legacy (non-UEFI) mode then you must install Ubuntu in legacy mode too. It may be because your system is old, still running on pre-installed Windows XP, is 32 bits.
  3. If Ubuntu is going to be the only Operating System in your computer then you can opt for any mode but better to go with UEFI mode if you have a computer that supports it.

Things to keep in mind

When you are installing Ubuntu in UEFi mode some of the things you need to keep in mind are as follows-

  1. Use a 64 bit version of Ubuntu as Ubuntu 32 bit can’t be easily installed in UEFI mode.
  2. You may require to disable fast startup and SecureBoot in the already installed Windows.
  3. Make sure you are using a UEFI supported version of Ubuntu. Latest versions have that support anyway so that shouldn’t be a problem. Just to make sure support for UEFI appeared in Ubuntu 11.10.
  4. If you are creating an installable USB/CD to boot through that make sure you use “EFI only image”.
  5. At startup make sure to change the boot option to boot in UEFI mode.
  6. When installation begins if you choose the option to manual partition (“Something else”) you can verify that one EFI System partition (ESP) exists. If you already have Windows installed just check the type of the partitions one of those should have type as “efi”.

Referencehttps://help.ubuntu.com/community/UEFI

That's all for the topic UEFI Compatibilty for Ubuntu Installation. If something is missing or you have something to share about the topic please write a comment.

You may also like

How to Create Bootable USB Drive For Installing Ubuntu

In this tutorial you'll learn how to create bootable USB drive for installing Ubuntu using Rufus tool. In this post the bootable USB drive is created on Windows OS.

Why do you need bootable USB Drive

You will need a bootable USB stick to-

  1. Install or upgrade Ubuntu.
  2. Boot into Ubuntu without actually installing it on the system.
  3. Use this bootable USB stick to repair the corrupt installation.

What do you need to create a bootable USB drive

In order to create a bootable USB drive you will need-

  1. A USB drive with at least 2 GB capacity (because you will have to store the Ubuntu iso image in the USB and size of iso image is around 1.5 GB).
  2. Windows XP or later OS (This post is created using Windows 10).
  3. Rufus tool that helps to format and create bootable USB stick. You can download it from https://rufus.akeo.ie/
  4. Of course an Ubuntu iso file. You can download it from here https://www.ubuntu.com/download. For this post image used is ubuntu-16.04.3 iso image.

Creating bootable USB drive

Once you have downloaded Ubuntu image and Rufus, it is time to create the bootable USB drive.

So launch Rufus and insert the USB stick. Rufus will identify the USB and update the device drop down to show it. If device is not correctly identified you can change it manually to point to the correct device.

For "partition scheme and target system type" drop down select "MBR partition scheme for UEFI" option if you have a newer hardware with UEFI. Alternatively you can select "MBR partition scheme for BIOS or UEFI".

For selecting the downloaded Ubuntu iso image click on the optical device symbol which is on the right side of the check box option “create a bootable disk using”. Select the downloaded Ubuntu iso image.

Rufus bootable USB ubuntu

Leave all the other options with their default values and click start button to initiate write process.

That will open “ISO Hybrid image detected” window. ISO hybrid image means that the same image can be used as the source for both a DVD and a USB stick without requiring any conversion.

rufus USB bootable

Keep the selected option "Write in ISO Image mode" and click on OK to continue.

You will get a warning that all data on the device will be lost. So make sure that selected device is correct and click ok. That will start the process of writing the ISO to your USB stick. Once the installation is completed you will have a bootable Ubuntu on a USB drive.

Reference: https://tutorials.ubuntu.com/tutorial/tutorial-create-a-usb-stick-on-windows#0

That's all for the topic How to Create Bootable USB Drive For Installing Ubuntu. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 29, 2022

JDBC Transaction Management and Savepoint Example

In this post we’ll see how to manage a transaction using JDBC in a Java application.

A transaction represents a single unit of work where a set of one or more statements are executed as a unit. In a transaction either all of the statements are executed successfully or none of them.

Transaction in JDBC

In JDBC API, the Connection interface provides the following methods for transaction management-

  • setAutoCommit()- In JDBC by default a connection is in auto-commit mode which means all its SQL statements will be executed and committed as individual transactions. So, first thing is to set auto-commit mode to false so that SQL statements are grouped into transactions and executed as a single unit of work.
  • commit()- This method makes all changes made with in the transaction permanent. Also releases any database locks currently held by this Connection object.
  • rollback()- This method is used to undo all changes made in the current transaction if any of the statement fails. Also releases any database locks currently held by this Connection object.

Using these methods the transaction steps in JDBC can be summarized as-

  1. To start a transaction set auto-commit mode to false by calling setAutoCommit(false) method.
  2. If all the statements with in the transaction execute with any error make the changes permanent by calling commit() method.
  3. If any statement doesn’t execute properly abort the transaction by rolling back all the changes done as part of transaction.
  4. You can also set save point in transaction and roll back to particular save point that gives you an option to salvage some of the work being done in a transaction rather than losing it all.

Method for setting transaction isolation level

You can also set the transaction isolation level using the Connection object. Connection interface defines following constants for different transaction isolation levels.

  • TRANSACTION_NONE- Indicates that transactions are not supported.
  • TRANSACTION_READ_UNCOMMITTED- Indicates that dirty reads, non-repeatable reads and phantom reads can occur.
  • TRANSACTION_READ_COMMITTED- Indicates that dirty reads are prevented; non-repeatable reads and phantom reads can occur.
  • TRANSACTION_REPEATABLE_READ- Indicates that dirty reads and non-repeatable reads are prevented; phantom reads can occur.
  • TRANSACTION_SERIALIZABLE- Indicates that dirty reads, non-repeatable reads and phantom reads are prevented.

You can pass any of these constants in the setTransactionIsolation(int level) method to set the required isolation level.

For example you want to set the transaction isolation level to read uncommitted.

connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);

JDBC transaction management example

Let’s take an example of transferring amount from one account to another that involves both of the following steps to be executed or none of them.

  1. Withdraw amount from the sender’s account.
  2. Deposit amount into the beneficiary’s account.

For the example Account table is used with the columns as acct_num, name, balance.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCTransactionDemo {
  public static void main(String[] args) {
    Connection connection = null;
    try {
      // Connection info
      Class.forName("com.mysql.cj.jdbc.Driver");
      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/knpcode", "root", "admin");
      // Auto commit disabled
      connection.setAutoCommit(false);
      
      int fromAccount = 2;
      int toAccount = 7;
      int amount = 200;
      withdrawAmount(connection, fromAccount, amount);
      depositAmount(connection, toAccount, amount);
      // Commit transaction
      connection.commit();
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }catch(SQLException e) {
      e.printStackTrace();
      if(connection != null){
        try {
          // Rolling back transaction
          connection.rollback();
        } catch (SQLException e1) {
          // TODO Auto-generated catch block
          e1.printStackTrace();
        }
      }
    }finally{
      if(connection != null){         
        try {
          connection.close();
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } 
    }	
  }
  
  private static void withdrawAmount(Connection connection, int accountNum, int amount) throws SQLException{
    String sql = "UPDATE ACCOUNT SET balance = balance - ? WHERE acct_num = ?";
    PreparedStatement stmt = null;
    try {
      stmt = connection.prepareStatement(sql);
      stmt.setInt(1, amount);
      stmt.setInt(2, accountNum);
      int count = stmt.executeUpdate();
      if(count == 0){
        throw new SQLException("Account number not found " + accountNum);
      }
    }finally{
      if(stmt != null){
        stmt.close();
      }
    }
  }	 
  
  private static void depositAmount(Connection connection, int accountNum, int amount) throws SQLException{
    String sql = "UPDATE ACCOUNT SET balance = balance + ? WHERE acct_num = ?";
    PreparedStatement stmt = null;
    try {
      stmt = connection.prepareStatement(sql);
      stmt.setInt(1, amount);
      stmt.setInt(2, accountNum);
      int count = stmt.executeUpdate();
      if(count == 0){
        throw new SQLException("Account number not found " + accountNum);
      }
    }finally{
      if(stmt != null){
        stmt.close();
      }
    }    
  }
}

Savepoint in JDBC transaction

Using a Savepoint object you can mark a point in current transaction. When a transaction is rolled back to a savepoint all changes made after that savepoint are undone where as the changes made till the savepoint can be committed. If you have lots of statements in your transaction and you don’t want to loose all of the work if something fails you can set savepoints at intervals to get a chance to commit your work at least till that savepoint.

Connection interface provides two overloaded methods for setting savepoint-

  • setSavepoint()- Creates an unnamed savepoint in the current transaction and returns the created Savepoint object.
  • setSavepoint(String name)- Creates a savepoint with the given name in the current transaction and returns the created Savepoint object.

There is also a method for releasing a savepoint.

  • releaseSavepoint?(Savepoint savepoint)- Removes the specified Savepoint from the current transaction.

Setting savepoint in JDBC transaction example

In the example few records are inserted in a transaction and a savepoint is created after few insertions so that we have a chance to insert records till there in case of rollback.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;

public class SavePointDemo {
  public static void main(String[] args) {
    Connection connection = null;
    Savepoint sp = null;
    try {
      // Load driver
      Class.forName("com.mysql.cj.jdbc.Driver");
      // connection object
      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/knpcode", "root", "admin");
      SavePointDemo sd = new SavePointDemo();
      
      // Auto commit disabled
      connection.setAutoCommit(false);

      sd.insertEmployee(connection, "Don", "Keaton", "HR");
      sd.insertEmployee(connection, "Virag", "Sharma", "IT");
      // Setting named savepoint
      sp = connection.setSavepoint("MySavePoint");
      sd.insertEmployee(connection, "Kelly", "Dorji", "IT");
      // Commit transaction
      connection.commit();
    } catch (ClassNotFoundException e) {
    	// TODO Auto-generated catch block
        e.printStackTrace();
    }catch(SQLException e) {
      e.printStackTrace();
      if(connection != null){
        try {
          // savepoint is not reached, rollback the whole transaction
          if(sp == null){
            System.out.println("Rollingback the transaction");
            connection.rollback();
          }else{
            System.out.println("Rollingback to savepoint");
            // rollback to created savepoint
            connection.rollback(sp);
            // Commit till the savepoint
            connection.commit();
          }
        } catch (SQLException e1) {
          // TODO Auto-generated catch block
          e1.printStackTrace();
        }
      }
    }finally{
      if(connection != null){         
        try {
          connection.close();
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } 
    }	      	     
  }

  private void insertEmployee(Connection connection, String fName, String lName, String dept) throws SQLException{
    String insertSQL = "INSERT INTO EMPLOYEE (FIRST_NAME, LAST_NAME, DEPARTMENT) values (?, ?, ?)";
    PreparedStatement prepStmt = null;
    try {
      prepStmt = connection.prepareStatement(insertSQL);
      prepStmt.setString(1, fName);
      prepStmt.setString(2, lName);
      prepStmt.setString(3, dept);
      int count = prepStmt.executeUpdate();
      System.out.println("Number of records inserted- " + count);
    }finally{
      if(prepStmt != null){
        prepStmt.close();
      }
    }
  }
}

That's all for the topic JDBC Transaction Management and Savepoint Example. If something is missing or you have something to share about the topic please write a comment.


You may also like

Serialization Proxy Pattern -readResolve() and writeReplace()

In this post we’ll discuss the Serialization proxy pattern which is a more secure way to serialize an object by serializing a proxy object instead.

Need for serialization proxy pattern

Serialization in Java do have some problems like-

  1. You don’t have much control over the whole serialization process. Changing the class over time also causes compatibility problem with the serialized objects.
  2. In serialization actual object is serialized which increases the security risk. Any attacker can reconstruct a real object from the serialized state or change the stream to manipulate the object data.

With serialization proxy pattern you can secure the serialization process. Rather than the actual object a proxy object is serialized. To get a proxy object you need to create a static inner class with in a real class which also implements Serializable interface and have the same fields as the actual class.

readResolve() and writeReplace() methods in Java

You need to implement two methods readResolve() and writeReplace() for correctly implementing serialization proxy pattern.

writeReplace()- This method is implemented by the Serializable class that want to write a proxy object to the stream.

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

readResolve()- Classes that need to return a replacement when an instance of it is read from the stream should implement this method. When proxy object is read from the stream then an actual object has to be returned in Serialization proxy pattern so this method has to be implemented in the proxy class.

ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

Serialization proxy pattern Java example

Here is a class whose object has to serialized using Serialization proxy pattern so it will have a static inner class and readResolve() and writeReplace() methods are implemented too.

import java.io.Serializable;

public class Employee implements Serializable{
  private static final long serialVersionUID = -8690951276691191306L;
  private String name;
  private String dept;
  private int salary;
  private int age;
  Employee(String name, String dept, int salary, int age){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.age = age;
  }
	
  //writeReplace method for the proxy pattern	
  private Object writeReplace() {
    System.out.println("In writeReplace() method");
    return new EmployeeProxy(this);
  }

  private void readObject(ObjectInputStream ois) throws InvalidObjectException{
    throw new InvalidObjectException("Use proxy class");
  }

  private static class EmployeeProxy implements Serializable{
    private String name;
    private String dept;
    private int salary;
    private int age;
    EmployeeProxy(Employee emp){
      this.name = emp.name;
      this.dept = emp.dept;
      this.salary = emp.salary;
      this.age = emp.age;
    }
    // readResolve method in Proxy class
    private Object readResolve() {
      System.out.println("In readResolve() method");
      return new Employee(name, dept, salary, age);
    } 
  }	
  // setters and getters
}

Some important points you should notice in this class are-

  1. EmployeeProxy class is defined as a static inner class. Proxy class also implements Serializable interface.
  2. Constructor of the EmployeeProxy class takes Employee object as argument and creates a proxy object using it. While creating proxy object if need be you can also encrypt data to make it more secure.
  3. Employee class implements writeReplace() method that returns an instance of proxy class.
  4. EmployeeProxy class implements readResolve() method and return Employee object.
  5. As an added precaution also implement readObject() method to throw an exception. With that there is no chance to fabricate Employee object from the stream.

Here is a class with methods to Serialize and deserialize an object.

public class SerializationDemo {

  public static void main(String[] args) {
    Employee emp = new Employee("Ryan", "IT", 7500, 35);
    final String fileName = "F:\\knpcode\\emp.ser";
    serialzeObject(emp, fileName);
    
    /// Do null check here
    Employee e = (Employee)deSerializeObject(fileName);
    System.out.println("Name- " + e.getName());
    System.out.println("Dept- " + e.getDept());
    System.out.println("Salary- " + e.getSalary());
    System.out.println("Age- " + e.getAge());
  }	
	
  // Method to serialize object 
  public static void serialzeObject(Object obj, String fileName) { 
    try(ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(fileName))){
      outStream.writeObject(obj); 
    } catch (IOException e) { 
      // TODO Auto-generated
      e.printStackTrace(); 
    } 
  }
	 	
  // Method to deserialize object
  public static Object deSerializeObject(String fileName){
    Object obj = null;
    try(ObjectInputStream inStream = new ObjectInputStream(new FileInputStream(fileName))){
      obj = inStream.readObject();	 			
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      System.out.println("No class found for serialization");
      e.printStackTrace();
    }
    return obj;
  }
}
Output
In writeReplace() method to serialize proxy
In readResolve() method to get actual object
Name- Ryan
Dept- IT
Salary- 7500
Age- 35

That's all for the topic Serialization Proxy Pattern -readResolve() and writeReplace(). If something is missing or you have something to share about the topic please write a comment.


You may also like

Versioning Using serialVersionUID in Java

When a class implements a Serializable interface you would have noticed this warning “The serializable class xxxx does not declare a static final serialVersionUID field of type long”. In this post we’ll see what is this serialVersionUID field and what is its significance with respect to serialization in Java.

InvalidClassException in Java Serialization

To understand the use of serialVersionUID first you’ll have to understand what happens when it is not assigned explicitly.

You have a class that implements Serializable and a class object has been written out to an object stream. While this object is still persisted you make some changes to the class by adding a new field or method. What happens now when you deserialize the serialized object.

It will throw java.io.InvalidClassException because of the changes made to the class.

For example take the following Employee class that implements Serializable interface.

public class Employee implements Serializable{
  private String name;
  private String dept;
  private int salary;
  private transient int ssn;
  Employee(String name, String dept, int salary, int ssn){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.ssn = ssn;
  }
}
Its is serialized using the following class-
public class SerializationDemo {

  public static void main(String[] args) {
    Employee emp = new Employee("Ryan", "IT", 7500, 11111);
    final String fileName = "F:\\knpcode\\emp.ser";
    serialzeObject(emp, fileName);
  }
	
  // Method to serialize object 
  public static void serialzeObject(Object obj, String fileName) { 
    try(ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(fileName))){
      outStream.writeObject(obj); 
    } catch (IOException e) { 
      // TODO Auto-generated
      e.printStackTrace(); 
    } 
  }
}

Once an object is already serialized and persisted to the emp.ser file Employee class is changed to add a new field age.

public class Employee implements Serializable{
  private String name;
  private String dept;
  private int salary;
  private transient int ssn;
  //new field
  private int age;
  Employee(String name, String dept, int salary, int ssn){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.ssn = ssn;
  }
}

Now when you try to deserialize the already persisted object-

public class SerializationDemo {

  public static void main(String[] args) {
    final String fileName = "F:\\knpcode\\emp.ser";
    /// Do null check here
    Employee e = (Employee)deSerializeObject(fileName);
    System.out.println("Name- " + e.getName());
    System.out.println("Dept- " + e.getDept());
    System.out.println("Salary- " + e.getSalary());
    System.out.println("SSN- " + e.getSsn());
  }
	
  // Method to deserialize object
  public static Object deSerializeObject(String fileName){
    Object obj = null;
    try(ObjectInputStream inStream = new ObjectInputStream(new FileInputStream(fileName))){
      obj = inStream.readObject();	 			
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      System.out.println("No class found for serialization");
      e.printStackTrace();
    }
    return obj;
  }
}

Exception is thrown-

java.io.InvalidClassException: com.knpcode.proj.Programs.Employee; local class incompatible: stream classdesc serialVersionUID = -3183131693238108702, local class serialVersionUID = 7612606573038921492
	at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
	at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
	at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
	at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
	at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
	at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
	at com.knpcode.proj.Programs.SerializationDemo.deSerializeObject(SerializationDemo.java:39)
	at com.knpcode.proj.Programs.SerializationDemo.main(SerializationDemo.java:16)

If you notice the stack trace there is a message-

local class incompatible: stream classdesc serialVersionUID = -3183131693238108702, local class serialVersionUID = 7612606573038921492

Clearly object when serialized and the class which it refers to are not compatible any more and the serialVersionUID of the serialized object and the changed class differ. Now, the question is who assigns this ID?

Version control using serialVersionUID

Classes that implement Serializable interface are automatically given a unique identifier. If the identifier of the class does not equal the identifier of the serialized object, the exception will be thrown.

What if you want to control that default action so that exception is not thrown for changes in the class but default values are used instead for the newly added fields? That’s where serialVersionUID comes handy.

Unique identifier that is part of all classes is maintained in a field called serialVersionUID. If you want to control class versioning you will have to assign serialVersionUID yourself. Then the ID remains same pre and post serialization.

When you assign serialVersionUID yourself you have the flexibility of controlling class versioning.

  • If you don't change the serialVersionUID after updating the class then object deserialization happens with out throwing any exception.
  • If you think that the changes made to the class are significant then you can change the serialVersionUID assigned to the class. Because of the non-matching serialVersionUID, InvalidClassException will be thrown now.

IDE like Eclipse gives you an option to generate serialVersionUID or you can use serialver utility that comes with the JDK distribution to generate serialVersionUID.

For example generating serialVersionUID for com.knpcode.proj.Programs.Employee using serialver utility class.

F:\Anshu\NetJs\Programs\target\classes>serialver com.knpcode.proj.Programs.Employee
com.knpcode.proj.Programs.Employee:    private static final long serialVersionUID = 7612606573038921492L;

serialVersionUID Java example

In the previous example we already used the Employee class now serialVersionUID is added to the class using the "Add generated serial version id" option in Eclipse IDE.

public class Employee implements Serializable{
  private static final long serialVersionUID = 7612606573038921492L;
  private String name;
  private String dept;
  private int salary;
  private transient int ssn;
  Employee(String name, String dept, int salary, int ssn){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.ssn = ssn;
  }
}

With serialVersionUID added, now if you follow the same tasks of serializing an object then changing the class by adding a new field (but not changing the added serialVersionUID) and then deserializing the object, you should get the default value for the new field rather than getting an exception.

Name- Ryan
Dept- IT
Salary- 7500
SSN- 0

That's all for the topic Versioning Using serialVersionUID in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

Remove Spaces From a String in Java - trim(), strip()

In this post you’ll learn how to remove spaces from a String in Java, the spaces may be leading spaces, trailing spaces or spaces in between the words. String class provides following options for removing String spaces in Java.

  • If you want to remove spaces at the beginning (leading spaces) and spaces at the end (trailing spaces) best way to do it is to use trim() method of the Java String class. As per trim() method space is defined as any character whose codepoint is less than or equal to 'U+0020' (the space character).
  • Java 11 onward there is also strip() method in Java String class for removing leading and trailing white spaces. This method internally uses the Character.isWhitespace() to check for whitepsaces. There are two more methods for removing either leading spaces or trailing spaces.

    If you want to remove only trailing white spaces then you can use-

    • stripLeading()- To remove all leading white spaces. Available Java 11 onward.

    If you want to remove only leading white spaces then you can use-

    • stripTrailing()- To remove all trailing white spaces. Available Java 11 onward.
  • Another option is to use replaceAll() method of the Java String class, passing regex ‘\\s+’ as an argument for removing spaces. This option removes spaces in between the words too apart from leading and trailing spaces.

One thing to remember here is that whenever string is modified in anyway a new String is created as String is immutable in Java, so you need to assign the modified string to a String reference.

Removing spaces using trim() method Java example

  • trim()- Returns a string whose value is this string, with all leading and trailing space removed, where space is defined as any character whose codepoint is less than or equal to 'U+0020' (the space character).
public class StringSpaces {
  public static void main(String[] args) {	
    String str = "  Hello    World		";
    str = str.trim();
    System.out.println("String- " + str);
  }
}
Output
String- Hello    World

As you can see leading and trailing spaces are removed though not the spaces in between the words.

Removing spaces using strip() method Java example

Java 11 onward there is also a strip() method in Java to remove leading and trailing spaces from a String. strip() method internally uses Character.isWhitespace() to check for white spaces which provides a much wider definition of whitespaces than trim(). In trim() space is defined as any character whose codepoint is less than or equal to 'U+0020' (the space character).

Let’s try to clarify it with an example where a unicode character '\u2002' is used which is not recognized by trim() method.

public class StringSpaces {
  public static void main(String[] args) {
    String str = '\u2002'+"Hello World!"+ '\u2002';
    System.out.println("String-" + str);
    str = str.trim();
    System.out.println("String-" + str);
  }
}
Output
String- Hello World!
String- Hello World!

You can see that the leading and trailing spaces are not removed by the trim() method as unicode character greater than '\u0020' is used. Using strip() method you can remove these spaces.

public class StringSpaces {
  public static void main(String[] args) {
    String str = '\u2002'+"Hello World!"+ '\u2002';
    System.out.println("String-" + str);
    str = str.strip();
    System.out.println("String-" + str);
  }
}
Output
String- Hello World!
String-Hello World!

Removing spaces using replaceAll() method Java example

If you have to remove spaces in between the words too apart from leading and trailing spaces then replaceAll() method can be used.

  • replaceAll(String regex, String replacement)- Replaces each substring of this string that matches the given regular expression with the given replacement.

By passing "\\s+" as regex which matches one or many whitespaces and "" as replacement for those whitespaces you can remove all whitespaces from a String.

public class StringSpaces {
  public static void main(String[] args) {	
    String str = "  Hello    World		";
    str = str.replaceAll("\\s+", "");
    System.out.println("String- " + str);
  }
}
Output
String- Hello World!
String- HelloWorld

That's all for the topic Remove Spaces From a String in Java - trim(), strip() Methods. If something is missing or you have something to share about the topic please write a comment.


You may also like

Compare Two Strings in Java - equals, compareTo() methods

If you have to compare two Strings in Java or the portion of two Strings on the basis of the content of those Strings then you can do it using one of the following methods-

  1. equals() method or equalsIgnoreCase() if you don’t want to consider case. See example.
  2. compareTo() method or compareToIgnoreCase() if you don’t want to consider case. See example.
  3. For comparing portion of the String you can use startsWith() and endsWith() methods. See example.
  4. To compare region of one String with the specified region of another String you can use regionMatches() method. See example.

Compare Strings using equals() and equalsIgnoreCase() methods

  • boolean equals(Object anObject)- Compares this string to the specified object. This method returns true if the passed argument is not null and is a String object having the same sequence of characters as this String.
  • boolean equalsIgnoreCase(String anotherString)- Compares this String to another String, ignoring case considerations. Two strings are considered equal (ignoring case) if they are of the same length and corresponding characters in the two strings are equal.
Java example using equals() method
public class StringComapre {
  public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = "Hello";
    String str3 = "hello";
    //returns true
    System.out.println("str1.equals(str2)-" + str1.equals(str2));
    //returns false as case is different
    System.out.println("str1.equals(str3)-" + str1.equals(str3));
  }
}
Output
str1.equals(str2)-true
str1.equals(str3)-false
Java example using equalsIgnoreCase() method
public class StringComapre {
  public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = "Hello";
    String str3 = "hello";
    //returns true
    System.out.println("str1.equals(str2)-" + str1.equals(str2));
    //returns true as case is ignored
    System.out.println("str1.equalsIgnoreCase(str3)-" + str1.equalsIgnoreCase(str3));
  }
}
Output
str1.equals(str2)-true
str1.equalsIgnoreCase(str3)-true

Compare Strings using compareTo() and compareToIgnoreCase() methods

  • int compareTo(String anotherString)- Compares two strings lexicographically. Returns positive integer if this String is greater than the argument, returns negative integer if this String is less than the argument, returns zero if this string is equal to the argument.
  • int compareToIgnoreCase(String str)- Compares two strings lexicographically, ignoring case differences. Returns positive integer if this String is greater than the argument, returns negative integer if this String is less than the argument, returns zero if this string is equal to the argument, ignoring case considerations.
Java example using compareTo() method
public class StringComapre {
  public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = "Hello";
    String str3 = "Halo";
    // returns 0
    System.out.println("str1.compareTo(str2): " + str1.compareTo(str2));
    // returns positive integer
    System.out.println("str1.compareTo(str3): " + str1.compareTo(str3));
    // returns negative integer
    System.out.println("str3.compareTo(str1): " + str3.compareTo(str1));
  }
}
Output
str1.compareTo(str2): 0
str1.compareTo(str3): 4
str3.compareTo(str1): -4

Since both str1 and str2 have the same value so 0 is returned on comparing them. On comparing str1 with str3 positive integer (4) is returned as "hello" comes after "halo".

Java example using compareToIgnoreCase() method
public class StringComapre {
  public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = "hello";
    String str3 = "cello";
    // returns 0
    System.out.println("str1.compareTo(str2): " + str1.compareToIgnoreCase(str2));
    // returns positive integer
    System.out.println("str1.compareTo(str3): " + str1.compareTo(str3));
    // returns negative integer
    System.out.println("str3.compareTo(str1): " + str3.compareTo(str1));
  }
}
Output
str1.compareTo(str2): 0
str1.compareTo(str3): -27
str3.compareTo(str1): 27

Compare String portions using startsWith() and endsWith() methods

  • boolean startsWith(String str)- Tests if this string starts with the passed argument. Returns true if substring matches at the start, false otherwise.
  • boolean startsWith(String str, int toffset)- Tests if the substring of this string beginning at the specified index starts with the passed argument. Returns true if substring matches at the start, false otherwise.
  • boolean endsWith(String str)- Tests if this string ends with the passed argument. Returns true if substring matches at the end, false otherwise.
Java example using startsWith() and endsWith()
public class StringComapre {
  public static void main(String[] args) {
    String str = "Compare this String";

    // returns true
    System.out.println("str.startsWith(\"Compare\"): " + str.startsWith("Compare"));
    // returns false
    System.out.println("str.startsWith(\"Comparison\"): " + str.startsWith("Comparison"));
    // returns true- Comparison starts from index 8
    System.out.println("str.startsWith(\"this\"): " + str.startsWith("this", 8));
    
    // returns true
    System.out.println("str.endsWith(\"String\"): " + str.endsWith("String"));
    // returns false
    System.out.println("str.endsWith(\"Sting\"): " + str.endsWith("Sting"));
  }
}
Output
str.startsWith("Compare"): true
str.startsWith("Comparison"): false
str.startsWith("this"): true
str.endsWith("String"): true
str.endsWith("Sting"): false

Compare String portions using regionMatches method

  • boolean regionMatches(int toffset, String other, int ooffset, int len)- Tests if two string regions are equal. A substring of the first string is compared to the substring of the second string. Index from which the substring of the first string starts is specified using toffset. Index from which the substring of the second string starts is specified using ooffset. Length of the substring which is to be compared is specfied using len.
  • boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)- If ignoreCase is passed as true, ignore case when comparing characters.
public class StringComapre {
  public static void main(String[] args) {
    String str1 = "Compare this string";
    String str2 = "Compare with this String";
    
    // Comparing "this" portion of both Strings- true
    System.out.println("str1.regionMatches(8, str2, 13, 4): " + str1.regionMatches(8, str2, 13, 4));
    // Comparing "String" portion of both Strings- false when case is considered
    System.out.println("str1.regionMatches(13, str2, 18, 6): " + str1.regionMatches(13, str2, 18, 6));
    // Comparing "String" portion of both Strings- true when case is ignored
    System.out.println("str1.regionMatches(true, 13, str2, 18, 6): " + str1.regionMatches(true, 13, str2, 18, 6));
  }
}
Output
str1.regionMatches(8, str2, 13, 4): true
str1.regionMatches(13, str2, 18, 6): false
str1.regionMatches(true, 13, str2, 18, 6): true

That's all for the topic Compare Two Strings in Java - equals, compareTo() methods . If something is missing or you have something to share about the topic please write a comment.


You may also like

Java LinkedHashMap With Examples

LinkedHashMap in Java is also one of the implementation of the Map interface. How it differs from the other implementation HashMap is that unlike HashMap which is unordered, LinkedHashMap is ordered. LinkedHashMap class in Java also extends HashMap apart from implementing Map interface.

LinkedHashMap maintains a doubly-linked list running through all of its entries which defines the iteration ordering. There are two options for ordering-

  • Insertion ordering- The order in which keys were inserted into the Map. Insertion ordering is default ordering for the LinkedHashMap in Java.
  • Access ordering- The order in which its entries were last accessed, from least-recently accessed to most-recently. There is a special constructor for creating LinkedHashMap with access ordering.

Features of LinkedHashMap

Some of the features of the LinkedHashMap in Java which are discussed in this post are as follows-

  1. In LinkedHashMap values may be duplicate but a key has to be unique. If same key is reinserted that doesn’t affect the insertion order.
  2. LinkedHashMap is ordered.
  3. LinkedHashMap permits both null values and null keys. But only single null key is permitted where as there can be multiple null values.
  4. LinkedHashMap in Java is not thread safe.
  5. The iterators returned by all of LinkedHashMap’s "collection view methods" are fail-fast. Which means, if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the Iterator throws a ConcurrentModificationException.

Java LinkedHashMap constructors

  • LinkedHashMap()- Constructs an empty insertion-ordered LinkedHashMap instance with the default initial capacity (16) and load factor (0.75).
  • LinkedHashMap(int initialCapacity)- Constructs an empty insertion-ordered LinkedHashMap instance with the specified initial capacity and a default load factor (0.75).
  • LinkedHashMap(int initialCapacity, float loadFactor)- Constructs an empty insertion-ordered LinkedHashMap instance with the specified initial capacity and load factor.
  • LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)- Constructs an empty LinkedHashMap instance with the specified initial capacity, load factor and ordering mode. If accessOrder is passed as true true then access-order, false for insertion-order.
  • LinkedHashMap(Map<? extends K,? extends V> m)- Constructs an insertion-ordered LinkedHashMap instance with the same mappings as the specified map.

Java example creating a LinkedHashMap

This example shows how LinkedHashMap is created and elements added to it.

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHMDemo {
  public static void main(String[] args) {
    // Creating LinkedHashMap
    Map<String, String> carMap = new LinkedHashMap<String, String>();
    // Storing elements
    carMap.put("1", "Audi");
    carMap.put("2", "BMW");
    carMap.put(null, "Mercedes");
    carMap.put("3", "Jaguar");
    carMap.put("4", "Mini Cooper");
    carMap.put(null, "Range Rover");

    for(Map.Entry<String, String> entry : carMap.entrySet()){
      System.out.println("Key is " + entry.getKey() + " Value is " + entry.getValue());
    }
  }
}
Output
Key is 1 Value is Audi
Key is 2 Value is BMW
Key is null Value is Range Rover
Key is 3 Value is Jaguar
Key is 4 Value is Mini Cooper

As you can see from the output insertion order is maintained. Also null is added only once even if it is added more than once.

LinkedHashMap with access order

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHMDemo {
  public static void main(String[] args) {
    // Creating LinkedHashMap
    Map<String, String> carMap = new LinkedHashMap<String, String>(16, 0.75f, true);
    // Storing elements
    carMap.put("1", "Audi");
    carMap.put("2", "BMW");
    carMap.put("3", "Jaguar");
    carMap.put("4", "Mini Cooper");
    System.out.println("value- " + carMap.get("2"));
    System.out.println("value- " + carMap.get("3"));
    for(Map.Entry<String, String> entry : carMap.entrySet()){
      System.out.println("Key is " + entry.getKey() + " Value is " + entry.getValue());
    }
  }
}
Output
Key is 1 Value is Audi
Key is 4 Value is Mini Cooper
Key is 2 Value is BMW
Key is 3 Value is Jaguar

Since access order goes from least-recently accessed to most-recently that is why keys 2 and 3 are displayed later because these 2 keys are accessed recently.

Methods in LinkedHashMap class

  • containsValue(Object value)- Returns true if this map maps one or more keys to the specified value.
  • entrySet()- Returns a Set view of the mappings contained in this map.
  • get(Object key)- Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
  • keySet()- Returns a Set view of the keys contained in this map.
  • removeEldestEntry(Map.Entry<K,V> eldest)- Returns true if this map should remove its eldest entry.
  • values()- Returns a Collection view of the values contained in this map.

LinkedHashMap implementation is not synchronized

LinkedHashMap in Java is not thread safe as it is not synchronized. If multiple threads access a LinkedHashMap concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. You can wrap your LinkedHashMap using the Collections.synchronizedMap() method.

Map m = Collections.synchronizedMap(new LinkedHashMap(...));

Java LinkedHashMap iterator

You can’t directly use an iterator with Map. You will have to get the collection view of the Map and then iterate it. The iterators returned by LinkedHashMap's collection view methods are fail-fast. If the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the Iterator throws a ConcurrentModificationException.

Iterating LinkedHashMap Java example
public class LinkedHMDemo {
  public static void main(String[] args) {
    // Creating HashMap
    Map<String, String> carMap = new LinkedHashMap<String, String>();
    // Storing elements
    carMap.put("1", "Audi");
    carMap.put("2", "BMW");
    carMap.put("3", "Jaguar");
    carMap.put("4", "Mini Cooper");
    // iterating map
    Iterator<Map.Entry<String, String>> itr = carMap.entrySet().iterator();
    while(itr.hasNext()) {
      Map.Entry<String, String> entry = itr.next();
      System.out.println("Key is " + entry.getKey() + " Value is " + entry.getValue());
    }
  }
}
Output
Key is 1 Value is Audi
Key is 2 Value is BMW
Key is 3 Value is Jaguar
Key is 4 Value is Mini Cooper

Performance of LinkedHashMap

Like HashMap, LinkedHashMap provides constant-time performance for the basic operations (add, contains and remove), assuming the hash function disperses elements properly among the buckets. LinkedHashMap's performance is likely to be just slightly below that of HashMap, due to the added expense of maintaining the linked list. One exception is iteration which is faster in LinkedHashMap because of the linked list traversal.

Reference: https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/LinkedHashMap.html

That's all for the topic Java LinkedHashMap With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like