This presentation provides a comprehensive overview of modern programming in Java. It focuses only on Java 8 features: Lambdas, Streams and Date Time API. It also briefly covers refactoring legacy Java code to Java 8.
12. What are lambda functions?
❖ (Java 8) One way to think about lambdas is
“anonymous function” or “unnamed function” - they
are functions without a name and are not associated
with any class
❖ They don’t change external state
13. What is functional programming?
❖ Functional languages view programs as an entity—
called a function—that accepts inputs and produces
output
❖ Functions are connected together by their outputs to
other functions’ inputs
❖ Underlying approach: “Evaluate an expression. Then
use the results for something else.”
20. $ cat limerick.txt
There was a young lady of Niger
Who smiled as she rode on a tiger.
They returned from the ride
With the lady inside
And a smile on the face of the tiger.
21. $ cat limerick.txt | tr -cs "[:alpha:]" "n" | awk '{print length(), $0}' | sort | uniq
1 a
2 as
2 of
2 on
3 And
3 Who
3 she
3 the
3 was
4 They
4 With
4 face
4 from
4 lady
4 ride
4 rode
5 Niger
5 There
5 smile
5 tiger
5 young
6 inside
6 smiled
8 returned
22. List<String> lines
= Files.readAllLines(Paths.get("./limerick.txt"), Charset.defaultCharset());
Map<Integer, List<String>> wordGroups
= lines.stream()
.map(line -> line.replaceAll("W", "n").split("n"))
.flatMap(Arrays::stream)
.sorted()
.distinct()
.collect(Collectors.groupingBy(String::length));
wordGroups.forEach( (count, words) -> {
words.forEach(word -> System.out.printf("%d %s %n", count, word));
});
1 a
2 as
2 of
2 on
3 And
3 Who
3 she
3 the
3 was
4 They
4 With
4 face
4 from
4 lady
4 ride
4 rode
5 Niger
5 There
5 smile
5 tiger
5 young
6 inside
6 smiled
8 returned
24. public static void main(String []file) throws Exception {
// process each file passed as argument
// try opening the file with FileReader
try (FileReader inputFile = new FileReader(file[0])) {
int ch = 0;
while( (ch = inputFile.read()) != -1) {
// ch is of type int - convert it back to char
System.out.print( (char)ch );
}
}
// try-with-resources will automatically release FileReader object
}
public static void main(String []file) throws Exception {
Files.lines(Paths.get(file[0])).forEach(System.out::println);
}
Existing APIs are enriched with
lambdas and streams support
25. Java 8 is the new Groovy ;-)
import java.io.*;
class Type {
public sta7c void main(String []files) {
// process each file passed as argument
for(String file : files) {
// try opening the file with FileReader
try (FileReader inputFile = new FileReader(file)) {
int ch = 0;
while( (ch = inputFile.read()) != -1) {
// ch is of type int - convert it back to char
System.out.print( (char)ch );
}
} catch (FileNotFoundExcep7on fnfe) {
System.err.prinR("Cannot open the given file %s ", file);
}
catch(IOExcep7on ioe) {
System.err.prinR("Error when processing file %s; skipping it", file);
}
// try-with-resources will automa7cally release FileReader object
}
}
}
args.each { println new File(it).getText() }
26. Agenda
• Introduction & Overview
• Lambdas
• Functional interfaces
• Streams
• Parallel streams
• Date & Time package
• Refactoring to Java 8
28. Java 8 lambdas - “Hello world!”
interface LambdaFunction {
void call();
}
class FirstLambda {
public static void main(String []args) {
LambdaFunction lambdaFunction = () -> System.out.println("Hello world");
lambdaFunction.call();
}
}
Functional interface - provides
signature for lambda functions
Lambda function/expression
Call to the lambda
Prints “Hello world” on the console when executed
29. Parts of a lambda expression
() -> System.out.println("Hello world");
No parameters, i.e., ()
Arrow operator that separates
parameters and the body
The lambda body
Return type “void” inferred from the body
30. Method references
Method references - “syntactic sugar” for lambda
functions
They “route” function parameters
arg -> System.out.println(arg)
System.out::println
32. Method references
Cannot use method references when lambda functions do
more than“routing” function parameters
strings.forEach(string -> System.out.println(string.toUpperCase()));
More processing here than just
“routing” parameters
50. Built-in interfaces
Predicate<T> Checks a condition and returns a
boolean value as result
In filter() method in
java.util.stream.Stream
which is used to remove elements
in the stream that don’t match the
given condition (i.e., predicate) asConsumer<T> Operation that takes an argument but
returns nothing
In forEach() method in
collections and in
java.util.stream.Stream; this
method is used for traversing all
the elements in the collection orFunction<T,
R>
Functions that take an argument and
return a result
In map() method in
java.util.stream.Stream to
transform or operate on the passed
value and return a result.
Supplier<T> Operation that returns a value to the
caller (the returned value could be
same or different values)
In generate() method in
java.util.stream.Stream to
create a infinite stream of
elements.
51. Predicate interface
Stream.of("hello", "world")
.filter(str -> str.startsWith("h"))
.forEach(System.out::println);
The filter() method takes a Predicate
as an argument (predicates are
functions that check a condition and
return a boolean value)
53. Predicate interface
A Predicate<T> “affirms” something as true or
false: it takes an argument of type T, and returns a
boolean value. You can call test() method on a
Predicate object.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
// other methods elided
}
58. Consumer interface
A Consumer<T> “consumes” something: it takes
an argument (of generic type T) and returns
nothing (void). You can call accept() method on a
Consumer object.
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// the default andThen method elided
}
63. Function interface
A Function<T, R> “operates” on something and
returns something: it takes one argument (of
generic type T) and returns an object (of generic
type R). You can call apply() method on a Function
object.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
// other methods elided
}
65. Function interface: Example
import java.util.Arrays;
import java.util.function.Function;
public class CombineFunctions {
public static void main(String []args) {
Function<String, Integer> parseInt = Integer:: parseInt ;
Function<Integer, Integer> absInt = Math:: abs ;
Function<String, Integer> parseAndAbsInt = parseInt.andThen(absInt)
Arrays.stream("4, -9, 16".split(", "))
.map(parseAndAbsInt)
.forEach(System. out ::println);
}
}
Prints:
4
9
16
66. Supplier interface
import java.util.stream.Stream;
import java.util.Random;
class GenerateBooleans {
public static void main(String []args) {
Random random = new Random();
Stream.generate(random::nextBoolean)
.limit(2)
.forEach(System.out::println);
}
}
Prints two boolean
values “true” and “false”
in random order
68. Supplier interface
A Supplier<T> “supplies” takes nothing but
returns something: it has no arguments and
returns an object (of generic type T). You can call
get() method on a Supplier object
@FunctionalInterface
public interface Supplier<T> {
T get();
// no other methods in this interface
}
69. Supplier interface: Example
Supplier<String> currentDateTime = () -> LocalDateTime.now().toString();
System.out.println(currentDateTime.get());
Prints current time:
2015-10-16T12:40:55.164
70. Summary of built-in interfaces in
java.util.function interface
❖ There are only four core functional interfaces in this
package: Predicate, Consumer, Function, and Supplier.
❖ The rest of the interfaces are primitive versions, binary
versions, and derived interfaces such as
UnaryOperator interface.
❖ These interfaces differ mainly on the signature of the
abstract methods they declare.
❖ You need to choose the suitable functional interface
based on the context and your need.
71. Agenda
• Introduction & Overview
• Lambdas
• Functional interfaces
• Streams
• Parallel streams
• Date & Time package
• Refactoring to Java 8
72. Java 8 streams (and parallel streams):
Excellent example of applying functional
programming in practice
78. IntStream.range(1, 6)
You can use range or iterate
factory methods in the
IntStream interface
IntStream.iterate(1, i -> i + 1).limit(5)
79. 1 2 3 4 5
1 4 9 16 25
map(i -> i * i)
IntStream.range(1, 5).map(i -> i * i).forEach(System.out::println);
Using streams instead of imperative for i = 1 to 5, print i * i
86. Pattern.compile(" ").splitAsStream("java 8 streams").forEach(System.out::println);
This code splits the input string “java 8
streams” based on whitespace and hence
prints the strings “java”, “8”, and
“streams” on the console
105. import java.util.Arrays;
class StringConcatenator {
public static String result = "";
public static void concatStr(String str) {
result = result + " " + str;
}
}
class StringSplitAndConcatenate {
public static void main(String []args) {
String words[] = "the quick brown fox jumps over the lazy dog".split(" ");
Arrays.stream(words).forEach(StringConcatenator::concatStr);
System.out.println(StringConcatenator.result);
}
}
Gives wrong results with
with parallel() call
106. Agenda
• Introduction & Overview
• Lambdas
• Functional interfaces
• Streams
• Parallel streams
• Date & Time package
• Refactoring to Java 8
107. –Craig Larman
"The critical design tool for software development
is a mind well educated in design principles"
109. Discussion Example
// using java.util.Date
Date today = new Date();
System.out.println(today);
$ java DateUse
Wed Dec 02 17:17:08 IST 2015
Why should we get the
time and timezone details
if I only want a date? Can
I get rid of these parts?
No!
110. So What?!
Date today = new Date();
System.out.println(today);
Date todayAgain = new Date();
System.out.println(todayAgain);
System.out.println(today.compareTo(todayAgain) == 0);
Thu Mar 17 13:21:55 IST 2016
Thu Mar 17 13:21:55 IST 2016
false
What is going
on here?
115. Refactored Example …
You can use only date,
time, or even timezone,
and combine them as
needed!
LocalDate today = LocalDate.now();
System.out.println(today);
LocalTime now = LocalTime.now();
System.out.println(now);
ZoneId id = ZoneId.of("Asia/Tokyo");
System.out.println(id);
LocalDateTime todayAndNow = LocalDateTime.now();
System.out.println(todayAndNow);
ZonedDateTime todayAndNowInTokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(todayAndNowInTokyo);
2016-03-17
13:28:06.927
Asia/Tokyo
2016-03-17T13:28:06.928
2016-03-17T16:58:06.929+09:00[Asia/Tokyo]
116. “Fluent interfaces”
❖ Code is more readable and easier to use:
❖ Classes in this package have numerous static methods
(many of them factory methods)
❖ Methods in the classes follow a common naming
convention (for example, they use the prefixes plus
and minus to add or subtract date or time values)
117. java.time Sub-packages
❖ java.time.temporal —Accesses date/time fields and
units
❖ java.time.format —Formats the input and output of
date/time objects
❖ java.time.zone —Handles time zones
❖ java.time.chrono —Supports calendar systems such as
Japanese and Thai calendars
118. ISO-8601 Calendar System Format
❖ The Java 8 date and time API uses ISO 8601 as the
default calendar format.
❖ In this internationally accepted format, the date and
time values are sorted from the largest to the smallest
unit of time: year, month/week, day, hour, minute,
second, and millisecond/nanosecond.
❖ Example: LocalDate is represented in the in a year-
month-day format (YYYY-MM-DD), as in, 2015-10-26.
120. java.time.LocalDate
LocalDate valentinesDay = LocalDate.of(2016, 14, 2);
System.out.println("Valentine's day is on: " + valentinesDay);
Exception in thread "main"
java.time.DateTimeException: Invalid value
for MonthOfYear(valid values 1 - 12): 14
121. java.time.LocalDate
long visaValidityDays = 180L;
LocalDate currDate = LocalDate.now();
System.out.println("My Visa expires on: " + currDate.plusDays(visaValidityDays));
My Visa expires on: 2016-04-23
125. java.time.LocalTime
long hours = 6;
long minutes = 30;
LocalTime currTime = LocalTime.now();
System.out.println("Current time is: " + currTime);
System.out.println("My meeting is at: " +
currTime.plusHours(hours).plusMinutes(minutes));
Current time is: 12:29:13.624
My meeting is at: 18:59:13.624
128. java.time.LocalDateTime
LocalDateTime christmas = LocalDateTime.of(2015, 12, 25, 0, 0);
LocalDateTime newYear = LocalDateTime.of(2016, 1, 1, 0, 0);
System.out.println("New Year 2016 comes after Christmas 2015”
+ newYear.isAfter(christmas));
New Year 2016 comes after
Christmas 2015? true
129. java.time.LocalDateTime
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("Today's date and current time: " + dateTime);
System.out.println("The date component is: " + dateTime.toLocalDate());
System.out.println("The time component is: " + dateTime.toLocalTime());
Today's date and current time:
2015-11-04T13:19:10.497
The date component is: 2015-11-04
The time component is: 13:19:10.497
130. java.time.Instant
import java.time.Instant;
public class UsingInstant {
public static void main(String args[]){
// prints the current timestamp with UTC as time zone
Instant currTimeStamp = Instant.now();
System.out.println("Instant timestamp is: "+ currTimeStamp);
// prints the number of seconds as Unix timestamp from epoch time
System.out.println("Number of seconds elapsed: " + currTimeStamp.getEpochSecond());
// prints the Unix timestamp in milliseconds
System.out.println("Number of milliseconds elapsed: " + currTimeStamp.toEpochMilli());
}
}
Instant timestamp is: 2015-11-02T03:16:04.502Z
Number of seconds elapsed: 1446434164
Number of milliseconds elapsed: 1446434164502
131. java.time.Period
LocalDate manufacturingDate = LocalDate.of(2016, Month.JANUARY, 1);
LocalDate expiryDate = LocalDate.of(2018, Month.JULY, 18);
Period expiry = Period.between(manufacturingDate, expiryDate);
System.out.printf("Medicine will expire in: %d years, %d months, and %d days (%s)n",
expiry.getYears(), expiry.getMonths(), expiry.getDays(), expiry);
Medicine will expire in: 2 years, 6 months, and 17
days (P2Y6M17D)
133. The Java 8 date and time API differentiates how humans
and computers use date- and time-related information.
For example, the Instant class represents a Unix
timestamp and internally uses long and int variables.
Instant values are not very readable or usable by
humans because the class does not support methods
related to day, month, hours, and so on (in contrast, the
Period class supports such methods).
137. TemporalUnit
import java.time.temporal.ChronoUnit;
public class ChronoUnitValues {
public static void main(String []args) {
System.out.println("ChronoUnit DateBased TimeBased Duration");
System.out.println("---------------------------------------");
for(ChronoUnit unit : ChronoUnit.values()) {
System.out.printf("%10s t %b tt %b tt %s %n”,
unit, unit.isDateBased(), unit.isTimeBased(), unit.getDuration());
}
}
}
138.
139. ZoneId
System.out.println("My zone id is: " + ZoneId.systemDefault());
My zone id is: Asia/Kolkata
ZoneId AsiaKolkataZoneId = ZoneId.of("Asia/Kolkata");
145. DateTimeFormatter
Wake up time: 06:00:00
LocalTime wakeupTime = LocalTime.of(6, 0, 0);
System.out.println("Wake up time: " + DateTimeFormatter.ISO_TIME.format(wakeupTime));
01 Jan 2016
DateTimeFormatter customFormat = DateTimeFormatter.ofPattern("dd MMM yyyy");
System.out.println(customFormat.format(LocalDate.of(2016, Month.JANUARY, 01)));
146. Uppercase and lowercase letters can have similar or
different meanings when used in format strings for
dates and times. Read the Javadoc for these patterns
carefully before trying to use these letters. For example,
in dd-MM-yy, MM refers to month; however, in dd-mm-
yy, mm refers to minutes !
147. Formatting Dates
• G (era: BC, AD)
• y (year of era: 2015, 15)
• Y (week-based year: 2015, 15)
• M (month: 11, Nov, November)
• w (week in year: 13)
• W (week in month: 2)
• E (day name in week: Sun, Sunday)
• D (day of year: 256)
• d (day of month: 13)
148. Custom Date Patterns
public class CustomDatePatterns {
public static void main(String []args) {
// patterns from simple to complex ones
String [] dateTimeFormats = {
"dd-MM-yyyy", /* d is day (in month), M is month, y is year */
"d '('E')' MMM, YYYY", /*E is name of the day (in week), Y is year*/
"w'th week of' YYYY", /* w is the week of the year */
"EEEE, dd'th' MMMM, YYYY" /*E is day name in the week */
};
LocalDateTime now = LocalDateTime.now();
for(String dateTimeFormat : dateTimeFormats) {
System.out.printf("Pattern "%s" is %s %n", dateTimeFormat,
DateTimeFormatter.ofPattern(dateTimeFormat).format(now));
}
}
} Pattern "dd-MM-yyyy" is 05-11-2015
Pattern "d '('E')' MMM, YYYY" is 5 (Thu) Nov, 2015
Pattern "w'th week of' YYYY" is 45th week of 2015
Pattern "EEEE, dd'th' MMMM, YYYY" is Thursday, 05th November, 2015
149. Formatting Times
• a (marker for the text a.m./p.m. marker)
• H (hour: value range 0–23)
• k (hour: value range 1–24)
• K (hour in a.m./p.m.: value range 0–11)
• h (hour in a.m./p.m.: value range 1–12)
• m (minute)
• s (second)
• S (fraction of a second)
• z (time zone: general time-zone format)
150. Custom Time Patterns
class CustomTimePatterns {
public static void main(String []args) {
// patterns from simple to complex ones
String [] timeFormats = {
"h:mm", /* h is hour in am/pm (1-12), m is minute */
"hh 'o''clock'", /* '' is the escape sequence to print a single quote */
"H:mm a", /* H is hour in day (0-23), a is am/pm*/
"hh:mm:ss:SS", /* s is seconds, S is milliseconds */
"K:mm:ss a" /* K is hour in am/pm(0-11) */
};
LocalTime now = LocalTime.now();
for(String timeFormat : timeFormats) {
System.out.printf("Time in pattern "%s" is %s %n", timeFormat,
DateTimeFormatter.ofPattern(timeFormat).format(now));
}
}
}
Time in pattern "h:mm" is 12:27
Time in pattern "hh 'o''clock'" is 12 o'clock
Time in pattern "H:mm a" is 12:27 PM
Time in pattern "hh:mm:ss:SS" is 12:27:10:41
Time in pattern "K:mm:ss a" is 0:27:10 PM
151. Flight Travel - Time Calculation - Example
DateTimeFormatter dateTimeFormatter =
DateTimeFormatter.ofPattern("dd MMM yyyy hh.mm a");
// Leaving on 1st Jan 2016, 6:00am from "Singapore"
ZonedDateTime departure = ZonedDateTime.of(
LocalDateTime.of(2016, Month.JANUARY, 1, 6, 0),
ZoneId.of("Asia/Singapore"));
System.out.println("Departure: " + dateTimeFormatter.format(departure));
// Arrival on the same day in 10 hours in "Auckland"
ZonedDateTime arrival =
departure.withZoneSameInstant(ZoneId.of("Pacific/Auckland")).plusHours(10);
System.out.println("Arrival: " + dateTimeFormatter.format(arrival));
Departure: 01 Jan 2016 06.00 AM
Arrival: 01 Jan 2016 09.00 PM
152. Agenda
• Introduction & Overview
• Lambdas
• Functional interfaces
• Streams
• Parallel streams
• Date & Time package
• Refactoring to Java 8
153. Examples of refactorings (to Java 8)
❖ Convert anonymous inner
classes to lambda expressions
(when they are functional
interfaces)
❖ Convert for/foreach loops to
streams (i.e., external iteration
to internal iteration)
154. Refactoring loops to streams
❖ Replace if conditions with ‘filter’ and calls to methods
that return a boolean value (Predicate)
❖ Replace accumulation operations with reduce (or its
special forms like sum, count, etc).
155. Source: LAMBDAFICATOR: From Imperative to Functional Programming through Automated Refactoring. Lyle Franklin; Alex
Gyori; Jan Lahoda; Danny Dig. 35th International Conference on Software Engineering (ICSE), 2013.
156. Tool support for refactoring
❖ Most Java IDEs provide
suggestions to automatically
refactor to lambdas and
streams
❖ IDEs that support Java 8
refactoring include: Eclipse,
IntelliJ Idea and NetBeans
162. Suggested Reading
❖ Refactoring with Loops and Collection Pipelines
(Martin Fowler, 2015)
❖ Pragmatic Functional Refactoring with Java 8 (Raoul-
Gabriel Urma & Richard Warburton, 2015)
❖ Migrating to Java 8 (IntelliJ IDEA, 2016)