Pages

Tuesday, July 3, 2018

How to use filter() method in Java 8

Java 8 Stream interface introduces filter() method which can be used to filter out some elements from object collection based on a particular condition. This condition should be specified as a predicate which the filter() method accepts as an argument.

The java.util.function.Predicate interface defines an abstract method named test() that accepts an object of generic type T and returns a boolean.

Let's do some coding to understand the filter method more clearly. Look at the following Dish class.

public class Dish {

     private String name;
     private Boolean vegitarian;
     private Integer calaries;
     private Type type;
 
     public Dish(String name, Boolean vegitarian, Integer calaries, Type type) {
          super();
          this.name = name;
          this.vegitarian = vegitarian;
          this.calaries = calaries;
          this.type = type;
     }

     public Boolean getVegitarian() {
         return vegitarian;
     }

     public void setVegitarian(Boolean vegitarian) {
         this.vegitarian = vegitarian;
     }

     public Type getType() {
         return type;
     }

     public void setType(Type type) {
         this.type = type;
     }

     public enum Type { MEAT, FISH, OTHER };
}


Let's think, we want to filter out only the vegetarian Dishes from a list of all Dishes. Following is the approach  before Java 8.

    List<Dish> vegetarianDishes = new ArrayList<Dish>(); 
    for(Dish d: menu) {
       if(d.getVegetarian()) { 
          vegetarianDishes.add(d);
       } 
    }

The above approach is called external iteration which we explicitly manage the iteration over the collection of data.

How this can be done with Java 8 ? It is just a matter of single line as follows.

List<Dish> menu = ....
List<Dish> vegitarianDishes = menu.stream()
                                    .filter(d -> d.getVegitarian())
                                    .collect(Collectors.toList());

We have passed a Predicate instance into the filter() method in a form of a Lambda expression.

Also, we can use java 8 method references to pass a Predicate instance to the filter() method as follows.
List<Dish> menu = ....
List<Dish> vegitarianDishes = menu.stream()
                                    .filter(Dish::getVegitarian)
                                    .collect(Collectors.toList());

Dish::getVegitarian is the syntax for Java 8 method references. It refers to the getVegitarian() method of Dish class. 

The filter() method returns a Stream of Dishes and the collect() method converts the Stream into a List. The 'collect' operation is called a terminal operation.

Now let's say, we want to get first three Dishes that have more than 300 calories. Streams support the limit(n) method, which returns another stream that’s no longer than a given size. The requested size is passed as argument to limit.

List<Dish> menu = ....
List<Dish> threeHighCalaricDish = menu.stream()
                                         .filter(d -> d.getCalaries() > 300)
                                         .limit(3)
                                         .collect(Collectors.toList());

Similarly, if we want to skip first 3 elements, streams support the skip(n) method to return a stream that discards the first n elements. If the stream has fewer elements than n, then an empty stream is returned. Note that limit(n) and skip(n) are complementary!

Now, an exercise for you ! How would you use streams to filter the first two meat dishes?
List<Dish> menu = ....
List<Dish> meatDishes = menu.stream()
                                  .filter(d -> d.getType() == Dish.Type.MEAT)
                                  .limit(2)
                                  .collect(Collectors.toList())

Saturday, June 9, 2018

Java 8 sorting examples

How many lines of code did you write to sort a collection of objects before Java 8 ? How many, you will need with Java 8 ?
You can do it with a single line in Java 8.

Let's see the following Employee class.

public class Employee {
 
     private String name;
 
     private Integer age;
 
     public Employee(String name, Integer age) {
         super();
         this.name = name;
         this.age = age;
     }

     public String getName() {
         return name;
     }

     public void setName(String name) {
         this.name = name;
     }

     public Integer getAge() {
         return age;
     }

     public void setAge(Integer age) {
        this.age = age;
     }

}

Using the Collection's sort() method, employee list can be sorted. The sort() method expects a Comparator as an argument in order to compare two Employee objects. So our first solution looks like as follows.


public class EmployeeComparotor implements Comparator {
    @Override
    public int compare(Employee e1, Employee e2) {
        return e1.getAge().compareTo(e2.getAge()); 
    }
}

employeeList.sort(new EmployeeComparotor());

Rather than implementing Comparator and instantiating a new instance of it, we can use an anonymous class to improve our program.

employeeList.sort(new Comparator() {
    @Override
    public int compare(Employee e1, Employee e2) {
        return e1.getAge().compareTo(e2.getAge()); 
    }
}); 

Now, let's see, how can we improve this code further in order to reduce the verbosity by using Java 8 features. Java 8 introduces lambda expressions which allows us to pass a code to a method. Lambda expression can be passed to a method where functional interface is expected. A functional interface is an interface defining only one abstract method. In Java 8, the Comparator is a functional interface. The Collection's sort() method expects a Comparator as an argument, which accepts a functional interface. In this case, the Comparator represents BiFunction's descriptor. The BiFunction is a functional interface in Java 8. So then, you can pass a lambda expression into the sort method as follows. In order to sort employee list by their age, you need a single line as follows.

employeeList.sort((Employee e1, Employee e2) -> e1.getAge().compareTo(e2.getAge()));

Java compiler can infer the types of parameters of a lambda expression by using the context in which the lambda appears. So you can remove the types of parameter and rewrite the code as follows.

employeeList.sort((e1, e2) -> e1.getAge().compareTo(e2.getAge()));

Let's try to further reduce the code. Java 8 Comparator has a static method called comparing() that accepts a Function as an argument. This Function should extract the sort key and produce a Comparator object. So the shortest code to sort a list of objects in Java 8 will be,

employeeList.sort(comparing((e) -> e1.getAge()));

In stead of using a lambda expression, we can use method references to make our code slightly less verbose.

employeeList.sort(comparing(Employee::getAge));

If you want to sort the employee list by descending order in age, you can use the reversed() default method of the interface.

employeeList.sort(comparing(Employee::getAge).reversed());

Now, let's see, you want to sort the employees in their age and then, similar age employees by their names. Just remind, how did you do this earlier version of Java. In Java 8, you can simply use thenComparing() method in order to do this.

employeeList.sort(comparing(Employee::getAge).thenComparing(Employee::getName));



Thursday, June 6, 2013

Online server console viewer with Ajax long polling.

This post will give you small web application which brings the real time server console to the browser.  I am going to explain you, how to run this web application as it is and also if you want to add more customization, how to build the project using the source.

The Comet concept

This application a demonstrative usage of the Comet concept introduced by  Alex Russell in 2006. Once you get the idea, you can develop innovative applications and make use of it with your web application. For example, Facebook, it shows new friend requests, inbox updates and notifications on time. That is one of the real time usage of Comet approach.

The Comet is a web application model which always keeps live  connection with the server and let the server push the data to the browser through that connection. The browser does not explicitly request specific data. It just keeps live connection with the server. What ever the data pushed (or published) by the server are carried to the browser through that open connection. Also this concept is know as Ajax-Push, Reverse-Ajax, Two-way-web, HTTP Streaming, HTTP-server push.

There are several  ways of implementing Comet model. The CometD is a java framework  developed by Dojo Foundation which implements the Comet concept with 'XMLHttpRequest long polling'. This works with all modern browsers which supports XHR. With XHR long polling, the browser makes an asynchronous request to the server and if there are data available at the server, the response will bring that data to the browser as XML or JSON. After processing the response at client side, browser makes another XHR to poll more available data from the server.

If you have frequent data changes on the server and want to update browsers, the comet approach will be a best fit, because this can be pretty network intensive, and you often make pointless requests, though nothing has happened on the server. For example, frequent stock market information can be published to many users as soon as latest information is available. 

How the application works?

This application keeps reading the specified server log file line by line and push collected chunk of lines to the browser as a one string. By default, the application reads the Tomcat's catalina.out file. Server runs a timer which is set to every one second and executes these log file reading function. It collects  all the lines read within a one second and push to the client. In the client side, application keeps appending new contents to HTML DIV element. The server function will always reads only the newly appending lines of the the log file.

How to run the application?

If you are using Tomcat, you can experiment this application without much worrying. You just need to download the 'console-viewer.war' file and deploy it in your Tomcat container. If you are testing this with your local configuration, point your browser to following URL.

http://localhost:8080/console-viewer

Click on 'Connect' button and keep looking while you are accessing some deployed application. You will see the Tomcat's console on your web browser. Keep in mind, by default, this application reads 'catalina.out' file. So you need to start the Tomcat with ./startup.sh command. If you are appending your application's logs into different log file or using different server, I will explain, how to customize the application for that later. 

How to build the project with source?

I have provided complete source to you so that you can download the source code and go one step further or to read different log file or run with different server other then Tomcat. You can build the project using maven. If you are not using maven, you can create your own simple web application and copy the required contents. If you want to get the set of .jar files, you can get it from console-viewer.war file.

Here are the steps to build the project using maven.

Download the source and extract it to some where in your local disk. 

1. Navigate to the location.

    cd /home/semika/console-viewer

2. Build the project with the following command.

    mvn clean install

You can see, it builds the project and copies the 'console-viewer.war' file into CATALINA_HOME/webapps folder.  

3. Start the Tomcat with the following command.

   ./startup.sh

If you want to read some other log file rather than default 'catalina.out' file, or you want to run this application to view different server's console, you have to provide required log file's absolute path as an initialization parameter of 'Initializer' servlet as follows and deploy the application on the server.

<servlet>
    <servlet-name>initializer</servlet-name>
    <servlet-class>com.semika.cometd.Initializer</servlet-class>
    <init-param>
         <param-name>logFilePath</param-name>
         <param-value>
             /home/semika/apache-tomcat-7.0.37/logs/catalina.out
         </param-value>
     </init-param>
     <load-on-startup>2</load-on-startup>
</servlet>

Download the application and source

Download console-viewer.war file.
Download source code. If you encounter some issues with this, please send me a mail. I am always ready to give help.

Friday, March 29, 2013

Don't use 'Query.list()' when you really need 'Query.uniqueResult()' in Hibernate.

I was motivated to discuss a little about this topic, since I am seeing a usage of hibernate which is capable of making server issues in your application. What I am going to discuss here, is very simple, but some developers are tend to do it in wrong way. Sometime, they are doing this intentionally for safe side.

When we are using hibernate Query to fetch a single instance, Query.uniqueResult() is being used except special scenarios. To use Query.uniqueResult(), we must make sure that query will return a single object. But some programmers are still used to do it with Query.list() method which can pull your application out into very inconsistency situation and issues which are very hard to discover the reason for failure. 

Just have a look into the following example.

public Account getAccountByAccountIdAndType(Long accountId, AccountType accountType) throws FetchAccountException {
 
    Account account = null;
    Query query = getSession().getNamedQuery("getAccountByAccountId");
    query.setLong("accountId", accountId); 
    query.setString("accountType", AccountType.SAVING.toString());
    List<Account> list = query.list();
    if (null != list && list.size() > 0) {
         account = list.get(0);
    }
    return account;
}

The above function is responsible to get Account instance for a given account number and type. Let's assume there can not be two accounts with the same type having same account number. 

If you carefully see the above code, the developer has applied many safe factors to minimize the exceptions. Some are even ambiguous. The above method will be functioning well until there is one Account with same type and account number and you expects that too. And also, it will execute well when there are more than one Account with same type and account number, which results wrong output and we don't actually need. 

What will happen, if there are more than one accounts with same type and same account number?

That will be a total failure of your application and you will have to compensate if banking system will be on this kind of state. Let's see how the above method will behave in this kind of situation. The above method will hide this critical exception and keeps application flow functioning. The function will get a list which is having the accounts and will return the first Account instance. Ultimately, this will result wrong outputs in your application. 

The programmer has added a safe factor to keep application flow functioning even with more than one accounts with same type and number. This is unnecessary and a kind of cheat programming. The programmer can survive for some time, the company who is working for, will have to compensate for loses. This is very poor programming. Some programmers do this intentionally as a safe factor, some are doing this as a quick fix for a defect. But this is very very dangerous.

Further the programmer has checked the "list" for NULL which is ambiguous, because hibernate does not return NULL list, instead it always returns empty list.

And other shortage of above method is, it may return NULL as the output which is not a good programming practice. Instead, you can throw an exception.

The getAccountByAccountIdAndType() method must return an exception in state. If the programmer used Query.uniqueResult() for this purpose, it returns the following exception keeping every one enlighten. We can take immediate action to get rid of this killer situation.

org.hibernate.NonUniqueResultException: query did not return a unique result: 2

We can improve the above function as follows.

public Account getAccountByAccountIdAndType(Long accountId, AccountType accountType) {
 
    Query query = getSession().getNamedQuery("getAccountByAccountId");
    query.setLong("accountId", accountId); 
    query.setString("accountType", AccountType.SAVING.toString());
    Account account = (Account)Query.uniqueResult();
    
    if (account == null) {
         throw new RuntimeException("Unable to find Account for account number :" + accountId);
    }
    return account;
}

Now the above method will return the exception when there are more than one account with same type and number.

If you want to send more specific error message rather than a hibernate exception message when you are having more than one account with same account number and type, you can put a try-catch block as follows.

public Account getAccountByAccountIdAndType(Long accountId, AccountType accountType) {
     
    Account account = null;
    try {
        Query query = getSession().getNamedQuery("getAccountByAccountId");
        query.setLong("accountId", accountId); 
        query.setString("accountType", AccountType.SAVING.toString());
        Account account = (Account)Query.uniqueResult();
    } catch(NonUniqueResultException) {
        throw new RuntimeException("Two account found with same account number and type : Acc No-" + accountId);
    }
    if (account == null) {
         throw new RuntimeException("Unable to find Account for account number :" + accountId);
    }
    return account;
}

As a conclusion, always use Query.uniqueResult() when you want to fetch a single object with hibernate Query and you should make sure your query will return a single object too.

Wednesday, March 20, 2013

How to set browser time to DateTimeItem in smart GWT?

The "DateTimeItem" item in Smart GWT allows you to specify the date and the time together as a single field and ultimately it can be mapped to java.util.Date field in your model (or a field in your controller class).

DateTimeItem startDateTime = new DateTimeItem("startDateTime","Start Datetime");

After picking a date from the calendar, the 'DateTimeItem' shows the value in the following format by default.

MM/dd/yyyy HH:mm

It sets the time part to 00:00. I wanted to have time part to set the browser's time.

After searching on the internet and doing some experiments, I ended up with the following solution.

I am creating a custom class by extending "DateTimeItem" class of smart GWT and overrides the 'transformInput' method.

package mypackage;

import java.util.Date;

import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.TimeZone;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemInputTransformer;
import com.smartgwt.client.widgets.form.fields.DateTimeItem;
import com.smartgwt.client.widgets.form.fields.FormItem;

public class MyDateTimeItem extends DateTimeItem {
 
     public MyDateTimeItem(String name, String title) {
        super(name, title);
        this.setUseTextField(true);
        this.setWidth(125);
        this.setInputTransformer(new FormItemInputTransformer() {
            @Override
            public Object transformInput(DynamicForm form, FormItem item, Object value, Object oldValue) {
               DateTimeFormat dtFormet    = DateTimeFormat.getFormat("MM/dd/yyyy HH:mm"); 
               String strCurrentDateTime  = dtFormet.format(new Date());
               String strSelectedDateTime = dtFormet.format((Date)value, TimeZone.createTimeZone(0));
    
               if (oldValue != null) { // Changing date.

                   if (strSelectedDateTime.split(" ")[1].equals("00:00")) { 
                        //Selecting new date time from the picker while keeping old value in the input field.
                        return strSelectedDateTime.split(" ")[0] + " " + strCurrentDateTime.split(" ")[1];
                   } 
                   return strSelectedDateTime;
               } 
     
               return strSelectedDateTime.split(" ")[0] + " " + strCurrentDateTime.split(" ")[1];   
           }
      });
   }
}
You can use the new component in the similar way in which the 'DateTimeItem' was used.

MyDateTimeItem startDateTime = new MyDateTimeItem("startDateTime","Start Datetime");
Share

Widgets