HashMap vs Hashtable vs HashSet

I was reading about collection framework of Java. And was studying Hashtable, HashMap and HashSet. Its quite interesting to know the differences between them. In this post I will discuss these three with examples.

Hashtable

Hashtable is basically a datastructure to retain values of key-value pair.

  • It didn’t allow null for both key and value. You will get NullPointerException if you add null value.
  • It is synchronized. So it comes with its cost. Only one thread can access in one time
Hashtable<Integer,String>; cityTable = new Hashtable<Integer,String>();
cityTable.put(1, "Lahore");
cityTable.put(2, "Karachi");
cityTable.put(3, null); /* NullPointerEcxeption at runtime*/

System.out.println(cityTable.get(1));
System.out.println(cityTable.get(2));
System.out.println(cityTable.get(3));

HashMap

Like Hashtable it also accepts key value pair.

  • It allows null for both key and value
  • It is unsynchronized. So come up with better performance
HashMap<Integer,String> productMap = new HashMap<Integer,String>();
productMap.put(1, "Keys");
productMap.put(2, null);

HashSet

HashSet does not allow duplicate values. It provides add method rather put method. You also use its contain method to check whether the object is already available in HashSet. HashSet can be used where you want to maintain a unique list.

HashSet<String> stateSet = new HashSet<String>();
stateSet.add ("CA");
stateSet.add ("WI");
stateSet.add ("NY");

if (stateSet.contains("PB")) /* if CA, it will not add but shows following message*/
System.out.println("Already found");
else
stateSet.add("PB");
Advertisements

Generate Capatcha in JAVA


package com.project.util;

import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Random;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;

/**
* Action implementation class CaptchaAction
*/
public class CaptchaGeneration {
private static final Logger log = Logger.getLogger(CaptchaGeneration.class);

private String captchValue;
private String prevImageName;
private String currentImageName;

public CaptchaGeneration(){

}
public CaptchaGeneration(String prevImageName){
       this.prevImageName = prevImageName;
}

public String getCaptchValue() {
        return captchValue;
}

public void setCaptchValue(String captchValue) {
        this.captchValue = captchValue;
}
public String getPrevImageName() {
return prevImageName;
}
public void setPrevImageName(String prevImageName) {
this.prevImageName = prevImageName;
}
public String getCurrentImageName() {
return currentImageName;
}
public void setCurrentImageName(String currentImageName) {
this.currentImageName = currentImageName;
}
public void refresh(String tempFolderPath) throws Exception {
log.info("Inside execute of CaptchaAction");
int height = 30;
int width = 120;
File f = null;
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = image.createGraphics();
Random r = new Random();
String token = Long.toString(Math.abs(r.nextLong()), 36);
String ch = token.substring(0, 6);
GradientPaint gp = new GradientPaint(30, 30, Color.gray, 15, 25, Color.GRAY, true);
graphics2D.setPaint(gp);
Font font = new Font("Verdana", Font.CENTER_BASELINE, 26);
graphics2D.setFont(font);
graphics2D.drawString(ch, 2, 24);
graphics2D.dispose();
setCaptchValue(ch);
StringBuffer fileName = null;
//String path = null;
FileOutputStream fout = null;
try {
fileName = new StringBuffer("Captcha").append(System.nanoTime()).append(".jpeg");
//path = req.getRealPath(CommonConstant.TEMPFILES_FOLDER_NAME);
log.info("path : " + tempFolderPath);
if(getPrevImageName()!=null){
f = new File(tempFolderPath + "/" + getPrevImageName());
log.info("File to delete : " + getPrevImageName());
if(f.exists()){
boolean isDeletd = f.delete();
log.info("FIle deleted ::::::::::::: " + isDeletd);
}
}
f = null;
f = new File(tempFolderPath + "/" + fileName.toString());
fout = new FileOutputStream(f);
ImageIO.write(image, "jpeg", fout);
log.info("file name is :: " + fileName.toString());
setCurrentImageName(fileName.toString());
setPrevImageName(fileName.toString());
} catch (Exception e) {
log.error("CaptchaGeneration : refresh() : Exception : " , e);
throw e;
}finally{
fileName = null;
f = null;
if(fout!=null){
fout.close();
}
fout = null;
}

}

}

Vector or ArrayList — which is better?

 Vector or ArrayList — which is better and why?

Sometimes Vector is better; sometimes ArrayListis better; sometimes you don’t want to use either. I hope you weren’t looking for an easy answer because the answer depends upon what you are doing. There are four factors to consider:

  • API
  • Synchronization
  • Data growth
  • Usage patterns

Let’s explore each in turn.

API

In The Java Programming Language (Addison-Wesley, June 2000) Ken Arnold, James Gosling, and David Holmes describe the Vector as an analog to the ArrayList. So, from an API perspective, the two classes are very similar. However, there are still some major differences between the two classes.

Synchronization

Vectors are synchronized. Any method that touches the Vector‘s contents is thread safe. ArrayList, on the other hand, is unsynchronized, making them, therefore, not thread safe. With that difference in mind, using synchronization will incur a performance hit. So if you don’t need a thread-safe collection, use the ArrayList. Why pay the price of synchronization unnecessarily?

Data growth

Internally, both the ArrayList and Vector hold onto their contents using an Array. You need to keep this fact in mind while using either in your programs. When you insert an element into an ArrayList or a Vector, the object will need to expand its internal array if it runs out of room. A Vector defaults to doubling the size of its array, while the ArrayList increases its array size by 50 percent. Depending on how you use these classes, you could end up taking a large performance hit while adding new elements. It’s always best to set the object’s initial capacity to the largest capacity that your program will need. By carefully setting the capacity, you can avoid paying the penalty needed to resize the internal array later. If you don’t know how much data you’ll have, but you do know the rate at which it grows, Vector does possess a slight advantage since you can set the increment value.

Usage patterns

Both the ArrayList and Vector are good for retrieving elements from a specific position in the container or for adding and removing elements from the end of the container. All of these operations can be performed in constant time — O(1). However, adding and removing elements from any other position proves more expensive — linear to be exact: O(n-i), where n is the number of elements and i is the index of the element added or removed. These operations are more expensive because you have to shift all elements at index i and higher over by one element. So what does this all mean?

It means that if you want to index elements or add and remove elements at the end of the array, use either a Vector or an ArrayList. If you want to do anything else to the contents, go find yourself another container class. For example, the LinkedList can add or remove an element at any position in constant time — O(1). However, indexing an element is a bit slower — O(i) where i is the index of the element. Traversing an ArrayList is also easier since you can simply use an index instead of having to create an iterator. The LinkedList also creates an internal object for each element inserted. So you have to be aware of the extra garbage being created.

Finally, in “PRAXIS 41” from Practical Java (Addison-Wesley, Feb. 2000) Peter Haggar suggests that you use a plain old array in place of either Vector or ArrayList — especially for performance-critical code. By using an array you can avoid synchronization, extra method calls, and suboptimal resizing. You just pay the cost of extra development time.

Servlet Init() method magic

A Common Mistake in Servlet Init() Methods:

Servlet init methods allows a servlet to perform one-time initialization prior to servicing requests. One common mistake when implementing init method is in this form:

public void init(ServletConfig config)
 throws ServletException {
 //do custom initialization ...
 System.out.println(" init(ServletConfig config) invoked.");
 ...
}

This is wrong because it doesn’t invoke super.init(ServletConfig). As a result, ServletConfig is not stored in the servlet instance, and subsequent calls to getServletConfig will return null.

Another variant of this mistake is to store the ServletConfig parameter in a class variable of the concrete servlet class:

private ServletConfig config;

public void init(ServletConfig config)
 throws ServletException {
 this.config = config;
 System.out.println(" init(ServletConfig config) invoked.");
 //do custom initialization ...
 ...
}

This is also wrong because config saved in the current servlet won’t be available to its superclass, usually GenericServlet or HttpServlet. When the default implementation of getServletConfig() method looks for ServletConfig in superclasses, it’s still null. The only way it can work is that you also override getServletConfig method to look in the concrete servlet class, which is unusual and unnecessary.

 

This is the error from Glassfish/JavaEE SDK 5, when running a servlet with those incorrect init methods:

java.lang.NullPointerException
test.HelloWorldServlet.doGet(HelloWorldServlet.java:14)
javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:73)
com.sun.enterprise.web.VirtualServerPipeline.invoke(VirtualServerPipeline.java:120)
org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:231)

To implement servlet init methods correctly, you have several options:

  • If you only need to save ServletConfig, do not override any init methods in servlet class. It’s already implemented in servlet superclass GenericServlet.
  • If you have custom initialization work to do, override the no-arg init() method, and forget about init(ServletConfig). Is it ok to call getServletConfig() method inside the no-arg init() method? Yes, an instance of ServletConfig has already been saved by superclass GenericServlet.
  • If you really want to override init(ServletConfig), make sure you invoke super.init(ServletConfig);, usually as the first line, though it’s not strictly required.

Why Servlet Init() Method confusing?

You may ask, what is the difference between servlet init() and init(ServletConfig), and why is it so confusing?

When servlet was invented, there was only one init method, the one with parameter ServletConfig. The no-arg init method was added around Servlet 2.3 timeframe, mainly to address this common mistake. This solution applies a Template Design Pattern to outline what needs to be done in init method and also keeps it extensible for concrete servlet classes.

init(ServletConfig) is the template method, which stores ServletConfig, and then delegates to init(). This is what javax.servlet.GenericServlet.init(ServletConfig) looks like:

public void init(ServletConfig config)
 throws ServletException {
 this.config. = config;
 init();
}

The real work of initialization is supposed to be done in init() method, which can be overrid by servlet subclasses. Its default implementation in javax.servlet.GenericServlet is merely a no-op.

From the above code snippet, when init() in your servlet class is invoked by the container, an instance of ServletConfig has already been saved. So you can safely call getServletConfig() inside of init() method.

Servlet classes rarely need to know about init(ServletConfig ) method. Only web containers need to invoke it. Ideally, this method should be declared as final or even private in GenericServlet. But that would break backward compatibility.

Having two overloaded init methods may also add to the confusion. Unless developers read the Javadoc carefully, their relationship (one calling the other) is unclear. So it’s possible someone will override init() method like this:

@Override public void init()
 throws ServletException {
 //do some initialization work first,
 //then call init(ServletConfig)
 init(null);
}

It will cause infinite loop and java.lang.StackOverflowError during servlet initialization, and the servlet will never be put into service. I hope I didn’t make it more confusing.