Sunday 10 February 2019

Functional Programming using Java 8

Functional Programming using Java 8


Java 8 brings the power of functional programming. Let's dig into the java code library and understand it better.

Let's create a small application called Adder which can take a few types of java wrappers and add those and return a result.

1. Create a Java interface called Adder as below. Here I, J are the type of input arguments and R is the type of return 


public interface Adder<I, J, R> {
    public R add(I arg1, J arg2); 
}

2. Create another java class called TraditionalDifferentAdders and a few implementations of Adder interface. This is a java traditional implementation of an interface and uses it in code.


import java.math.BigDecimal;

public class TraditionalDifferentAdders {
 
 public static void main(String[] args) {
  Adder<Integer, Integer, Integer> integerAdder = 
                     new TraditionalDifferentAdders().new IntergerAdder();
  System.out.println(integerAdder.add(10, 20));
  
  Adder<Double, Double, Double> doubleAdder = 
                     new TraditionalDifferentAdders().new DoubleAdder();
  System.out.println(doubleAdder.add(10.0, 20.0));
  
  Adder<BigDecimal, BigDecimal, BigDecimal> bigDecimalAdder = 
                     new TraditionalDifferentAdders().new BigDecimalAdder();
  System.out.println(bigDecimalAdder.add(new BigDecimal(10 ), new BigDecimal(20)));
  
  Adder<String, String, String> stringAdder = 
                    new TraditionalDifferentAdders().new StringAdder();
  System.out.println(stringAdder.add("10", "20"));
  
 }
 
 class IntergerAdder implements Adder<Integer, Integer, Integer>{

  @Override
  public Integer add(Integer arg1, Integer arg2) {
   return arg1 + arg2;
  }
  
 }
 
 class DoubleAdder implements Adder<Double, Double, Double>{

  @Override
  public Double add(Double arg1, Double arg2) {
   return arg1 + arg2;
  }
  
 }
 
 class BigDecimalAdder implements Adder<BigDecimal, BigDecimal, BigDecimal>{

  @Override
  public BigDecimal add(BigDecimal arg1, BigDecimal arg2) {
   return arg1.add(arg2);
  }
  
 }
 
 class StringAdder implements Adder<String, String, String>{

  @Override
  public String add(String arg1, String arg2) {
   return arg1.concat(arg2);
  }
  
 }
 
}


3. Let us simplify it by using anonymous inner classes. This will improve the code readability and reduce a few lines of codes.



import java.math.BigDecimal;

public class AnonymousAdders {
 
 public static void main(String[] args) {
 
  Adder<Integer, Integer, Integer> integerAdder = 
    new Adder<Integer, Integer, Integer>() {
   @Override
   public Integer add(Integer arg1, Integer arg2) {
    return arg1 + arg2;
   }
  };
  
  System.out.println(integerAdder.add(10, 20));
  
  Adder<Double, Double, Double> doubleAdder = 
    new Adder<Double, Double, Double>(){
   
   @Override
   public Double add(Double arg1, Double arg2) {
    return arg1 + arg2;
   }
  };
  
  System.out.println(doubleAdder.add(10.0, 20.0));
  
  Adder<BigDecimal, BigDecimal, BigDecimal> bigDecimalAdder = 
    new Adder<BigDecimal, BigDecimal, BigDecimal>() {
   
   @Override
   public BigDecimal add(BigDecimal arg1, BigDecimal arg2) {
    return arg1.add(arg2);
   }
   
  };
  System.out.println(bigDecimalAdder.add(new BigDecimal(10 ), new BigDecimal(20)));
  
  Adder<String, String, String> stringAdder = new Adder<String, String, String>() {
   @Override
   public String add(String arg1, String arg2) {
    return arg1.concat("+").concat(arg2);
   }
  };
  
  System.out.println(stringAdder.add("10", "20"));
    
 }

}


4. Let us further simplify this by using a Lambda adder



import java.math.BigDecimal;

public class LamdaAdder {
 
 public static void main(String[] args) {
  
  /*
    Way to reduce the unwanted codes from Lamda functions
    
   Adder<Integer, Integer, Integer> integerAdder = 
    (Integer arg1, Integer arg2) -> { return arg1 + arg2;};
  
  Adder<Integer, Integer, Integer> integerAdder = 
    (Integer arg1, Integer arg2) -> arg1 + arg2;
    
   */
  
  Adder<Integer, Integer, Integer> integerAdder = 
    (arg1, arg2) -> arg1 + arg2;
  
  System.out.println(integerAdder.add(10, 20));
  
  Adder<Double, Double, Double> doubleAdder = 
    (arg1, arg2) -> arg1 + arg2;
  System.out.println(doubleAdder.add(10.0, 20.0));
  
  Adder<BigDecimal, BigDecimal, BigDecimal> bigDecimalAdder = 
    (arg1, arg2) -> arg1.add(arg2);
  System.out.println(bigDecimalAdder.add(new BigDecimal(10 ), new BigDecimal(20)));
  
  Adder<String, String, String> stringAdder = (arg1, arg2) -> arg1 + arg2;
  System.out.println(stringAdder.add("10", "20"));
  
 }

}

5. Let us further tweak it by removing the Adder interface



import java.math.BigDecimal;
import java.util.function.BiFunction;

public class FunctionalInterfaceAdder {
 
 
 public static void main(String[] args) {
  
  BiFunction<Integer, Integer, Integer> integerAdder = 
    (arg1, arg2) -> arg1 + arg2;
  System.out.println(integerAdder.apply(10, 20));
  
  BiFunction<Double, Double, Double> doubleAdder = 
    (arg1, arg2) -> arg1 + arg2;
  System.out.println(doubleAdder.apply(10.0, 20.0));
  
  BiFunction<BigDecimal, BigDecimal, BigDecimal> bigDecimalAdder = 
    (arg1, arg2) -> arg1.add(arg2);
  System.out.println(bigDecimalAdder.apply(new BigDecimal(10 ), new BigDecimal(20)));
  
  BiFunction<String, String, String> stringAdder = 
    (arg1, arg2) -> arg1 + arg2;
  System.out.println(stringAdder.apply("10", "20"));
  
 }

}


By looking at the above code, it is very clear that if we use functional interfaces, our code looks neat and clean. There are several other advantages like we can pass the functional interfaces as an argument to functions. Also, we can return the same.


Deep dive into Java Date and Time APIs

Date and Time is one of the most important API in any programming language. In this blog, I will try to explain some basic concepts of Date and Time in java


Before we start, I will write a few concepts

UTC and GMT

UTC: Coordinated Universal Time is a standard by which the world regulates clocks and time.  https://en.wikipedia.org/wiki/Coordinated_Universal_Time

GMT : https://en.wikipedia.org/wiki/Greenwich_Mean_Time

Refer below videos
https://www.youtube.com/watch?v=X1DkiuaFCuA&t=79s
https://www.youtube.com/watch?v=DFDsN-NaMuM
https://www.youtube.com/watch?v=eHMqSwdF4RU
https://www.youtube.com/watch?v=84aWtseb2-4

Unix Time or UNIX Epoch time

It is is a system for describing a point in time.  It is the number of seconds that have elapsed since 00:00:00 Thursday, 1 January 1970,[Coordinated Universal Time (UTC), minus leap seconds.


Refer:
https://en.wikipedia.org/wiki/Unix_time
https://www.youtube.com/watch?v=RuPQsqZaq8A
https://www.youtube.com/watch?v=O_KidUQpeKo


java.util.Date


Java is also working based on the Epoch time and it is 01/Jan/1970 00:00:00 GMT

The Java epoch time can be obtained by using the below code, Note I am using GMT timezone. If you remove it, it will show the date in default timezone of your machine.


import java.util.Date;
import java.util.TimeZone;

public class JavaTime {

 public static void main(String[] args) {
  
  TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
  Date epochDate = new Date(0L);
  System.out.println(epochDate);
  
 }
}

Output: Thu Jan 01 00:00:00 GMT 1970 

What does it mean? It means that the epochDate in java is Thu Jan 01 00:00:00 GMT 1970 the value of 0L is giving the epochDate

Let's increase the value from 0L - 1L - 100L - 999L - 1000L

I am using a SimpleDateFormat class for showing the dates in a yyyy-MM-dd HH:mm:ss.SSS format. Just note the seconds' format ss.SSS, it will show the seconds in SSS a.k.a milliseconds.


import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class JavaTime {

 public static void main(String[] args) {
  
  TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
  SimpleDateFormat  formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
  System.out.println("0L -> "+formater.format(new Date(0L)));
  System.out.println("1L -> "+formater.format(new Date(1L)));
  System.out.println("100L -> "+formater.format(new Date(100L)));
  System.out.println("999L -> "+formater.format(new Date(999L)));
  System.out.println("1000L -> "+formater.format(new Date(1000L)));
 }
}

Output: 
0L -> 1970-01-01 00:00:00.000 GMT
1L -> 1970-01-01 00:00:00.001 GMT
100L -> 1970-01-01 00:00:00.100 GMT
999L -> 1970-01-01 00:00:00.999 GMT
1000L -> 1970-01-01 00:00:01.000 GMT 


It is very clear from the above code that Java can measure seconds in the Milli range. When seconds reached 999 milli, we are able to see that the second is still showing as 1970-01-01 00:00:00.999 GMT, but when it reached 1000, the second is changed to one as 1970-01-01 00:00:01.000 GMT This proves that one second in java is equal to 1000L.

This is giving some important concept to us.

1. If we want to represent different time slices

  • Epoch Date (1970-01-01 00:00:00.000 GMT) = 0L
  • 1 second = 1000L
  • 1 minute = 60*1000L = 60000L
  • 1 hour = 1000L*60*60 = 3600000L
  • 1 Day = 1000L*60*60*24
  • 1 Year = 1000L*60*60*24*365
2. If we want to represent any date, just calculate the number of seconds in that date from Epoch Date.

E.g. I want to represent 10 days after Epoch date i.e. 1970-01-11 00:00:00.000 GMT
        10* 1000L*60*60*24 = 864000000 , try below code


import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class JavaTime {

 public static void main(String[] args) {
  
  TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
  SimpleDateFormat  formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
  System.out.println("864000000L -> "+formater.format(new Date(864000000L)));
 }
}

Output: 
864000000L -> 1970-01-11 00:00:00.000 GMT

3. We can represent any date by finding the long value of the date from Epoch date. E.g. the java function System.currentTimeMillis() is returning a long value which is equal to the long value of the current date from Epoch date.

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class JavaTime {

 static long ONE_DAY=1000L*60*60*24;
 static long ONE_YEAR=1000L*60*60*24*365;
  
  public static void main(String[] args) {
  
 TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
 SimpleDateFormat  formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
 long timeInMillisFromEpochDate = System.currentTimeMillis();
 System.out.println("timeInMillisFromEpochDate :"+timeInMillisFromEpochDate);
 System.out.println("Today -> "+formater.format(new Date(timeInMillisFromEpochDate)));
 System.out.println("Day from Epoch -> "+timeInMillisFromEpochDate/ONE_DAY);
 System.out.println("Year from Epoch -> "+timeInMillisFromEpochDate/ONE_YEAR);
  
   }
}

Output: 
timeInMillisFromEpochDate :1549791631262
Today -> 2019-02-10 09:40:31.262 GMT
Day from Epoch -> 17937
Year from Epoch -> 49

Hope the above helped you to understand what is java.util.Date underlying concepts.


Now it's the time to explore the java.util.Date API

  • Date date = new Date(); is returning the current date instance. Internally it is calling below method, a code snippet from java.util.Date class
 public Date() {
        this(System.currentTimeMillis());
    }
  • Date.getTime() returns a long value which is the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this date.
  • Date.getXXX() methods return various time slices of the date like seconds, day, month, year etc.
  • Date.setXXX methods set various time slices of the date like seconds, day, month, year etc.
  • Date.toString() returns the date in EEE MMM dd HH:mm:ss zzz yyyy format, so your machine's default timezone is taken into consideration.

Some pain points with java.util.Date package

Imagine I want to get Tomorrow from Today, I have to use something like below 

import java.util.Date;

public class JavaTime {
 
 public static void main(String[] args) { 
  
  Date date = new Date();
  long nextDayLongValue = date.getTime()+1000*60*60*24L;
  System.out.println("Today is    : "+date );
  System.out.println("Tomorrow is : "+ new Date(nextDayLongValue) ); 
 }
}

Output:

Today is    : Sun Feb 10 15:44:05 IST 2019
Tomorrow is : Mon Feb 11 15:44:05 IST 2019


So it is a painful class for developers. The below makes Date class less effective
  • The numeric representations of calendar data are counter-intuitive in many cases. For example: getMonth() is zero-based, getYear() is 1900-based (i.e., the year 2009 is represented as 109)
    • An example if, you want to represent March 18, 2014, we have to create instance of Date as follows.
      • Date date = new Date(114, 2, 18);
      • Here in the year field we have to pass year as 114 (2014-1900) and 2 as 3rd month which are quite confusing
  • Dates are mutable, as a result, you need to clone the date object if you want to pass it to some other methods.
  • The Calendar, designed to 'fix' this, actually makes the same mistakes. They're still mutable.
  • They have a double nature. They represent both a timestamp and a calendar date. It turns out this is problematic when doing calculations on dates.
  • Date represents a DateTime, but in order to defer to those in SQL land, there's another subclass java.sql.Date, which represents a single day (though without a timezone associated with it).
  • There are no TimeZones associated with a Date, and so ranges (such as a 'whole day') are often represented as a midnight-midnight (often in some arbitrary timezone)
  • The API for these functions were not easy for internationalization.
  • The arguments given to the Date API methods don’t fall within any specific ranges; for example, a date may be specified as January 32 and is interpreted as meaning February 1. There is no explicit control over it.

java.sql.Date

  • RDBMS has a data type called Date which saves only date and no time information
  • The java.sql.Date has the below signature. So sql date is extending java.util.Date class
    • public class Date extends java.util.Date
  • A thin wrapper around a millisecond value that allows JDBC to identify this as an SQL DATE value. A milliseconds value represents the number of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.
  • To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
  • java.sql.Date doesn’t hold timezone information, the timezone conversion between our local environment and database server depends on an implementation of JDBC driver. This adds another level of complexity.
  • In order to support other SQL data types: SQL TIME and SQL TIMESTAMP, two other java.sql classes are available: Time and Timestamp.
  • java.sql.Time
    • A thin wrapper around the java.util.Date class that allows the JDBC API to identify this as an SQL TIME value. The Time class adds formatting and parsing operations to support the JDBC escape syntax for time values.
    • The date components should be set to the "zero epoch" value of January 1, 1970 and should not be accessed.
  • java.util.TimeStamp
    • A thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL TIMESTAMP value. It adds the ability to hold the SQL TIMESTAMP fractional seconds value, by allowing the specification of fractional seconds to a precision of nanoseconds. A Timestamp also provides formatting and parsing operations to support the JDBC escape syntax for timestamp values.
    • Note: This type is a composite of a java.util.Date and a separate nanoseconds value. Only integral seconds are stored in the java.util.Date component. The fractional seconds - the nanos - are separate. The Timestamp.equals(Object) method never returns true when passed an object that isn't an instance of java.sql.Timestamp, because the nanos component of a date is unknown. As a result, the Timestamp.equals(Object) method is not symmetric with respect to the java.util.Date.equals(Object) method. Also, the hashcode method uses the underlying java.util.Date implementation and therefore does not include nanos in its computation.
    • Due to the differences between the Timestamp class and the java.util.Date class mentioned above, it is recommended that code not view Timestamp values generically as an instance of java.util.Date. The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance.
import java.sql.Date;

public class JavaTime {
 
 public static void main(String[] args) { 
  
  Date sqlDate = new Date(0L);
  System.out.println(sqlDate);

 }
}


Output:

1970-01-01

  • To convert between two dates
import java.sql.Date;

public class JavaTime {
 
 public static void main(String[] args) { 
  
  Date sqlDate = new Date(0L);
  System.out.println("SQL Date    : "+sqlDate);
  
  java.util.Date utilDate  = new java.util.Date(sqlDate.getTime());
  System.out.println("Util Date    : "+utilDate);
  
  Date sqlDateFromUtilDate = new Date(utilDate.getTime());
  System.out.println("SQL Date from Util Date  : "+sqlDateFromUtilDate);
 }
}


Output:
SQL Date    : 1970-01-01
Util Date from SQL Date  : Thu Jan 01 05:30:00 IST 1970
SQL Date from Util Date  : 1970-01-01


java.util.Calendar
  • By default, java supports three Calendar implementation
    • BuddhistCalendar
    • JapaneseImperialCalendar
    • GregorianCalendar
      • https://en.wikipedia.org/wiki/Gregorian_calendar
  • Calendar.getInstance() is returning any of the above calendar instance based on the default Locale
import java.util.Calendar;

public class JavaTime {
 
 public static void main(String[] args) { 
  
  Calendar calendar = Calendar.getInstance();
  System.out.println(calendar.getAvailableCalendarTypes());
  System.out.println(calendar.getClass());
  System.out.println(calendar.getTime());
  System.out.println(calendar.getTimeInMillis());
  System.out.println(calendar.getCalendarType());
  System.out.println(calendar.getFirstDayOfWeek());
  System.out.println(calendar.getAvailableCalendarTypes());
 }
}

Output:
[gregory, buddhist, japanese]
class java.util.GregorianCalendar
Sun Feb 10 16:58:48 IST 2019
1549798128200
gregory
1
[gregory, buddhist, japanese]

  • Constants were added in Calendar class but still, Month is zero index based.
  • Calendar class is mutable so thread safety is always a question for it.
  • It is very complicated to do date calculations. In fact, there is no simple, efficient way to calculate the days between two dates.
  • java.text.DateFormat were introduced for the purpose of parsing of date strings but it isn’t thread-safe. Following example shows the serious problem can occur when DateFormat is used in multithreaded scenarios
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class JavaTime {
 
 public static void main(String[] args) { 
  
  SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
  ExecutorService es = Executors.newFixedThreadPool(5);
  for (int i = 0; i < 10; i++) {
      es.submit(() -> {
          try {
             System.out.println(sdf.parse("15081947"));
          } catch (ParseException e) {
             e.printStackTrace();
          }
      });
  }
  es.shutdown();
 }
}


Output:
Fri Nov 28 00:00:00 IST 1952
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947
Fri Aug 15 00:00:00 IST 1947


java.time package
  • Support standard time concepts including date, time, instant, and time-zone.
  • Immutable implementations for thread-safety.
  • Provide an effective API suitable for developer usability.
  • Provide a limited set of calendar systems and be extensible to others in the future.

java.time.LocalDate

            LocalDate is an immutable object that represents a plain date with out time of day. It doesn’t carry any information about the offset or time zone. It stores the date in YYYY-MM-DD format, for example, ‘2014-03-18’.


import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoField;

public class JavaTime {
 
 public static void main(String[] args) { 
  
  LocalDate ldate1 = LocalDate.of(2019, 02, 10);
  System.out.println(ldate1);
  
  LocalDate ldate2 = LocalDate.parse("2019-02-10");
  System.out.println(ldate2);
  
  LocalDate ldate3 = LocalDate.now();
  System.out.println(ldate3);
  
  LocalDate ldate4 = LocalDate.now(ZoneId.of("Asia/Calcutta"));
  System.out.println(ldate4);
  
  LocalDate ldate5 = LocalDate.now();
  System.out.println(ldate5.getChronology());
  System.out.println(ldate5.getEra());
  System.out.println(ldate5.getYear());
  System.out.println(ldate5.get(ChronoField.YEAR));
  System.out.println(ldate5.getLong(ChronoField.YEAR));
  System.out.println(ldate5.getMonth());
  System.out.println(ldate5.getMonthValue());
  System.out.println(ldate5.getDayOfMonth());
  System.out.println(ldate5.getDayOfYear());
  System.out.println(ldate5.getDayOfWeek());
 
 }
}


Output:
2019-02-10
2019-02-10
2019-02-10
2019-02-10
ISO
CE
2019
2019
FEBRUARY
2
10
41
SUNDAY
2019