Recent Tutorials and Articles
    Bounded Wildcard Generics in Java
    Published on: 9th August 2013

    This tutorial explains the lower bounded and upper bounded wildcard Generics and demonstrates their simple usage.

    This tutorial assumes that you know what Generics are and can write a very basic program using Generics. If not, you are strongly recommended to read this.

    As we know that Generics code certainly has got an edge over non-generics code. Moreover if you are using Java 5 or higher version, the compiler will generate the warnings for not using Generics. So if situation allows, you would certainly want to convert your legacy code to Generics.

    Suppose we have following code to write the Serializable objects into the files -

    ObjectsFileStream.java
    package com.sts.allprogrammingtutorials.generics;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.Collection;
    
    /**
     * @author Sain Technology Solutions
     *
     */
    public class ObjectsFileStream {
    	private static final String FILE_LOCATION = "C:\\dropbox\\";
    	
    	public void write(Collection objects) throws IOException {
    		
    		for(Object object : objects) {
    			//Check if the object is serializable i.e. implementing Serializable interface
    			if(!(object instanceof Serializable)) {
    				System.out.println("Object: " + object +" is not serializable");
    			}
    			
    			final File file = new File(FILE_LOCATION + File.separator+ object.getClass().getCanonicalName() + 
    					"_" + object.hashCode());
    			file.createNewFile();
    			
    			ObjectOutputStream objectOutputStream = null;
    			try {
    				
    				final FileOutputStream fileOutputStream = new FileOutputStream(file);
    				objectOutputStream = new ObjectOutputStream(fileOutputStream);
    				
    				objectOutputStream.writeObject(object);
    				
    			} finally {
    				if(objectOutputStream != null) {
    					objectOutputStream.close();
    				}
    			}
    			
    		}
    		
    	}
    }
    
    

    Here is the code to run the above program (Please make sure that you have got dropbox folder into C drive or change the FILE_LOCATION to an existing path) -

    ObjectsFileStreamDemo.java
    package com.sts.allprogrammingtutorials.generics;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collection;
    
    
    /**
     * @author Sain Technology Solutions
     *
     */
    public class ObjectsFileStreamDemo {
    	
    	public static void main(String[] args) throws IOException {
    		
    		//Collection of Strings to serialize
    		Collection objects = new ArrayList();
    		objects.add("One");
    		objects.add("Two");
    		objects.add("Three");
    		
    		final ObjectsFileStream objectsFileStream = new ObjectsFileStream();
    		objectsFileStream.write(objects);
    	}
    }
    
    

    On running the above code, you would see 3 files in your C://dropbox location, provided you have got the write access in this directory.

    Converting Legacy code to Generics

    A naive attempt to convert the code into Generics might be to either -

    1. Replace Collection with Collection<Object> or
    2. Replace Collection with Collection<Serializable> in order to remove the instanceof check as below
    ObjectsFileStreamGenerics.java
    package com.sts.allprogrammingtutorials.generics;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.Collection;
    
    /**
     * @author Sain Technology Solutions
     *
     */
    public class ObjectsFileStreamGenerics {
    	private static final String FILE_LOCATION = "C:\\dropbox\\";
    	
    	public void write(Collection<Serializable> objects) throws IOException {
    		
    		for(Serializable object : objects) {
    			
    			final File file = new File(FILE_LOCATION + File.separator+ "");
    			file.createNewFile();
    			
    			ObjectOutputStream objectOutputStream = null;
    			try {
    				
    				final FileOutputStream fileOutputStream = new FileOutputStream(file);
    				objectOutputStream = new ObjectOutputStream(fileOutputStream);
    				
    				objectOutputStream.writeObject(object);
    				
    			} finally {
    				if(objectOutputStream != null) {
    					objectOutputStream.close();
    				}
    			}
    			
    		}
    		
    	}
    	
    }
    
    

    Certainly, this code looks more robust and type safe, and you no longer need to check if the Object to be serialized implements Serializable interface. However as soon as you start changing Demo class code to Generics, you will get a compile time error at the write method call as below -

    ObjectsFileStreamGenericsDemo.java
    package com.sts.allprogrammingtutorials.generics;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collection;
    
    
    /**
     * @author Sain Technology Solutions
     *
     */
    public class ObjectsFileStreamGenericsDemo {
    	
    	public static void main(String[] args) throws IOException {
    		
    		//Collection of Strings to serialize
    		Collection<String> objects = new ArrayList<String>();
    		objects.add("One");
    		objects.add("Two");
    		objects.add("Three");
    		
    		final ObjectsFileStreamGenerics objectsFileStream = new ObjectsFileStreamGenerics();
    		
    		//Compilation Error: The method write(Collection<Serializable>) is not applicable for the arguments (Collection<String>)
    		objectsFileStream.write(objects); 
    	}
    }
    
    

    It might look odd at first, as since String is subtype of Serializable, you would expect Collection<String> to be subtype of Collection<Serializable>, hence no problems should be there in this call.

    However the fact is that Collection<String> is not subtype of Collection<Serializable>. This is where wildcard generics come into the picture.

    Upper Bounded Wildcard Generics

    In this particular scenarion, we need to define a Generic type which can accept Serializable as well as any class implementing this. Since we know our upper limit, we need an Upper bounded wildcard Generics.

    ? is defined as wildcard character in Generic Types and upper bounded generics use extends keyword to tell that it will accept any type same or extending what we have after extends.

    For above example, the generics type that we need is ? extends Serializable meaning that all classes implementing Serializable would be accepted by this.

    Therefore, the correct Generics code for our example would be as below -

    ObjectsFileStreamGenerics.java
    package com.sts.allprogrammingtutorials.generics;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.Collection;
    
    /**
     * @author Sain Technology Solutions
     *
     */
    public class ObjectsFileStreamGenerics {
    	private static final String FILE_LOCATION = "C:\\dropbox\\";
    	
    	public void write(Collection<? extends Serializable> objects) throws IOException {
    		
    		for(Serializable object : objects) {
    			
    			final File file = new File(FILE_LOCATION + File.separator+ "");
    			file.createNewFile();
    			
    			ObjectOutputStream objectOutputStream = null;
    			try {
    				
    				final FileOutputStream fileOutputStream = new FileOutputStream(file);
    				objectOutputStream = new ObjectOutputStream(fileOutputStream);
    				
    				objectOutputStream.writeObject(object);
    				
    			} finally {
    				if(objectOutputStream != null) {
    					objectOutputStream.close();
    				}
    			}
    			
    		}
    		
    	}
    }
    
    
    Lower Bounded Wildcard Generics

    In some cases, you might need to have lower bounded wildcard meaning that any class which is super class of the specified type should be accepted. In this case, super keyword is used in place of extends keyword.

    An example of the lower bounded wildcard Generics would be ? super Integer meaning it would accept Integer and any of its super types (Number, Object etc.)

    Thank you for reading through the tutorial. In case of any feedback/questions/concerns, you can communicate same to us through your comments and we shall get back to you as soon as possible.

    Published on: 9th August 2013

    Comment Form is loading comments...