Tuesday, 9 December 2014

Enum Data Types in Java

Background

Sometime we need to program to restrict use inputs. Lets take a scenario - you are opening a pet store. As a starter you decide only to provide  - Dogs, Cats and Parrots. Next you have to design a Java program to provide the pet to customers. One way would be as follows - 

class PetStore {
    
    public static final String CATEGORY_DOGS = "Dogs";
    public static final String CATEGORY_CATS = "Cats";
    public static final String CATEGORY_PARROTS = "Parrots";
    
    public void getPet(String petType) {
        switch(petType){
        case CATEGORY_DOGS : System.out.println("You are opting for a pet Dog");
                            break;
        case CATEGORY_CATS : System.out.println("You are opting for a pet Cat");
                            break;
        case CATEGORY_PARROTS : System.out.println("You are opting for a pet Parrot");
                            break;
        default : System.out.println("We do not provide other pet animals");
        }
    }
}


It serves the purpose. But it does not stop user from entering Lion, Tiger does it ? Program would fall back to default saying we do not provide other pet Animals. But Lion, Tiger are not pet in the first place. One way to restrict user input is declaring an Enum. Lets come to that.



Using Enums

enum PetTypes {
    DOGS,CATS,PARROTS
}

class PetStore {
    
    public void getPet(PetTypes petType) {
        switch(petType){
        case DOGS : System.out.println("You are opting for a pet Dog");
                            break;
        case CATS : System.out.println("You are opting for a pet Cat");
                            break;
        case PARROTS : System.out.println("You are opting for a pet Parrot");
                            break;
        }
    }
}

Now you have successfully restricted user from entering one of the three allowed values. That is not it Enums has other advantages too.Lets come to those. Lets say you also need to store the number of available pet of each category. You can store that in enum too. Each enum value can have multiple attributes.


enum PetTypes {
    DOGS(10),CATS(7),PARROTS(9);
    
    int availableUnits;
    
    //enum constructors are implicitly private
    PetTypes(int availableUnits) {
        this.availableUnits = availableUnits;
    }

    public int getAvailableUnits() {
        return availableUnits;
    }
    
}

class PetStore {
    
    public void getPet(PetTypes petType) {
        switch(petType){
        case DOGS : System.out.println("You are opting for a pet Dog.");
                            break;
        case CATS : System.out.println("You are opting for a pet Cat");
                            break;
        case PARROTS : System.out.println("You are opting for a pet Parrot");
                            break;
        }
        System.out.println("Available units are : " + petType.getAvailableUnits());
    }
}


You can test it by

    public static void main(String args[])
    {
        new PetStore().getPet(PetTypes.CATS);
    }


You will get :

You are opting for a pet Cat
Available units are : 7

Note : When you say DOGS(10), corresponding constructor is called i.e PetTypes(10).

Enums are better than a bunch of constants because it provides type‐safe
checking.

Important Points

  • Enums are implicitly private, static and final. 
  • Each declared enum implicitly inherits java.lang.Enum.
  • You can use valueOf() and name() methods on enums.
  • You can compare enums with == operator.
  • You cannot use new operator on enums. Not even inside enum definition. Outside you cannot because constructor is implicitly private. 
  • Enums cannot be local meaning you cannot declare them inside a method. They should be declared and defines inside of a top level class or an interface.

Question : 

 1. What happens when you compile the following code - 

enum PetTypes {
    int availableUnits;             //  #1
    DOGS(10),CATS(7),PARROTS(9);    //  #2
    
    //enum constructors are implicitly private
    PetTypes(int availableUnits) {
        this.availableUnits = availableUnits;
    }

    public int getAvailableUnits() {
        return availableUnits;
    }
 }

Above enum definition is incorrect and will not compile. You need to declare enum elements first before any other attributes. In short you need to interchange line #1 and #2 for above code to compile. (JLS reference)
NOTE : You can also create an enum from a String. This is helpful when working with older
code. The String passed in must match exactly, though.

Eg.

PetTypes s1 = PetTypes.valueOf("DOGS"); // DOGS
PetTypes s2 = PetTypes.valueOf("dogs"); // exception



NOTE : The final clone method in Enum ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by the enum constants.

NOTE : Another thing that you can’t do is extend an enum. The values in an enum are all that are allowed. You cannot add more at runtime by extending the enum.

You can also have abstract method in an enum in which case each enum will have to implement the abstract method -

    public enum PetTypes {
        DOGS {
            public void printHours() { System. out .println("9am-3pm"); }
        }, CATS {
            public void printHours() { System. out .println("9am-5pm"); }
        }, PARROTS {
            public void printHours() { System. out .println("9am-7pm"); }
        }, RABBIT {
            public void printHours() { System. out .println("9am-5pm"); }
        };
        public abstract void printHours();
    }


If we don’t want each and every enum value to have a method, we can create a default
implementation and override it only for the special cases:

     public enum PetTypes {
        DOGS {
            public void printHours() { System. out .println("9am-3pm"); }
        }, CATS {
            public void printHours() { System. out .println("9am-5pm"); }
        }, PARROTS , RABBIT ;
        public void printHours() { System. out .println("9am-9pm"); };
    } 
  
NOTE : If in your enum class all you have are types of that enums you can skip the semicolon. So you can do something like -

    enum Flavors {
        VANILLA, CHOCOLATE, STRAWBERRY
    }


But you cannot do something like -

    enum Flavors {
        VANILLA, CHOCOLATE, STRAWBERRY //not allowed, need semicoln here
       
        Flavors(){}
    }


This will give compilation error. If you have anything more than enum declarations you need to add a semicolon. Also as stated earlier enums should be the 1st thing in the enum structure.

NOTE : The ordinal() method of an enum returns its corresponding int value. Like arrays,
enums are zero based. Remember that the index of an enum may change when you recompile
the code and should not be used for comparison.

Related Links

Monday, 8 December 2014

Method Overloading resolution in Java

Background

Instead of giving an overview of what this post entails let me give you a quick problem to solve. Lets say you have few methods

public static void execute( int data) {System.out.println("int")}
public static  void execute( short data) {System.out.println("short")}
public static  void execute( Object data) {System.out.println("object")}
public static  void execute( String data) {System.out.println("string")}


and I call following methods - 

public static void main(String[] args) {
    byte byt = 3;
    execute(byt); // 1st call
    execute(10); // 2nd call
    Integer i = 6;
    execute(6); // 3rd call
    execute("Test"); // 4th call
}

What would be the output ?
It would be - 

short
int
object
string

Surprised? Wondering ?

Will solve the mystery in a minute :). Lets get our basics clear first and then there would be no need for me to go ahead and explain the outputs.

Few points to note about the question -
  1. The methods you see have same name, return type but different types of arguments. This is called method overloading. For more details refer Overriding Methods in Java - How it works?
  2. Next we are calling methods some of which that do not exactly match the ones which are defined. Like calling execute() with byte 3. There is no method which takes byte as argument. But there is short, int and even Object argument methods that are compatible. Note the word "compatible" but only one is chosen from it - and we saw it was short in this case. Java as all programming languages has rules which dictates these things which is exactly what we will see in some time.

Rules for method overloading resolution

  1.  Java Compiler always tries to choose the most specific method available with least number of modifications to the arguments.
  2. Next point is about Boxing / Unboxing. Java developers wanted the old code to work exactly the same a sit used to work before boxing / unboxing.
  3. With points 1 and 2 in mind the order in which preference is given is -

    Widening (size wise)[Minimum first] > Boxing/Unboxing > variable arguments.

 Primitive types sizes in Java

  • byte: The byte data type is an 8-bit signed two's complement integer.
  • short: The short data type is a 16-bit signed two's complement integer.
  • int: By default, the int data type is a 32-bit signed two's complement integer.
  • long: The long data type is a 64-bit two's complement integer. 
  • float: The float data type is a single-precision 32-bit IEEE 754 floating point.
  • double: The double data type is a double-precision 64-bit IEEE 754 floating point.
  • boolean: The boolean data type has only two possible values: true and false.
  • char: The char data type is a single 16-bit Unicode character.

Primitive types default values in Java



Now give the question in backgrounds section another try.

With above rules in mind lets try to solve the question posted at the top of this post.

First call was

byte byt = 3;
execute(byt); // 1st call

As per above rule most preferred was would be widening. There are two options here. Widen byte (8bit) to a short (16 bit) or an int (32 bit). Widening with lowest size is preferred (which is short in this case) and hence we got short printed.

Next is

execute(10); // 2nd call

and is a direct call as we have execute method with int parameter. So int is printed.

Next we have

Integer i = 6;
execute(6); // 3rd call

Since we do not have a method with Integer as argument we will go for next best case and that is polymorphic superclass. Object is superclass of all objects implicitly. So we get object printed.

Lastly we have

execute("Test"); // 4th call

Again we have execute method with String which is chosen here. Again straight forward.

Note : Widening is preferred over boxing/unboxing which is preferred over variable arguments. By variable arguments I mean something like

public void execute (int ...x)

Hope this clarifies all doubts regarding our original question.

Note : Java Compilation will fail if there are no matches or ambiguous matches for a function call.

Example of no matches : 

Methods available are

public static  void execute( short data) {System.out.println("short")}
public static  void execute( byte data) {System.out.println("byte")}

and you call

execute (10) // execute (int)

Example of ambiguous matches : 


Methods available are

public static  void execute( int data1, long data2) {System.out.println("int-long")}
public static  void execute( long data1, int data2) {System.out.println("long-int")}

and you call

execute (1,2) // execute (int,int)

Related Links


Sunday, 30 November 2014

Starting a new Process programmatically from Java

Background

In this post we will see how we can run any process from java programmatically. In specific I will show how can we compile a java file from a Java process. We can very well use Runtime.getRuntime().exec() method to start the process but in this post I am going to demonstrate using ProcessBuilder class.

Code

    public static void executeJavacCommand() throws IOException {

        List<String> paramsExecute = new ArrayList<String>();
        paramsExecute.add("C:\\Program Files\\Java\\jdk1.6.0_31\\bin\\javac.exe");
        paramsExecute.add("-cp");
        paramsExecute.add(".");
        paramsExecute.add("HelloWorld.java");
        ProcessBuilder pBuilder = new ProcessBuilder(paramsExecute);
        Process process = pBuilder.start();
        Reader reader = new InputStreamReader(process.getErrorStream());
        int ch;
        while((ch = reader.read())!= -1)
            System.out.print((char)ch);
        reader.close();

    }

Note1 : In above code I am only printing the error stream of the process but you can manipulate the output stream as well as provide input stream to the process.
Note 2:  You can also see my previous post on how to get the java executable paths. You can programmatically derive those and use it in above code.


Related Links

Finding Java home programatically from Java program

Background

There might be various scenarios in which you might need to get the path of java executable. For example to lets say start java program from withing Java code. In this post we will see how can we achieve that. I will demonstrate a method to find the JAVA_HOME that is usually the JDK directory. Once you have that it is easy to get executable. For eg javac will be in JAVA_HOME/bin/javac.exe

Code

public class JavaHomeTest{

    public static void main(String args[]) throws IOException {
        System.out.println(getJDKDir());
    }

    public static String getJDKDir() {
        File javaHome = new File( System.getProperty( "java.home" ) ).getParentFile();
        File jdkDirectory = null;
        if( javaHome.getName().contains( "jdk" ) ) { 
            //happens in IntelliJ
            jdkDirectory = javaHome;
        } else { 
            //General Scenario - eclipse / command line
            File[] childDirs = javaHome.listFiles();
            for(File file : childDirs) {
                if(file.getName().contains("jdk")) {
                    jdkDirectory = file;
                    break;
                }
            }
            
        }
        return jdkDirectory.getAbsolutePath();
    }

}


Output : 

I am running Windows. The output that I get is 'C:\Program Files (x86)\Java\jdk1.7.0_55'. Code is same for Linux as well. You will get your Java directory.

Saturday, 29 November 2014

How to delete a directory in Java

Background

Well lately I have written a lot of code for file manipulation, I/O etc. So let me take this post to show how can we create or delete directories. Well Java provides APIs for them so it should be pretty straightforward to understand. Important point to look forward is that if you are deleting a directory and it has more files in it then the directory will not get deleted unless all it's children are deleted recursively.  Note File as a Java object can represent either a file or a directory. You can use File 's class isDirectory() method Eg.

        File file = new File("C:\\Users\\athakur\\Downloads");
        if(file.isDirectory()) {
            System.out.println("File is a directory");
        }


Now lets get to creating and deleting directories/files.



Creating a File

To create a file we can use createNewFile() method. Eg - 

        File file = new File("C:\\Users\\athakur\\Downloads\\abc.txt");
        if(!file.exists()) {
            file.createNewFile();
        }

Creating a Directory

To create a directory first create a File object and then call mkdir() on it. Eg -

        File file = new File("C:\\Users\\athakur\\Downloads\\Movies");
        if(!file.exists()) {
            file.mkdir();
        }

Deleting a file/directory

To delete a file or a directory we have to use delete() method. As stated in introductory paragraph if directory has data that data needs to be deleted first. "rm -rf *" does not work in java :).

    public void deleteDirectory(String path) {
        
        File file  = new File(path);
        if(file.isDirectory()){
            String[] childFiles = file.list();
            if(childFiles == null) {
                //Directory is empty. Proceed for deletion
                file.delete();
            }
            else {
                //Directory has other files.
                //Need to delete them first
                for (String childFilePath :  childFiles) {
                    //recursive delete the files
                    deleteDirectory(childFilePath);
                }
            }
            
        }
        else {
            //it is a simple file. Proceed for deletion
            file.delete();
        }
        
    }


Above method will delete complete directory.
t> UA-39527780-1 back to top