5. Faster : Applications that have moved to Java 8 see some sort of speed improvement without
any specific work or tuning.
Less Code : A more functional style for the new APIs, focusing on WHAT you want to achieve
and not HOW to do it.
Easy to Parallelize : JVM splits operation into separate jobs and use fork/join to run them on
multiple cores
• parallelStream
Minimize Null Pointers
• Optional Type
5
6. Faster
Performance Improvements in Common Data Structures:
Benchmarks of the ever-popular HashMap show that performance is better in Java 8. No need to learn the new
Streams API or lambda syntax or even change the existing code to get speed improvements in your application.
Garbage Collector Improvements:
Poor garbage collection performance will impact an application’s performance. Java 8 has substantial changes to
GC that improve performance and simplify tuning. Removal of PermGen and the introduction of Metaspace.
Fork/Join Speed Improvements:
The fork/join framework was new in Java 7, and was the latest effort to simplify concurrent programming using
the JVM. A lot of work went into improving it further for Java 8. Fork/join is now the framework that’s used
under the covers for parallel operations in the Streams API.
6
9. Interface Improvements
Interfaces can now define static methods:
A common scenario in Java libraries is, for some interface 'XYZ ' there would be a companion utility class
'XYZUtility' with static methods for generating or working with XYZ instances. With the ability to define static
methods in the interfaces, in many cases the XYZUtility class can go away, with its public methods going on the
interface instead.
Interfaces can now define default methods (Defender Methods)
Prior to Java 8, it was essentially impossible for Java libraries to add methods to interfaces. Adding a method to
an interface would mean breaking all existing code that implements the interface. Now, as long as a sensible
default implementation of a method can be provided, library maintainers can add methods to these interfaces.
9
14. After introducing Default(Defender) Methods, it seems that interfaces and abstract
classes are same. However, they are still different concept in Java 8.
Abstract class can define constructor.
They are more structured and can have a state associated with them. While in
contrast, default method can be implemented only in the terms of invoking other
interface methods, with no reference to a particular implementation's state.
Abstract Classes can have fields that are not static and final, and define public,
protected, and private concrete methods.With interfaces, all fields are automatically
public, static, and final, and all methods that you declare or define (as default
methods) are public.
Abstract Class is object oriented while Interface is functionality oriented.
14
15. Functional Interfaces
Java has always been an Object Oriented Programming language. Everything in java
programming revolves around Objects
There is no way of defining just a function / method which stays in Java all by itself.
There is no way of passing a method as argument or returning a method body for that
instance.
15
16. In Java, a functional interface is basically an interface with a single abstract method.
This kind of interfaces are also known as SAM (Single Abstract Method) types.
An interface is considered a functional interface if it contains one and only one
abstract method with no default implementation
Examples??
java.lang.Runnable, java.awt.event.ActionListener, java.util.Comparator,
java.util.concurrent.Callable.
16
17. @FunctionalInterface
@FunctionalInterface is a new interface added in Java 8 to indicate that an interface
type declaration is intended to be a functional interface as defined by the Java
Language Specification.
@FunctionalInterface can be used for compiler level errors when the interface you
have annotated is not a valid Functional Interface.
@FunctionalInterface annotation is a facility to avoid accidental addition of abstract
methods in the functional interfaces.
17
19. Function<T, R> - take a T as input, return an R as ouput [R apply(T t)]
Predicate<T> - take a T as input, return a boolean as output [boolean test(T t)]
Consumer<T> - take a T as input, perform some action and don't return anything
[void accept(T t)]
Supplier<T> - with nothing as input, return a T [T get()]
BinaryOperator<T> - take two T's as input, return one T as output, useful for "reduce"
operations [T apply(T t1,T t2)]
IntConsumer - take an int as input, perform some action and don't return anything
[void accept(Int i)]
IntUnaryOperator - an operation on a single int-valued operand that produces an int-valued
result [int applyAsInt(int i)] 19
21. A bit of Lambda Calculus!!!
The λ-calculus is an elegant notation for working with applications of functions to
arguments.
In λ-calculus, the idea is the same: we create a function by using λ to specify which
arguments a function takes in, then we give an expression for the function’s return
value.
λ-calculus treats functions "anonymously", without giving them explicit names.
λ-calculus only uses functions of a single input. An ordinary function that requires
two inputs, for instance the function, can be reworked into an equivalent function
that accepts a single input, and as output returns another function, that in turn
accepts a single input.
21
22. Lambda Expressions
Lambda Expression is thought to be one of the biggest features of
Java 8 through which we can visualize functional programming in the
Java object oriented world.
It’s a shorthand that allows you to write a method in the same place
where it is going to be used.
Useful in places where a method is being used only once, and the
method definition is short. It saves the effort of declaring and writing
a separate method to the containing class
One of the major benefits of functional interface is the possibility to
use lambda expressions to instantiate them.
22
23. Anonymous classes to Lambda Expression
Remove below things in order:
new keyword new,
class name and it’s parentheses Comparator,
class opening and closing braces { };,
@Override annotation (if have any),
remove method declaration (leave argument parentheses (int arg1, int arg2)) public int compare
removing method opening { and closing braces } is not necessary, however, if there is single line of code in
it then it is advisable to remove them.
add -> between parentheses () and execution code inside { }
23
25. List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2){
return p1.getName().compareTo(p2.getName());
}
});
25
26. List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2){
return p1.getName().compareTo(p2.getName());
}
} );
26
27. List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2){
return p1.getName().compareTo(p2.getName());
}
} );
27
28. List<Person> people = loadPeople();
Collections.sort(people,
(Person p1, Person p2) ---> p1.getName().compareTo(p2.getName()));
28
29. List<Person> people = loadPeople();
Collections.sort(people,
(Person p1, Person p2) ---> p1.getName().compareTo(p2.getName()));
29
30. List<Person> people = loadPeople();
Collections.sort(people,
(p1,p2) ---> p1.getName().compareTo(p2.getName()));
30
31. List<Person> people = loadPeople();
Collections.sort(people, (p1,p2) ---> p1.getName().compareTo(p2.getName()));
Best Practices:
Make use of parameter type inference
Only specify the types when compiler needs it
Prefer expression lambda over block ones and if required create a separate method.
Avoid using parameter brackets for single argument methods.
31
35. Anonymous Class vs Lambda Expression
An anonymous class object creates a separate class
file after compilation which increases the size jar
while after compilation Lambda expression
becomes invokedynamic which dynamic language
implementation.
We can use this keyword to represent the current
class in lambda expression while in the case of
anonymous class this keyword represents that
particular anonymous class.
In the case of Lambda expression, we need to
provide the function body only while in the case of
anonymous class we need to write the redundant
class definition.
35
36. Function<T, R> - take a T as input, return an R as ouput
(x) --> Integer.parseInt(x);
Predicate<T> - take a T as input, return a boolean as output
(x) --> x%2==0;
Consumer<T> - take a T as input, perform some action and don't return anything
(x) -> System.out.println(x.toLowerCase());
Supplier<T> - with nothing as input, return a T.
() --> “Sample String”;
BinaryOperator<T> - take two T's as input, return one T as output
(x, y) --> x + y;
IntConsumer - take an int as input, perform some action and don't return anything
(x) --> System.out.println(x);
IntUnaryOperator - an operation on a single int-valued operand that produces an INT
(x) --> x * x;
36
37. Streams API
Sounds similar to InputStream and OutputStream from Java I/O. But Java 8 streams
are a completely different thing.
A java.util.Stream represents a sequence of elements on which one or more operations
can be performed.
Stream operations are either intermediate or terminal.
Intermediate operations return a stream so we can chain multiple intermediate
operations without using semicolons. Such a chain of stream operations is also
known as operation pipeline.
Terminal operations are either void or return a non-stream result.
37
38. Not a data structure.
Streams have no storage;
A stream is something like an iterator. The
values "flow past" (analogy to a stream of water)
and then they're gone.
A stream can only be traversed once, then it's
used up.
Designed for lambdas. All stream operations
take lambdas as arguments
Parallelizable. If a stream is designated as
parallel all operations on it will automatically be
done in parallel without explicit use of threads.
38
44. Collection is a data structure. Based on the problem you decide which collection to be used
like ArrayList, LinekedList (Considering time and space complexity) . Where as Stream is just
a processing kind of tool, which makes your life easy.
Collection can be considered as in-memory data structure, where we can add , remove
element. Where as in Stream you can perform two kind of operation:
a. Intermediate operation : Filter, map ,sort,limit on the result set
b. Terminal operation : forEach ,collect the result set to a collection.
With stream we can't add or remove elements.
Stream is kind of iterator, you can traverse collection through stream. Note, you can traverse
stream only once
While collections have a finite size, streams need not. Short-circuiting operations such as
limit(n) or findFirst() can allow computations on infinite streams to complete in finite time.
44
45. Parallel Streams
Streams can be executed in parallel to increase
runtime performance on large amount of input
elements.
Parallel streams use a common ForkJoinPool
available via the static ForkJoinPool.commonPool()
method. The size of the underlying thread-pool uses
up to five threads - depending on the amount of
available physical CPU cores:
Collections support the method parallelStream() to
create a parallel stream of elements. Alternatively
you can call the intermediate method parallel() on
a given stream to convert a sequential stream to a
parallel counterpart.
45
48. The parallel stream utilizes all available threads
from the common ForkJoinPool for executing the
stream operations. The output may differ in
consecutive runs because the behavior which
particular thread is actually used is non-
deterministic.
48
51. filter
Filter accepts a predicate to filter all elements of the stream. This operation is
intermediate which enables us to call another stream operation (forEach) on the
result.
stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
51
52. sorted
Sorted is an intermediate operation which returns a sorted view of the stream. The
elements are sorted in natural order unless you pass a custom Comparator.
stringCollection
.stream()
.sorted()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
52
53. map
The intermediate operation map converts each element into another object via the
given function. But you can also use map to transform each object into another type.
The generic type of the resulting stream depends on the generic type of the function
you pass to map
stringCollection
.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
53
54. count
Count is a terminal operation returning the number of elements in the stream as a
long.
long startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
54
55. collect
Collect is an extremely useful terminal operation to transform the elements of the
stream into a different kind of result, e.g. a List, Set or Map.
Collect accepts a Collector which consists of four different operations: a supplier, an
accumulator, a combiner and a finisher. This sounds super complicated at first, but the
good part is Java 8 supports various built-in collectors via the Collectors class.
List<Person> filtered =
persons
.stream()
.filter(p -> p.name.startsWith("P"))
.collect(Collectors.toList());
55
56. count
Map<Integer, List<Person>> personsByAge = persons
.stream()
.collect(Collectors.groupingBy(p -> p.age));
personsByAge
.forEach((age, p) -> System.out.format("age %s: %sn", age, p));
create aggregations on the elements of the stream, e.g. determining the average age of
all persons:
Double averageAge = persons
.stream()
.collect(Collectors.averagingInt(p -> p.age));
56
57. count
n order to transform the stream elements into a map, we have to specify how both the
keys and the values should be mapped. Keep in mind that the mapped keys must be
unique, otherwise an IllegalStateException is thrown. You can optionally pass a merge
function as an additional parameter to bypass the exception:
Map<Integer, String> map = persons
.stream()
.collect(Collectors.toMap(
p -> p.age,
p -> p.name,
(name1, name2) -> name1 + ";" + name2));
57
58. reduce
The reduce operation combines all elements of the stream into a single result. Java 8
supports two different kind of reduce methods.
1. Accepts a BinaryOperator accumulator function/reduces a stream of elements to
exactly one element of the stream. determine the oldest person:
persons
.stream()
.reduce((p1, p2) -> p1.age > p2.age ? p1 : p2)
.ifPresent(System.out::println);
58
59. reduce
2. Accepts both an identity value and a BinaryOperator accumulator.
construct a new Person with the aggregated names and ages from all other persons in
the stream:
Person result =
persons
.stream()
.reduce(new Person("", 0), (p1, p2) -> {
p1.age += p2.age;
p1.name += p2.name;
return p1;
});
59
60. Most stream operations accept some kind of lambda expression parameter, a
functional interface specifying the exact behavior of the operation.Most of those
operations must be both non-interfering and stateless.
A function is non-interfering when it does not modify the underlying data source of
the stream.
A function is stateless when the execution of the operation is deterministic.
60
61. Optional
New class 'Optional' added to Java 8
Optional is a simple container for a value which may be null
or non-null. Think of a method which may return a non-null
result but sometimes return nothing. Instead of returning null
an Optional can be returned in Java 8.
Simple concept - two states
• present, with a value - Optional.of(foo)
• empty - Optional.empty()
61
65. Best Practices:
Variable of type Optional must NEVER be null.
Assign empty variable as Optional.empty();
Optional is designed as a return type and not an input type.
Prefer functional methods like orElse()
Using isPresent() a lot is misusing the feature.
65
66. Date APIs
Date & Time API is a new introduction in Java 8
Designed to overcome all the flaws in the legacy
date time implementations.
66
67. Why new Date API?
Java Date Time classes are not defined consistently, we have Date Class in both java.util as
well as java.sql packages. Again formatting and parsing classes are defined in java.text package.
java.util.Date contains both date and time, whereas java.sql.Date contains only date. Also both
the classes have same name, that is a very bad design itself.
There are no clearly defined classes for time, timestamp, formatting and parsing.
All the Date classes are mutable, so they are not thread safe. It’s one of the biggest problem
with Java Date and Calendar classes.
Date class have no timezone support. So java.util.Calendar and java.util.TimeZone classes were
introduced, but they also have all the problems listed above.
67
69. Immutability: All the classes in the new Date Time API are immutable and
good for multithreaded environments.
Separation of Concerns: The new API separates clearly between human
readable date time and machine time (unix timestamp). It defines separate
classes for Date, Time, DateTime, Timestamp, Timezone etc.
Clarity: The methods are clearly defined and perform the same action in all
the classes. For example, to get the current instance we have now() method.
There are format() and parse() methods defined in all these classes rather
than having a separate class for them. All the classes use Factory Pattern and
Strategy Pattern for better handling. Once you have used the methods in one
of the class, working with other classes won’t be hard.
Utility operations: All the new Date Time API classes comes with methods
to perform common tasks, such as plus, minus, format, parsing, getting
separate part in date/time etc.
69
70. The java.time.LocalDate class represents a date without time or timezones; the
java.time.LocalTime class represents time without dates and timezones; the
java.time.LocalDateTime class represents both date and time without time zones.
The java.time.Instant class represents a Unix timestamp. Instants can be used to
create legacy java.util.Date objects
The java.time.Period is used to measure the amount of time in terms of years,
months, and days.
The java.time.Duration class represents time in terms of hours, minutes,seconds,
and fraction of seconds.
ZoneId identifies a time zone; ZoneOffset represents time zone offset from
UTC/Greenwich.
70
71. ZonedDateTime provides support for all three aspects: date, time, and timezone.
The java.time.format.DateTimeFormatter class provides support for reading or
printing date and time values in different formats.
The DateTimeFormatter class provides predefined constants (such as ISO_DATE
and ISO_TIME ) for formatting date and time values.
The Java 8 date and time API differentiates how humans and computers use date-
and time-related information.
71
74. Repeatable Annotations
Prior to Java8, it was forbidden to declare more than one annotation of the same type
to the same location of a code.
Annotations in Java 8 are repeatable.
Java 8 enables us to use multiple annotations of the same type by declaring the
annotation @Repeatable
74
75. Prior to Java8, to have a repeated annotation, will have to group them in a container
annotation
With Java8 repeating annotations, it gives us the flexibility to write the same thing
without any container annotation
Though the container annotation was not used here, the Java compiler this time
around takes responsibility for wrapping the two annotations into a container.
75
76. String Joiners
Java 8 added a new class called StringJoiner.and as the name suggests we can use this
class to join strings.
String joined = String.join("/", "2014", "10", "28" ); // "2014/10/28"
Intention is to abstract away the choice of seperator from the act of adding entries.
StringJoiner is very useful, when it is needed to join Strings in a Stream.
String joinedString = Stream.of("Foo","Bar","Baz").collect(Collectors.joining(":", "[", "]"));
System.out.println(joinedString);
76
Java 7 is now end of life—making Java 8 the only Oracle-supported option until Java 9. However, since organizations value stability over trendiness, many of us are still working with Java 7, or even 6.
http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf
Why can't default methods override equals, hashCode, and toString?
Since the ValidationUtils will need to have the validation logic very specific to the business requirement for SimpleInterface the best place to define it can be in the interface itself and we can totally get rid of the ValidationUtils class.
Abstract is object oriented. It offers the basic data an 'object' should have and/or functions it should be able to do. It is concerned with the object's basic characteristics: what it has and what it can do. Hence objects which inherit from the same abstract class share the basic characteristics (generalization). It reflects "is a" relation with concrete classes
Interface is functionality oriented. It defines functionalities an object should have. Regardless what object it is, as long as it can do these functionalities, which are defined in the interface, it's fine. It ignores everything else. An object/class can contain several (groups of) functionalities; hence it is possible for a class to implement multiple interfaces. It provides "has a" capability for classes.
Simplification1:
the function
sqsum(x,y) = x*x + y*y
can be rewritten in anonymous form as
(x,y) -> x*x +y*y;
Simplification2:
sqsum(x,y) = x*x + y*y
can be reworked into
x -> (y->x*x + y*y)
A lambda expression can have zero, one or more parameters.
The type of the parameters can be explicitly declared or it can be inferred from the context. e.g. (int a) is same as just (a)
Parameters are enclosed in parentheses and separated by commas. e.g. (a, b) or (int a, int b) or (String a, int b, float c)
Empty parentheses are used to represent an empty set of parameters. e.g. () -> 42
When there is a single parameter, if its type is inferred, it is not mandatory to use parentheses. e.g. a -> return a*a
The body of the lambda expressions can contain zero, one or more statements.
If body of lambda expression has single statement curly brackets are not mandatory and the return type of the anonymous function is the same as that of the body expression.
When there is more than one statement in body than these must be enclosed in curly brackets (a code block) and the return type of the anonymous function is the same as the type of the value returned within the code block, or void if nothing is returned.
Lambda Expressions allows us to code in functional style so it provides all benefits of functional style as well as we can see Lambda Expressions lets developers
Simply understand the code.
Simplify and shorten their code.
Making it more readable and maintainable.
Remove more verbose class declarations.
ForkJoinPool commonPool = ForkJoinPool.commonPool();
System.out.println(commonPool.getParallelism());
This value can be decreased or increased by setting the following JVM parameter:
-Djava.util.concurrent.ForkJoinPool.common.parallelism=5
Keep in mind that sorted does only create a sorted view of the stream without manipulating the ordering of the backed collection. The ordering of stringCollection is untouched: