August 31, 2022

Java LinkedHashSet With Examples

LinkedHashSet in Java is also one of the implementation of the Set interface like HashSet and Treeset. How LinkedHashSet differs from the other implementation HashSet is that unlike HashSet which is unordered, LinkedHashSet is an ordered collection, it maintains iteration ordering, which is the order in which elements were inserted into the set.

LinkedHashSet implementation in Java

LinkedHashSet maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering. LinkedHashSet class in Java extends HashSet apart from implementing Set interface and uses the methods of the HashSet class itself.

If you have idea about the HashSet internal implementation then you must be knowing that internally HashSet uses HashMap to store its element. Same way LinkedHashSet internally uses LinkedHashMap.

Features of LinkedHashSet

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

  1. LinkedHashSet in Java stores only unique elements.
  2. LinkedHashSet is an ordered collection and maintains the insertion order.
  3. LinkedHashSet permits null elements.
  4. LinkedHashSet is not thread-safe.
  5. The iterators returned by the iterator method of the LinkedHashSet class are fail-fast. Which means, 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.

Java LinkedHashSet constructors

LinkedHashSet class in Java has 4 constructors.

  • LinkedHashSet()- Constructs a new, empty linked hash set with the default initial capacity (16) and load factor (0.75).
  • LinkedHashSet(int initialCapacity)- Constructs a new, empty linked hash set with the specified initial capacity and the default load factor (0.75).
  • LinkedHashSet(int initialCapacity, float loadFactor)- Constructs a new, empty linked hash set with the specified initial capacity and load factor.
  • LinkedHashSet(Collection<? extends E> c)- Constructs a new linked hash set with the same elements as the specified collection.

Java example creating a LinkedHashSet

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

import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetDemo {
  public static void main(String[] args) {
    // Creating LinkedHashSet
    Set<String> carSet = new LinkedHashSet<String>();
    // Storing elements
    carSet.add("Audi");
    carSet.add("BMW");
    carSet.add("Mini Cooper");
    carSet.add(null);
    carSet.add("Jaguar");
    carSet.add("Mini Cooper");
    carSet.add(null);

    // Iterating the Set
    for(String str : carSet){
      System.out.println("Car Name- " + str);
    }  
  }
}
Output
Car Name- Audi
Car Name- BMW
Car Name- Mini Cooper
Car Name- null
Car Name- Jaguar

As you can see from the output insertion order is maintained. Also duplicate element is added only once and it doesn’t affect the insertion order, same way null is added only once even if it is added more than once.

LinkedHashSet implementation is not synchronized

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

Set s = Collections.synchronizedSet(new LinkedHashSet(...));

Java LinkedHashSet iterator

The iterators returned by LinkedHashSet'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 LinkedHashSet Java example
public class LinkedHashSetDemo {
  public static void main(String[] args) {
    Set<String> carSet = new LinkedHashSet<String>();
    // Storing elements
    carSet.add("Audi");
    carSet.add("BMW");
    carSet.add("Mini Cooper");
    carSet.add("Jaguar");
    
    Iterator<String> itr = carSet.iterator();
    while(itr.hasNext()){
      System.out.println("Car Name- " + itr.next());
    } 
  }
}
Output
Car Name- Audi
Car Name- BMW
Car Name- Mini Cooper
Car Name- Jaguar

Performance of LinkedHashSet

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

Reference: https://docs.oracle.com/javase/10/docs/api/java/util/LinkedHashSet.html

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


You may also like

August 30, 2022

Java HashSet With Examples

HashSet in Java is part of the Java Collections framework and one of the most used Set implementation in Java applications. HashSet class extends AbstractSet class and implements Set, Cloneable and Serializable interfaces. HashSet is backed by a HashMap instance that means HashSet class internally uses HashMap to store its elements.

Features of HashSet in Java

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

  1. HashSet stores only unique elements.
  2. HashSet is an unordered collection, which means insertion order is not maintained as in ArrayList.
  3. HashSet in Java allows null.
  4. HashSet is not thread-safe.
  5. The iterators returned by HashSet's iterator method are fail-fast. Which means, 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.

Java HashSet constructors

HashSet class in Java has 4 constructors.

  • HashSet()- This constructor constructs a new, empty set; the backing HashMap instance has default initial capacity (16) and load factor (0.75).
  • HashSet(int initialCapacity)- This constructor constructs a new, empty set; the backing HashMap instance has the specified initial capacity and default load factor (0.75).
  • HashSet(int initialCapacity, float loadFactor)- This constructor constructs a new, empty set; the backing HashMap instance has the specified initial capacity and the specified load factor.
  • HashSet(Collection<? extends E> c)- This constructor constructs a new set containing the elements in the specified collection.

Capacity and Load Factor for HashSet

As already stated HashSet class in Java internally uses HashMap to store its elements. HashMap in turns uses an array of type Node to store elements. If you don’t specify any capacity while creating HashSet then the array will have default initial capacity of 16.

In HashMap concept of bucket is used so each index of array is conceptualized as one bucket. So, total there are 16 buckets. For every value that is added to HashSet a hash is calculated, based on that hash value one of these buckets is chosen to store the element. That way HashSet is able to offer constant time performance for basic operations like add, remove, contains and size.

Load factor provides the threshold for the HashSet storage. Once the threshold is reached the capacity is doubled. Default load factor is 0.75 which means if the 75% of the capacity is used the HashSet is resized.

To know more about HashSet internal implementation in Java refer this post- HashSet Internal Implementation in Java

Java example creating a HashSet

Let’s see a basic example where a HashSet is created and elements added to it. Then the added elements are displayed.

import java.util.HashSet;
import java.util.Set;

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires

As you can see HashSet of default capacity is created using this statement.

Set<String> capitalSet = new HashSet<String>();

All Collections classes are generic now, so you can specify in the beginning itself what type of elements will be stored in the Set. The Set used in this example can store only Strings.

From the output you can see that the insertion order is not maintained in the HashSet.

Methods in the HashSet class

Here is a list of some of the methods in the HashSet class in Java.

  • add(E e)- Adds the specified element to this set if it is not already present.
  • clear()- Removes all of the elements from this set.
  • clone()- Returns a shallow copy of this HashSet instance: the elements themselves are not cloned.
  • contains(Object o)- Returns true if this set contains the specified element.
  • isEmpty()- Returns true if this set contains no elements.
  • iterator()- Returns an iterator over the elements in this set.
  • remove(Object o)- Removes the specified element from this set if it is present.
  • size()- Returns the number of elements in this set.
  • spliterator()- Creates a late-binding and fail-fast Spliterator over the elements in this set.

Duplicates are not allowed in HashSet

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    // added again
    capitalSet.add("New Delhi");
    System.out.println("HashSet size-- " + capitalSet.size());
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
HashSet size-- 4
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires

As you can see, even if “New Delhi” is added twice it is inserted only once. Size of the HashSet is also 4.

Inserting Null is allowed in HashSet

You can insert null in HashSet but it can be added only once. In the below example null is added twice, in the output you can see that it is inserted only once.

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add(null);
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    capitalSet.add(null);
    System.out.println("HashSet size-- " + capitalSet.size());
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
HashSet size-- 5
Capital city- null
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires

Example code to remove elements from HashSet

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    
    capitalSet.remove("Buenos Aires");
      
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
    // Removing all elements
    capitalSet.clear();      
    System.out.println("HashSet size after clearing -- " + capitalSet.size());
  }
}
Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
HashSet size after clearing – 0

Java HashSet iterator example

You can use an iterator to iterate a HashSet. You can get an Iterator using iterator() method of the HashSet class. The iterators returned by HashSet’s iterator method 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.

Refer How to Iterate a Java HashSet to see different ways to traverse a HashSet in Java.

Let’s try to clarify it with an example. In the code while iterating the HashSet using iterator we’ll try to remove an element using the HashSet’s remove() method not the iterator’s remove method.

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    
    Iterator<String> itr = capitalSet.iterator();
    while(itr.hasNext()){
      String capital = itr.next();
      System.out.println("Capital city- " + capital);
      if(capital.equals("Lisbon")){
        capitalSet.remove(capital);
      }
    }
  }
}

As you can see ConcurrentModificationException exception is thrown as you are trying to structurally modify the HashSet while it is iterated using an iterator.

Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(Unknown Source)
	at java.util.HashMap$KeyIterator.next(Unknown Source)
	at com.knpcode.HashSetDemo.main(HashSetDemo.java:19)
Using iterator’s remove method
public class HashSetDemo {
  public static void main(String[] args) {
    Set capitalSet = new HashSet();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
		
    Iterator itr = capitalSet.iterator();
    while(itr.hasNext()){
      String capital = itr.next();
      System.out.println("Capital city- " + capital);
      if(capital.equals("Lisbon")){
        itr.remove();
      }
    }
    System.out.println("** After element removal **");
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires
** After element removal **
Capital city- Beijing
Capital city- New Delhi
Capital city- Buenos Aires

As you can see using iterator’s remove method you can remove an element while the HashSet is iterated.

HashSet is not threadsafe

HashSet in Java is not threadsafe. If you are using HashSet in multi-threaded environment where instance of HashSet is shared among many threads, you should synchronize it externally. In order to synchronize Set you can use Collections.synchronizedSet() method which returns a synchronized set backed by the passed set to this method.

As example-
Set tempSet = Collections.synchronizedSet(capitalSet); 

See an example of synchronizing HashSet in Java here- How to Synchronize HashSet in Java

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


You may also like

August 29, 2022

Java ArrayList With Examples

In Java programming language when you create an array you will have to provide its length. Once created, array is of fixed length and that length can’t be changed. In many cases you may not know the exact length in advanced in such scenarios you can use ArrayList in Java.

ArrayList class in Java

ArrayList in Java is a resizable-array implementation of the List interface and resides in java.util package. Since ArrayList is dynamic so it can grow or shrink automatically.

Internally ArrayList uses an array which is created with an initial capacity. If that capacity is reached because of the addition of elements, a new array is created whose capacity is 50% more than the capacity of the older one and the existing elements are copied to this new array. Same way when an element is removed from an ArrayList the gap created in the underlying array is filled automatically. As a user that logic of increasing or decreasing the length of an ArrayList is abstracted from us.

Refer ArrayList Internal Implementation in Java to know more about internal implementation of ArrayList in Java.

Features of ArrayList in Java

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

  1. ArrayList is part of Java Collections framework. ArrayList extends AbstractList class and implements List, RandomAceess, Cloneable and Serializable interfaces.
  2. While creating an ArrayList you can provide the capacity for it or use the default capacity which is 10.
  3. Since ArrayList in Java implements RandomAccess interface so elements of the list can be accessed randomly by passing the index of the element with the method. Index starts at 0 in List.
  4. ArrayList in Java can store only objects, if you need to store primitive data types you will have to use wrapper classes. Because of Autoboxing even that can happen automatically where primitives are wrapped behind the scene.
  5. You can add null to an ArrayList.
  6. Adding duplicate elements to an ArrayList is also allowed.
  7. ArrayList in Java is not thread safe.
  8. The iterators returned by iterator and listIterator methods of ArrayList are fail-fast. Which means, if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.

Java ArrayList Constructors

  • ArrayList()- This constructor creates an empty list with an initial capacity of ten, which is the default capacity.
  • ArrayList(int initialCapacity)- This constructor constructs an empty list with the specified initial capacity.
  • ArrayList(Collection<? extends E> c)- Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.

Java example creating an ArrayList

Let’s see an example where an ArrayList is created and elements are added to it. Later in the code those elements are printed too.

import java.util.ArrayList;
import java.util.List;

public class ArrayListDemo {
  public static void main(String[] args) {
    List<String> nameList = new ArrayList<String>();
    // adding elements
    nameList.add("Adam");
    nameList.add("Amy");
    nameList.add("Jim");
    // Adding at specific index
    nameList.add(0, "Leo");
    // Displaying list elements
    for(String name : nameList){
      System.out.println("Name- " + name);
    }
  }
}
Output
Name- Leo
Name- Adam
Name- Amy
Name- Jim

As you can see an ArrayList of default capacity is created using this statement.

List<String> nameList = new ArrayList<String>();

All Collections classes are generic now, so you can specify in the beginning itself what type of elements will be stored in the list. The list used in this example can store only Strings.

Then some elements are added to the list, one of the element is added at a specific index. Later the elements are displayed using for-each loop.

Methods in the ArrayList class

Here is a list of some of the methods in the ArrayList class in java.

  1. add(int index, E element)- This method inserts the passed element at the specified position in this list.
  2. add(E e)- This method appends the specified element to the end of this list.
  3. addAll(int index, Collection<? extends E> c)- This method inserts all of the elements in the passed collection into this list, starting at the specified position.
  4. addAll(Collection<? extends E> c)- This method appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's Iterator.
  5. clear()- Method to remove all of the elements from this list.
  6. contains(Object o)- Returns true if this list contains the specified element.
  7. get(int index)- Returns the element at the specified position in this list.
  8. indexOf(Object o)- Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
  9. isEmpty()- Returns true if this list contains no elements.
  10. iterator()- Returns an iterator over the elements in this list in proper sequence.
  11. lastIndexOf(Object o)- Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
  12. remove(int index)- Removes the element at the specified position in this list.
  13. remove(Object o)- Removes the first occurrence of the specified element from this list, if it is present.
  14. removeIf(Predicate<? super E> filter)- Removes all of the elements of this collection that satisfy the given predicate.
  15. set(int index, E element)- Replaces the element at the specified position in this list with the specified element.
  16. size()- Returns the number of elements in this list.

ArrayList allows duplicate values and null

In ArrayList you can add duplicate elements, null is also allowed that too any number of times.

import java.util.ArrayList;
import java.util.List;

public class ArrayListDemo {
  public static void main(String[] args) {
    List<String> nameList = new ArrayList<String>();
    // adding elements
    nameList.add("Adam");
    nameList.add("Amy");
    nameList.add(null);
    nameList.add("Jim");
    nameList.add("Jim");
    nameList.add(null);
    // Displaying list elements
    for(String name : nameList){
      System.out.println("Name- " + name);
    }
    System.out.println("Size of the list- " + nameList.size());
  }
}
Output
Name- Adam
Name- Amy
Name- null
Name- Jim
Name- Jim
Name- null
Size of the list- 6

Java example to remove elements from an ArrayList

Following example shows how you can delete any element from a Java ArrayList using remove() method.

public class ArrayListDemo {
  public static void main(String[] args) {
    List<String> nameList = new ArrayList<String>();
    // adding elements
    nameList.add("Adam");
    nameList.add("Amy");
    nameList.add("Jim");
    nameList.add("Leo");
    // removing using index
    nameList.remove(2);
    // Displaying list elements
    for(String name : nameList){
      System.out.println("Name- " + name);
    }
    System.out.println("--------------------------");
    // removing using object
    nameList.remove("Leo");
    // Displaying list elements
    for(String name : nameList){
      System.out.println("Name- " + name);
    }
  }
}
Output
Name- Adam
Name- Amy
Name- Leo
--------------------------
Name- Adam
Name- Amy

Adding primitive data types to an ArrayList

ArrayList in Java can store only objects, if you need to store primitive data types you will have to wrap them in the corresponding wrapper class to get an object. With autoboxing even that process is automatic now and done behind the scene.

If you want to add int to an ArrayList-

public class ArrayListDemo {
  public static void main(String[] args) {
    List<String> nameList = new ArrayList<String>();
    // Wrapping int in Integer wrapper class
    numList.add(new Integer(5));
    // Done automatically
    numList.add(6);
    for(Integer num : numList){
      System.out.println("Number- " + num);
    }
  }	
}
Output
Number- 5
Number- 6

In the code you can see both of the ways to add the primitive data types to an ArrayList. While adding first element int is wrapped in the Integer wrapper class. In the second addition it is done automatically.

Also notice in the for-each loop you are assigning the elements to an Integer variable which doesn’t create any problem for the second element as it is automatically wrapped to get an Integer object.

Java ArrayList iterator

Using iterator in ArrayList you can traverse the list in a sequential manner. You can get an Iterator using iterator() method and ListIterator using listIterator() method. Difference between Iterator and ListIterator is that ListIterator allows to traverse the list in either direction.

Refer How to Iterate Java ArrayList to see different options to iterate an ArrayList in Java.

The iterators returned by both iterator and listIterator methods are fail-fast. If the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Note that List iterator provides both add and remove methods where as Iterator interface provides only remove() method.

Java ArrayList iterator example
public class ArrayListDemo {
  public static void main(String[] args) {
    List<String> nameList = new ArrayList<String>();
    // adding elements
    nameList.add("Adam");
    nameList.add("Amy");
    nameList.add("Jim");
    nameList.add("Leo");
    // getting iterator
    Iterator<String> itr = nameList.iterator();
    while(itr.hasNext()){
      System.out.println("Name- " + itr.next());
      nameList.add("Jack");			
    }
  }
}
Output
Name- Adam
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
	at java.util.ArrayList$Itr.next(Unknown Source)
	at com.knpcode.ArrayListDemo.main(ArrayListDemo.java:20)

In the code while iteration is in progress an attempt is made to add an element using the list’s add method (Structural modification) that is why ConcurrentModificationException is thrown.

Example code using iterator’s remove method
public class ArrayListDemo {
  public static void main(String[] args) {
    List<String> nameList = new ArrayList<String>();
    // adding elements
    nameList.add("Adam");
    nameList.add("Amy");
    nameList.add("Jim");
    nameList.add("Leo");
    // getting iterator
    Iterator<String> itr = nameList.iterator();
    while(itr.hasNext()){
      String name = itr.next();
      if(name.equals("Jim")){
        // using iterators remove method
        itr.remove();
      }	
    }
    for(String name : nameList){
      System.out.println("Name- " + name);
    }
  }
}
Output
Name- Adam
Name- Amy
Name- Leo

This code works fine as the modification is done using the iterator's remove method.

ArrayList is not thread-safe

ArrayList in Java is not thread safe. If an instance of ArrayList is shared among multiple threads and any thread modifies the List structurally then other threads may not get the updated list. In such scenario ArrayList must be synchronized externally using Collections.synchronizedList() method. For example-

List<String> tempList = Collections.synchronizedList(nameList);

To see an example of how to synchronize ArrayList and what other thread-safe alternatives are available, refer this post- How to Synchronize ArrayList in Java

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


You may also like

August 28, 2022

Object Cloning in Java Using clone() Method

Object cloning in Java is the process of creating a copy of an object. To clone an object in Java clone() method of the Object class is used.

clone() method

clone() method is defined in the Object class as a protected method.

protected Object clone() throws CloneNotSupportedException

If you are going to write a clone() method in your class to override the one in Object class then it has to be written as a public method.

public Object clone() throws CloneNotSupportedException

Cloning an object in Java using clone() method

One of the requirement for cloning an object is that the class whose objects are to be cloned must implement Cloneable interface. Cloneable interface is a marker interface and defines no members of its own. If you try to call clone() method on a class that does not implement Cloneable interface, a CloneNotSupportedException is thrown.

If you have to create a clone of an object obj using clone() method then you write-

obj.clone();

Default implementation of the clone() method creates an object of the same class as the original object. Cloned object's member variables are initialized to have the same values as the original object's corresponding member variables.

Examples of Java object cloning

Here is a simple example of cloning an object by directly calling clone() method of the Object class using super.

class TestClone implements Cloneable{
  int i;
  String str;
  TestClone(int i, String str){
    this.i = i;
    this.str = str;
  }
  TestClone cloneObject() throws CloneNotSupportedException{
    // calling Object class clone method
    return (TestClone) super.clone();
  }
}

public class CloningDemo {
  public static void main(String[] args) {
    TestClone obj1 = new TestClone(10, "Clone Test");
    try {
      TestClone obj2 = obj1.cloneObject();
      System.out.println("Original object- " + obj1.i + " " + obj1.str);
      System.out.println("Cloned object- " + obj2.i + " " + obj2.str);
      // Checking object references for objects
      if(obj1 == obj2){
        System.out.println("Object references are same");
      }else{
        System.out.println("Object references are not same");
      }
    } catch (CloneNotSupportedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 			
  }
}
Output
Original object- 10 Clone Test
Cloned object- 10 Clone Test
Object references are not same

In the code you can note what all is done for object cloning-

  1. Class whose object is to be cloned implements Cloneable interface.
  2. super.clone() is called to use the default implementation of the clone() method in the Object class.
  3. You can see that the copy of an object has the same state as the original object (same value for the member variables as original object).
  4. Though the state is same but the reference is not same. Cloned object is distinct.
Override clone method in the class

You can also override the clone method in the class though it is not always necessary.

class TestClone implements Cloneable{
  int i;
  String str;
  TestClone(int i, String str){
    this.i = i;
    this.str = str;
  }
  // overriding clone method
  public Object clone() throws CloneNotSupportedException{
    return super.clone();
  }
}

public class CloningDemo {
  public static void main(String[] args) {
    TestClone obj1 = new TestClone(10, "Clone Test");
    try {
      TestClone obj2 = (TestClone) obj1.clone();
      System.out.println("Original object- " + obj1.i + " " + obj1.str);
      System.out.println("Cloned object- " + obj2.i + " " + obj2.str);
    } catch (CloneNotSupportedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 			
  }
}
Output
Original object- 10 Clone Test
Cloned object- 10 Clone Test

Advantages of object cloning

  1. Object cloning in Java is the easiest way to get a new object with a state. You don’t need to go through the whole process of calling new operator to create an object and assign value to its fields.
  2. Cloned object is a distinct object with its own state. Changing one of the object doesn’t change the state of the other object.

Disadvantages of object cloning

  1. Though using the default clone() method make the process of cloning an object automatic but at the same time you don’t have any control over the whole process. Even the constructor is not called when object is cloned.
  2. Object.clone() method creates a shallow copy. That is fine if the fields in an object are primitive or immutable. In case original object holds reference to another object then that reference is shared between original and cloned object which may be a problem.

Object cloning - Shallow copy

When an object is cloned a bit wise copy happened where each field’s value in the original object is copied to the cloned object’s corresponding field. This way of object cloning in Java is known as Shallow copy. This works fine for primitive values as we have already seen in the examples.

But this process of creating an exact copy may have a problem when object holds reference to another object because that reference is copied as it is in the cloned object and both objects share that object reference. That’s when you may need a deep copy.

Java Object cloning - Deep copy

You need to do a deep copy if you don’t want any object references to be copied as it is during the object cloning process.

For creating a deep copy you need to explicitly override the clone() method in your class and call the clone() method for the objects referenced by the original object too.

Creating a Deep copy is more expensive as you need to create new objects for all the referenced objects. It is more complicated too as there may be a whole object tree that you may need to clone.

To know more about Shallow copy and Deep copy in Java object cloning please refer this post- Shallow Copy Vs Deep Copy in Java Object Cloning

Object cloning in Java - Deep copy example

In the example there are two classes One and Two. In Class Two there is a reference to an object of class One. In order to do a deep copy clone() method is overridden in class Two and clone() method for the referenced object (object of class One) is also called explicitly to create a distinct copy of that object too.

class One implements Cloneable{
  int i;
  String str;
  One(int i, String str){
    this.i = i;
    this.str = str;
  }
  // overriding clone method
  public Object clone() throws CloneNotSupportedException{
    return super.clone();
  }
  public int getI() {
    return i;
  }
  public void setI(int i) {
    this.i = i;
  }
  public String getStr() {
    return str;
  }
  public void setStr(String str) {
    this.str = str;
  }
}

class Two implements Cloneable{
  int j;
  // Object reference
  One obj;
  Two(int j, One obj){
    this.j = j;
    this.obj = obj;
  }
  public Object clone() throws CloneNotSupportedException{
    Two objCloned =  (Two) super.clone();
    // Explicitly calling clone method for
    // object of Class One
    objCloned.obj = (One) obj.clone();
    return objCloned;
  }
  public int getJ() {
    return j;
  }
  public void setJ(int j) {
    this.j = j;
  }
  public One getObj() {
    return obj;
  }
  public void setObj(One obj) {
    this.obj = obj;
  }
}

public class CloningDemo {
  public static void main(String[] args) {
    One one = new One(10, "Clone Test");
    Two two = new Two(5, one);
    try {
      Two objCopy = (Two) two.clone();
      System.out.println("Original object- " +  two.getJ() + " " + two.getObj().str);
      System.out.println("Cloned object- " +  + objCopy.getJ() + " " + objCopy.getObj().str);
      objCopy.getObj().setStr("Value changed");
      System.out.println("---After changing value---");
      System.out.println("Original object- " +  two.getJ() + " " + two.getObj().str);
      System.out.println("Cloned object- " +  + objCopy.getJ() + " " + objCopy.getObj().str);
    } catch (CloneNotSupportedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 			
  }
}
Output
Original object- 5 Clone Test
Cloned object- 5 Clone Test
---After changing value---
Original object- 5 Clone Test
Cloned object- 5 Value changed

As you can see from the output when the str field is modified in class One object referenced by the cloned object that change is not reflected in the original object because of the deep copy.

That's all for the topic Object Cloning in Java Using clone() Method. If something is missing or you have something to share about the topic please write a comment.


You may also like

August 27, 2022

Shallow Copy Vs Deep Copy in Java Object Cloning

In this post we’ll see the differences between shallow copy and deep copy in Java object cloning. To understand the differences it is very important to understand the concept of shallow copy and deep copy while cloning an object so first we’ll try to understand the concept using examples of both shallow copy and deep copy.

To know more about object cloning in Java please refer this post- Object Cloning in Java Using clone() Method

Shallow copy in Java object cloning

When an object is cloned using clone() method a bit wise copy happens where each field’s value in the original object is copied to the cloned object’s corresponding field. This way of object cloning in Java using the default clone() method creates a Shallow copy.

This is known as shallow copy because this process of creating an exact copy works fine for primitive values but has a shared state between the original object and cloned object when original object holds reference to another object.

In that case that reference is copied as it is in the cloned object and both object share that object reference.

For example if there is a class MyClass which has another object objA as a field.

class MyClass implements Cloneable{
  private ClassA objA;
  ...
  ...
}

If there is an object myObj of class MyClass and that is cloned then the objA reference is shared between myObj and cloned copy of myObj.

shallow copy in Java

Shallow copy in Java example

In the example there are two classes One and Two. In Class Two there is a reference to an object of class One.

class One implements Cloneable{
  int i;
  String str;
  One(int i, String str){
    this.i = i;
    this.str = str;
  }
  // overriding clone method
  public Object clone() throws CloneNotSupportedException{
    return super.clone();
  }
  public int getI() {
    return i;
  }
  public void setI(int i) {
    this.i = i;
  }
  public String getStr() {
    return str;
  }
  public void setStr(String str) {
    this.str = str;
  }
}

class Two implements Cloneable{
  int j;
  // Object reference
  One obj;
  Two(int j, One obj){
    this.j = j;
    this.obj = obj;
  }
  public Object clone() throws CloneNotSupportedException{
    Two objCloned =  (Two) super.clone();
    return objCloned;
  }
  public int getJ() {
    return j;
  }
  public void setJ(int j) {
    this.j = j;
  }
  public One getObj() {
    return obj;
  }
  public void setObj(One obj) {
    this.obj = obj;
  }
}

public class CloningDemo {
  public static void main(String[] args) {
    One one = new One(10, "Clone Test");
    Two two = new Two(5, one);
    try {
      Two objCopy = (Two) two.clone();
      System.out.println("Original object- " +  two.getJ() + " " + two.getObj().str);
      System.out.println("Cloned object- " +  + objCopy.getJ() + " " + objCopy.getObj().str);
      // modifying field in the referenced object
      objCopy.getObj().setStr("New Value");
      // Modifying primtive value
      objCopy.setJ(25);
      System.out.println("---After changing value---");
      System.out.println("Original object- " +  two.getJ() + " " + two.getObj().str);
      System.out.println("Cloned object- " +  + objCopy.getJ() + " " + objCopy.getObj().str);
    } catch (CloneNotSupportedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 	
  }
}
Output
Original object- 5 Clone Test
Cloned object- 5 Clone Test
---After changing value---
Original object- 5 New Value
Cloned object- 25 New Value

As you can see from the output when the field in the referenced object is changed in the copy that change is reflected in the original object too. Change in primitive type field done in the copy (value of j changed to 25) is not reflected in the original object.

Deep copy in Java object cloning

To avoid such sharing of state between the original object and cloned object where the mutation of the referenced object is reflected in both the objects deep copy is required. In case of deep copy while cloning an object in Java even the referenced objects are created separately so that both objects have their own independent references.

For example if there is a class MyClass which has another object objA as a field.

class MyClass implements Cloneable{
  private ClassA objA;
  ...
  ...
}

If there is an object myObj of class MyClass and and a deep copy is created then even objA’s separate and independent copy is there for myObj and cloned copy of myObj.

deep copy in Java

Deep copy in Java example

When you do a deep copy there are two scenarios, both of which are discussed here with examples-

1- If class whose object is referenced implements Cloneable interface then you can explicitly call clone() method of that object too.

In the example you can see that the clone method is overridden in class Two and clone() method for the referenced object is also called explicitly to create a distinct copy of that object too.

class One implements Cloneable{
  int i;
  String str;
  One(int i, String str){
    this.i = i;
    this.str = str;
  }
  // overriding clone method
  public Object clone() throws CloneNotSupportedException{
    return super.clone();
  }
  public int getI() {
    return i;
  }
  public void setI(int i) {
    this.i = i;
  }
  public String getStr() {
    return str;
  }
  public void setStr(String str) {
    this.str = str;
  }
}

class Two implements Cloneable{
  int j;
  // Object reference
  One obj;
  Two(int j, One obj){
    this.j = j;
    this.obj = obj;
  }
  public Object clone() throws CloneNotSupportedException{
    Two objCloned =  (Two) super.clone();
    // Explicitly calling clone method for
    // object of Class One
    objCloned.obj = (One) obj.clone();
    return objCloned;
  }
  public int getJ() {
    return j;
  }
  public void setJ(int j) {
    this.j = j;
  }
  public One getObj() {
    return obj;
  }
  public void setObj(One obj) {
    this.obj = obj;
  }
}

public class CloningDemo {

  public static void main(String[] args) {
    One one = new One(10, "Clone Test");
    Two two = new Two(5, one);
    try {
      Two objCopy = (Two) two.clone();
      System.out.println("Original object- " +  two.getJ() + " " + two.getObj().str);
      System.out.println("Cloned object- " +  + objCopy.getJ() + " " + objCopy.getObj().str);
      // modifying field in the referenced object
      objCopy.getObj().setStr("New Value");
      // Modifying primtive value
      objCopy.setJ(25);
      System.out.println("---After changing value---");
      System.out.println("Original object- " +  two.getJ() + " " + two.getObj().str);
      System.out.println("Cloned object- " +  + objCopy.getJ() + " " + objCopy.getObj().str);
    } catch (CloneNotSupportedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 	
  }
}
Output
Original object- 5 Clone Test
Cloned object- 5 Clone Test
---After changing value---
Original object- 5 Clone Test
Cloned object- 25 New Value

As you can see when the field in the referenced object is changed in the copy that change is not reflected in the original object when deep copy is done.

2- If a class whose object is referenced doesn’t implement Cloneable interface then CloneNotSupportedException is thrown if clone() method is called upon it. In this case you need to create a new object and assign values for the fields explicitly in the clone() method.

class One{
  int i;
  String str;
  One(int i, String str){
    this.i = i;
    this.str = str;
  }
  // overriding clone method
  public Object clone() throws CloneNotSupportedException{
    return super.clone();
  }
  public int getI() {
    return i;
  }
  public void setI(int i) {
    this.i = i;
  }
  public String getStr() {
    return str;
  }
  public void setStr(String str) {
    this.str = str;
  }
}

class Two implements Cloneable{
  int j;
  // Object reference
  One obj;
  Two(int j, One obj){
    this.j = j;
    this.obj = obj;
  }
  public Object clone() throws CloneNotSupportedException{
    Two objCloned =  (Two) super.clone();
    // Creating new object
    One newObj = new One(12, "New Value");
    // assigning new oject to the clone
    objCloned.setObj(newObj);
    return objCloned;
  }
  public int getJ() {
    return j;
  }
  public void setJ(int j) {
    this.j = j;
  }
  public One getObj() {
    return obj;
  }
  public void setObj(One obj) {
    this.obj = obj;
  }
}

public class CloningDemo {

  public static void main(String[] args) {
    One one = new One(10, "Clone Test");
    Two two = new Two(5, one);
    try {
      Two objCopy = (Two) two.clone();
      System.out.println("Original object- " +  two.getJ() + " " + two.getObj().getI() + " " + two.getObj().getStr());
      System.out.println("Cloned object- " +  + objCopy.getJ() + " "  + objCopy.getObj().getI() + " " + objCopy.getObj().getStr());
    } catch (CloneNotSupportedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 	
  }
}
Output
Original object- 5 10 Clone Test
Cloned object- 5 12 New Value

Shallow copy Vs Deep Copy in Java

  1. Shallow copies are inexpensive and easy to implement. Deep copies are expensive as each referenced object has to be created separately. It is also more complex as object tree may be very long.
  2. In case of shallow copy though a distinct copy of an object is created with its own set of fields but object references are shared. In case of deep copy even for the referenced objects separate copies are created.
  3. By default Object class’ clone method creates a shallow copy. For creating a deep copy you need to override clone method and call the clone method on the referenced objects too.

That's all for the topic Shallow Copy Vs Deep Copy in Java Object Cloning. If something is missing or you have something to share about the topic please write a comment.


You may also like

August 26, 2022

Java if-else Statement With Examples

In Java programming language there are two selection statements if-else and switch statement to control the execution flow. This post talks about if and if-else statements in detail with examples.

Java if-else statement

Java if-else statement is used to evaluate a condition and take the execution path based on whether the evaluated condition is true or false. Java if statement is very flexible and provides many combinations.

  • if statement
  • if-else statement
  • if-else-if statement
  • nested if statement

Java if statement

You can have just the if statement (else is optional).

Syntax of the Java if statement-

if(condition){
  //statement(s)
}

Here condition is a boolean expression. If condition is evaluated to true if block is executed, if condition evaluates to false then the if block is not executed. If there is only a single statement with in the if condition then the curly braces are optional.

Java if statement examples

public class IfDemo {
  public static void main(String[] args) {
    int age = 25;
    // check for age
    if(age > 18){
      System.out.println("Eligible to vote (age > 18)");
    }
    System.out.println("After if statement");
  }
}
Output
Eligible to vote (age > 18)
After if statement

Here the condition (age > 18) is evaluated to true so the if block is executed.

In the same program if age is passed as less than 18.

public class IfDemo {
  public static void main(String[] args) {
    int age = 15;
    // check for age
    if(age > 18)
      System.out.println("Eligible to vote (age > 18)");
    System.out.println("After if statement");
  }
}
Output
After if statement

Here the condition (age > 18) is evaluated to false so the if block is not executed. Note that the curly braces are not used with the if statement as there is only a single statement.

Java if-else statement

In Java if-else statement condition is evaluated and the execution flow is routed based on whether the condition is true or false.

Syntax of the Java if-else statement-

if(condition){
  //statement(s)
}else{
  //statement(s)
}

In the if-else statement if block is executed when condition is evaluated to true, if condition evaluates to false then the else block is executed.

if-else Java

Java if-else statement examples

public class IfDemo {
  public static void main(String[] args) {
    int age = 25;
    // check for age
    if(age > 18){
      System.out.println("Eligible to vote (age > 18)");
    }else{
      System.out.println("Not eligible to vote (age < 18)");
    }
    System.out.println("After if statement");
  }
}
Output
Eligible to vote (age > 18)
After if-else statement

Since condition evaluates to true so the if block is executed.

public class IfDemo {
  public static void main(String[] args) {
    int age = 15;
    // check for age
    if(age > 18){
      System.out.println("Eligible to vote (age > 18)");
    }else{
      System.out.println("Not eligible to vote (age < 18)");
    }
    System.out.println("After if-else statement");
  }
}
Output
Not eligible to vote (age < 18)
After if-else statement

Java if-else-if ladder

You can also have a series of if-else if statements where each if and else if statement has a condition and a particular block is executed if the condition associated with that block evaluates to true.

Java if-else-if syntax-
if(condition1){
  statement(s);
}else if(condition2){
  statement(s);
}else if(condition3){
  statement(s);
}
.
.
.
else{
  statement(s);
}

In if-else-if statement condition is evaluated from the top. Whichever condition evaluates to true statements associated with that block are executed and rest of the statements are bypassed. Last else statement acts as a default which is executed if none of the condition evaluates to true. But the lase else statement is optional if it is not present and all the conditions are false then no statement is executed and the control comes out of if-else-if.

Java if-else-if example

public class IfDemo {
  public static void main(String[] args) {
    int angle = 55;
    
    if(angle < 90){
      System.out.println("Acute angle");
    }else if (angle == 90){
      System.out.println("Right Angle");
    }else if (angle > 90 && angle < 180){
      System.out.println("Obtuse angle");
    }else if (angle == 180){
      System.out.println("Straight angle");
    }else {
      System.out.println("angle more than 180");
    }
  }
}
Output
Acute angle

In the code first if condition itself is evaluated to true so none of the other conditions are evaluated.

Java nested if-else

You can have a if-else statement inside a if-else statement in Java. It is known as a nested if-else statement.

Java nested if-else example

public class IfDemo {

  public static void main(String[] args) {
    int angle = 155;
    
    if(angle < 180){
      if(angle < 90)
        System.out.println("Acute angle");
      else if(angle > 90){
        System.out.println("Obtuse angle");
      }else{
        System.out.println("Right Angle");
      }
    }else {
      if (angle == 180){
        System.out.println("Straight angle");
      }else {
        System.out.println("angle more than 180");
      }
    }
  }
}
Output
Obtuse angle

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


You may also like

August 25, 2022

Java Program to Find Factorial

In this post we’ll see a Java program to find the factorial of a number.

Factorial of a non-negative integer n is product of all positive integers less than or equal to n. For example

5! = 5 X 4 X 3 X 2 X 1 = 120

Factorial program in Java

Factorial program in Java can be written as both iterative as well as recursive solution. In this post both of the solutions are given.

Factorial program using iteration

In the following program user is asked to enter the number for which factorial has to be calculated. In iterative logic you can start a for loop with the entered number and decrease it by 1 in each iteration. What you need is the multiplication of all the numbers in the loop.

import java.util.Scanner;

public class Factorial {
  public static void main(String[] args) {
    // Input from user
    Scanner input = new Scanner(System.in);
    System.out.println("Enter a number: ");
    int number = input.nextInt();
    int factorial = 1;
    for(int i = number; i >= 1; i--){
      factorial = factorial * i; 
    }
    System.out.println("Factorial of " + number + " is " + factorial); 
  }
}
Output
Enter a number: 
5
Factorial of 5 is 120

Factorial program in Java using recursion

In the recursive logic to write factorial Java program, you need to call the same method recursively passing the (number – 1) as parameter every time until the base case (number = 1) is reached.

import java.util.Scanner;

public class Factorial {
  public static void main(String[] args) {
    // Input from user
    Scanner input = new Scanner(System.in);
    System.out.println("Enter a number: ");
    int number = input.nextInt();
    int factorial = calculateFactorial(number);

    System.out.println("Factorial of " + number + " is " + factorial); 
  }
	
  // Factorial using recursion
  private static int calculateFactorial(int num){
    // base case
    if(num == 1){
      return 1;
    }else{
      return num * calculateFactorial(num - 1);
    }
  }
}
Output
Enter a number: 
8
Factorial of 8 is 40320

That's all for the topic Java Program to Find Factorial. If something is missing or you have something to share about the topic please write a comment.


You may also like

August 24, 2022

JDBC ResultSetMetaData Interface

Using java.sql.ResultSetMetaData interface you can get metadata about the ResultSet object. When you retrieve data from DB a ResultSet object is returned with each ResultSet object there is an associated ResultSetMetaData object containing information about the returned ResultSet like table name, column count, column’s data type.

How to get ResultSetMetaData Object

You obtain the ResultSetMetaData instance by calling the getMetaData() method of the ResultSet.

ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE_NAME"); ResultSetMetaData rsmd = rs.getMetaData();

Methods in Java ResultSetMetaData

Some of the important methods of ResultSetMetaData are as given below-

  • getColumnCount()- Returns the number of columns in this ResultSet object.
  • getColumnName(int column)- Get the designated column's name.
  • getColumnType(int column)- Retrieves the designated column's SQL type.
  • getSchemaName(int column)- Get the designated column's table's schema.
  • getTableName(int column)- Gets the designated column's table name.
  • isAutoIncrement(int column)- Indicates whether the designated column is automatically numbered.

ResultSetMetaData Java Example

DB used is MySql, schema is knpcode and table used is EMPLOYEE with columns as id, FIRST_NAME, LAST_NAME and DEPARTMENT note that id is auto-incremented.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

public class RSMDDemo {
  public static void main(String[] args) {
    Connection connection = null;
    try {
      // Load driver
      Class.forName("com.mysql.cj.jdbc.Driver");
      // connection object
      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/knpcode", 
                   "root", "admin");
      // create Statement object   
      Statement statement = connection.createStatement();  
      ResultSet rs = statement.executeQuery("Select * from Employee");
      System.out.println("***ResultSet Metadata information***");
      ResultSetMetaData rsmd = rs.getMetaData();
      int columnCount = rsmd.getColumnCount();	      
      System.out.println("Number of columns in each row- " + columnCount);
      System.out.println("ID column auto incremented- " + rsmd.isAutoIncrement(1));
      System.out.println("Table Name- " + rsmd.getTableName(2));
      for(int i = 1; i <= columnCount; i++) {
    	  System.out.println("Column " + rsmd.getColumnName(i) + " is of type " + rsmd.getColumnTypeName(i));
      }
  //	      // Iterate through ResultSet
  //	      while(rs.next()){
  //	        System.out.println("id: " + rs.getInt("id") + 
  //	           " First Name: " + rs.getString("FIRST_NAME") + 
  //	           " Last Name: " + rs.getString("LAST_NAME")+ 
  //	           " Dept: " + rs.getString("DEPARTMENT")); 
  //	      } 
    }catch(ClassNotFoundException | SQLException e) {
      e.printStackTrace();
    }finally{
      if(connection != null){
        //close connection 
        try {
          connection.close();
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
  }
}
Output
***ResultSet Metadata information***
Number of columns in each row- 4
ID column auto incremented- true
Table Name- employee
Column id is of type INT
Column first_name is of type VARCHAR
Column last_name is of type VARCHAR
Column department is of type VARCHAR

That's all for the topic JDBC ResultSetMetaData Interface. If something is missing or you have something to share about the topic please write a comment.


You may also like

August 23, 2022

JDBC DatabaseMetaData Interface

Using java.sql.DatabaseMetaData interface you can get metadata about the DB you are connected to.

DatabaseMetaData interface in Java has methods to get information about-

  • Database like DB Product name and version, scehemas available in DB.
  • JDBC Driver like the driver’s name and version
  • Tables in any DB schema,
  • Views in the Schema
  • Stored procedures and functions

How to get DatabaseMetaData Object

You obtain the DatabaseMetaData instance by calling the getMetaData() method of the Connection class.

DatabaseMetaData databaseMetaData = connection.getMetaData();

DB Product, version and user information using DatabaseMetaData

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

public class MetaDataInfo {
  public static void main(String[] args) {
    Connection connection = null;
    try {
      Class.forName("com.mysql.cj.jdbc.Driver");
      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/knpcode", 
                        "root", "admin");
      // DBMetaData instance
      DatabaseMetaData dbMetaData = connection.getMetaData();
      // Database information
      System.out.println("DB Name - " + dbMetaData.getDatabaseProductName());
      System.out.println("DB Version - " + dbMetaData.getDatabaseProductVersion());
      System.out.println("DB Major Version - " + dbMetaData.getDatabaseMajorVersion());
      System.out.println("DB Minor Version - " + dbMetaData.getDatabaseMinorVersion());
      System.out.println("DB User - " + dbMetaData.getUserName());
      
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally{
      if(connection != null) {
        try {
          connection.close();
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } 
    }
  }
}

JDBC Driver Name, version information using DatabaseMetaData

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

public class MetaDataInfo {
  public static void main(String[] args) {
    Connection connection = null;
    try {
      Class.forName("com.mysql.cj.jdbc.Driver");
      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/knpcode", 
                        "root", "admin");
      // DBMetaData instance
      DatabaseMetaData dbMetaData = connection.getMetaData();
      // Driver information
      System.out.println("Driver Name - " + dbMetaData.getDriverName());
      System.out.println("Driver Version - " + dbMetaData.getDriverVersion());
      System.out.println("Driver Major Version - " + dbMetaData.getDriverMajorVersion());
      System.out.println("Driver Minor Version - " + dbMetaData.getDriverMinorVersion());
      System.out.println("JDBC Major Version - " + dbMetaData.getJDBCMajorVersion());
      System.out.println("JDBC Minor Version - " + dbMetaData.getJDBCMinorVersion());
      
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally{
      if(connection != null) {
        try {
          connection.close();
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } 
    }
  }
}

Listing tables in DB using DatabaseMetaData

You can get a list of tables in the DB using getTables() method.

getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types)

Parameters passed to this method are-

  • catalog- A catalog name
  • schemaPattern- A schema name pattern
  • tableNamePattern- A table name pattern
  • types- A list of table types. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".

If you pass values for any of these parameters that helps in narrowing down the search and limit the number of tables returned. You can pass all of these parameters as null to return all the table types.

The getTables() method returns a ResultSet where each row contains a table description. This table description is made up of 10 columns. For getting the table names you will have to get the third column value from each row in the ResultSet.

  • TABLE_CAT- Table catalog
  • TABLE_SCHEM- Table schema
  • TABLE_NAME- Table name
  • TABLE_TYPE- Table type
  • REMARKS- Explanatory comment on the table
  • TYPE_CAT- The types catalog
  • TYPE_SCHEM- The types schema
  • TYPE_NAME- Type name
  • SELF_REFERENCING_COL_NAME- Name of the designated "identifier" column of a typed table
  • REF_GENERATION- Specifies how values in SELF_REFERENCING_COL_NAME are created. Values are "SYSTEM", "USER", "DERIVED".
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MetaDataInfo {
  public static void main(String[] args) {
    Connection connection = null;
    try {
      Class.forName("com.mysql.cj.jdbc.Driver");
      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/knpcode", 
                        "root", "admin");
      // DBMetaData instance
      DatabaseMetaData dbMetaData = connection.getMetaData();
      ResultSet rs = dbMetaData.getTables(null, null, null, null);
      while (rs.next()){
       // Third column for table name
       System.out.println("Table name " + rs.getString(3));
      }
      
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally{
      if(connection != null) {
        try {
          connection.close();
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } 
    }
  }
}

If you want to list only tables then you can limit the search by passing table types as table.

String table[] = {"table"};
ResultSet rs = dbMetaData.getTables(null, null, null, table);

If you want to list only views then you can limit the search by passing table types as view.

String table[] = {"view"};
ResultSet rs = dbMetaData.getTables(null, null, null, table);

Columns of a DB table using DatabaseMetaData

You can get the column names of a specific table by using the getColumns() method.

getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)

Parameters passed to this method are-

  • catalog- A catalog name
  • schemaPattern- A schema name pattern
  • tableNamePattern- A table name pattern
  • columnNamePattern- A column name pattern

The getColumns() method returns a ResultSet where each row contains a column description. This column description is made up of 24 columns. For getting the column names you will have to get the fourth column value from each row in the ResultSet.

public class MetaDataInfo {
  public static void main(String[] args) {
    Connection connection = null;
    try {
      Class.forName("com.mysql.cj.jdbc.Driver");
      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/knpcode", 
                        "root", "admin");
      // DBMetaData instance
      DatabaseMetaData dbMetaData = connection.getMetaData();
      ResultSet rs = dbMetaData.getColumns(null, null, "Employee", null);
     
      while (rs.next()){
       System.out.println("Column name-" + rs.getString(4));
      }
      
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally{
      if(connection != null) {
        try {
          connection.close();
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } 
    }
  }
}

That's all for the topic JDBC DatabaseMetaData Interface. If something is missing or you have something to share about the topic please write a comment.


You may also like

August 22, 2022

Constructor in Java

Constructor in Java is a special method which is called automatically to initialize an object when the object is created.

Need for a constructor

When an object is created it is a very common requirement to initialize that object (provide values for its instance variables). To facilitate that a constructor is provided and Java automatically calls that constructor when an object is created to guarantee initialization.

Java constructor example

public class ConstructorDemo {
  int num;
  String name;
  public ConstructorDemo(int num, String name){
    this.num = num;
    this.name = name;
  }

  public static void main(String[] args) {
    ConstructorDemo cd = new ConstructorDemo(10, "Rodrigo");
    System.out.println("Number is " + cd.num + " Name is " + cd.name);
  }
}
Output
Number is 10 Name is Rodrigo

In the above code constructor is defined as follows, which is a parameterized constructor (constructor with arguments).

public ConstructorDemo(int num, String name){
  this.num = num;
  this.name = name;
}

When an object of the class is created using the new() operator, constructor is called automatically to initialize the object before the object creation is completed by the new operator.

Rules for Constructors

Since constructor in Java is a special method so its usage is governed by special rules which are as follows.

  1. Constructor has the same name as the class that way Java can identify a constructor and call it automatically.
  2. Constructor doesn’t have a return type not even void. That’s what differentiates a constructor from a regular method. If a return type is specified then it is not treated as a constructor but a regular method.
  3. A constructor in Java can have a public, protected, default (package-private) or private access modifier.
  4. A constructor in Java can’t be final. Trying to make a constructor final results in compile time error “Illegal modifier for the constructor in type; only public, protected & private are permitted

Types of constructors

Constructor in Java can be of two types-

  • No-arg constructor- A constructor with no parameters. A default no-arg constructor is implicitly inserted by the Java itself if you don’t provide a constructor in your class.
  • Parameterized constructor- A constructor with parameters. If you explicitly specify a constructor in your class then the default no-arg constructor is not inserted implicitly.
No-arg constructor example
public class ConstructorDemo {
  public static void main(String[] args) {
    ConstructorDemo cd = new ConstructorDemo();
  }
}

Here when the object is created ConstrucorDemo cd = new ConstrucorDemo(); the default no-arg constructor is called.

Parameterized Constructor
public class ConstructorDemo {
  int num;
  String name;
  public ConstructorDemo(int num, String name){
    this.num = num;
    this.name = name;
  }

  public static void main(String[] args) {
    ConstructorDemo cd = new ConstructorDemo(10, "Rodrigo");
    System.out.println("Number is " + cd.num + " Name is " + cd.name);
    
    //This will call no-arg constructor - ERROR
    ConstructorDemo cd1 = new ConstructorDemo();
  }
}

This code will result in compile time error - “The constructor ConstrucorDemo() is undefined”. Since a parameterized constructor is already provided so default no-arg constructor is not provided in this case.

If you want no-arg constructor also in this case then you will have to explicitly write it. You can have more than one constructor in the same class that is known as constructor overloading in Java.

public class ConstructorDemo {
  int num;
  String name;
  // Parameterized constructor
  public ConstructorDemo(int num, String name){
    this.num = num;
    this.name = name;
  }
  // no-arg constructor	
  public ConstructorDemo(){
    
  }
	
  public static void main(String[] args) {
    ConstructorDemo cd = new ConstructorDemo(10, "Rodrigo");
    System.out.println("Number is " + cd.num + " Name is " + cd.name);
    
    //This will call no-arg constructor
    ConstructorDemo cd1 = new ConstructorDemo();
  }
}

Private constructor in Java

A constructor in the class can have private access modifier too, in that case constructor will only be visible with in the class it is created so no other class would be able to create instance of the class. That helps in controlling the instantiation of the class. One class design where you can see use of private constructor is Singleton design pattern where you control the instantiation of the class so that there is only one instance of the class.

Private constructor example in Java

public class ConstructorDemo {
  int num;
  String name;
  // Parameterized constructor
  private ConstructorDemo(int num, String name){
    this.num = num;
    this.name = name;
  }

  public static void main(String[] args) {
    ConstructorDemo cd = new ConstructorDemo(10, "Rodrigo");
    System.out.println("Number is " + cd.num + " Name is " + cd.name);
  }
}

When object is created in the same class- ConstructorDemo cd = new ConstructorDemo(10, "Rodrigo"); that is OK.

But trying to create object of ConstructorDemo class from any other class results in an error “The constructor ConstructorDemo(int, String) is not visible”.

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


You may also like