Friday, 12 December 2014

Difference between Comparator and Comparable in Java

Background

How do we sort numbers in Java. Following is the simple program to do that - 

    public static void main(String args[]) {
        int[] myArray = new int[]{5,10,2,1,6};
        Arrays.sort(myArray);
        for(int no : myArray) {
            System.out.print(no + " ");
        }
    }

And we get the output as : 1 2 5 6 10 

Same goes for Collections as well.

But that is for simple numbers. How do we sort complex custom Objects. For example lets say you have Student Objects and you need to sort them on the basis of their age or some other scenario may require them to be sorted alphabetically by name. In this post we will see exactly how to do this.

Ordering Custom Objects


Lets create our Student class first.

Student.java


public class Student {
    
    private String name;
    private int age;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}



For simplicity I have just kept two parameters - name and age. Before we proceed to create group of students and order them we need to answer a question -

What is the natural ordering ? The answer will vary depending on the scenario for which you are writing your code. In this scenario we will take age as natural ordering criteria.

Why did we answer above question ? Because it is the basis of the title of this post - Difference between Comparator and Comparable in Java.

Difference between Comparator and Comparable in Java

Implementing Comparable means "I can compare myself with another object." This is typically useful when there's a single natural default comparison.

Implementing Comparator means "I can compare two other objects." This is typically useful when there are multiple ways of comparing two instances of a type - e.g. you could compare people by age, name etc.

In our case we decided age will be our natural ordering. So we will handle age comparison in Comparable interface where as handle name in Comparator.

Note : Both Comparator and Comparable are interfaces. You need to implement them. Your model class which needs to be naturally ordered implements Comparable interface where as you need to create a separate class that implements Comparator to handle non natural ordering. When you call methods like sort we need to supply instance of this class that implemented Comparator interface.

 Comparable interface is in package java.lang whereas Comparator interface is in java.util package. Also when you implement Comparable interface you override a.compareTo(b) method where as in case of Comparator you override compare(a, b). Don't worry about the technicality. We will see this with example.

Implementing Comparable interface - natural ordering

As I mentioned earlier with reference to our Student object I am going to use age as natural ordering criteria.

Lets rewrite our Student class which will now implement Comparable interface.


public class Student implements Comparable<Student> {
    
    private String name;
    private int age;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    
    @Override
    public int compareTo(Student o) {
        return (this.age > o.age ? 1 : (this.age < o.age ? -1 : 0));
    }
}


Notice the logic in compareTo() method. We return 1 if current object is higher in order, -1 if lower and 0 if same. Lets test this now - 

public class OrderingTester {

    

    public static void main(String args[]) {

        Student[] allStudents = new Student[] { new Student("John", 21),

                new Student("Rita", 19), new Student("Sam", 26),

                new Student("Claire", 16) };


        System.out.println("Before natural sorting");

        for(Student student : allStudents) {

            System.out.println(student);

        }

        Arrays.sort(allStudents);

        System.out.println("After natural Sorting");

        for(Student student : allStudents) {

            System.out.println(student);

        }

    }

}

And the output is - 

Before natural sorting
Student [name=John, age=21]
Student [name=Rita, age=19]
Student [name=Sam, age=26]
Student [name=Claire, age=16]
After natural Sorting
Student [name=Claire, age=16]
Student [name=Rita, age=19]
Student [name=John, age=21]
Student [name=Sam, age=26]


That's how natural ordering/comparable interface work. Now lets move on to comparator interface.

Implementing Comparator interface - Custom ordering

Lets start by writing our comparator class - 

public class StudentNameComparator implements Comparator<Student> {

    @Override
    public int compare(Student student1, Student student2) {
        return student1.getName().compareTo(student2.getName());
    }

}

and now lets test this - 

public class OrderingTester {
    
    public static void main(String args[]) {
        Student[] allStudents = new Student[] { new Student("John", 21),
                new Student("Rita", 19), new Student("Sam", 26),
                new Student("Claire", 16) };
        
        System.out.println("Before custom sorting");
        for(Student student : allStudents) {
            System.out.println(student);
        }
        Arrays.sort(allStudents, new StudentNameComparator());
        System.out.println("After custom Sorting");
        for(Student student : allStudents) {
            System.out.println(student);
        }
    }

}

And the output is - 

Before custom sorting
Student [name=John, age=21]
Student [name=Rita, age=19]
Student [name=Sam, age=26]
Student [name=Claire, age=16]
After custom Sorting
Student [name=Claire, age=16]
Student [name=John, age=21]
Student [name=Rita, age=19]
Student [name=Sam, age=26]


Logic in compare() method that we override on implementing Comparator interface is same as compareTo() method that we override on implementing Comparable interface.

Notice how we just gave the array to sort in Arrays.sort() in natural sorting where as we gave the comparator with custom ordering logic as a separate argument to sort method.



Hope this clarifies the difference. Let me know if you still have any doubts or questions.

Java 8 changes in Comparator and Comparable interface

 With introduction of function interface and Lambda expressions in Java 8 there are changes made in comparable and comparator  interfaces as well. 
  • Both comparable and comparator interfaces are functional interfaces.
Just to remind you interfaces can now also have static methods and they do not affect the functional status of an interface.

Now let's visit our old problem of sorting student. As per what we discussed we said let age be used to do natural sorting (used comparable interface for that) and for sorting with name (custom sorting) we use comparator interface. But what if we 1st want to compare using name and if that matches then compare using age. Lets see how that would workout

public class StudentNameComparator implements Comparator<Student> {

    @Override
    public int compare(Student student1, Student student2) {
        int result =  student1.getName().compareTo(student2.getName());
        if (result != 0) return result;
        return student1.getAge() - student2.getAge();
    }

}


Sure that works out but there is a smarter way. One that Java 8 provides. Well see that now.

public class StudentNameComparator implements Comparator<Student> {

    @Override
    public int compare(Student student1, Student student2) {
        Comparator<Student> c = Comparator.comparing(s -> s.getName());
        c = c.thenComparingInt(s -> s.getAge());
        return c.compare(s1, s2);
    }

}


NOTE : comparing static method - Accepts a function that extracts a Comparable sort key from a type T, and returns a Comparator<T> that compares by that sort key.


Related Links


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.

t> UA-39527780-1 back to top