Thursday, January 1, 2015


JAVA SE 8 for The Really Impatient 
Chapter 1

1- The principal enhancement in Java 8 is the addition of functional programming constructs to its object-oriented roots

Why Lambda:
Before, you had to define a class to pass a code, for example a run() method inside Runnable interface implementation to be used later for threading,

class Worker implements Runnable {
 public void run() {
   for (int i = 0; i < 1000; i++)

Another example is compare() method inside Comparator interface implementation to sort elements, or you may define an anonymous class with a method to be used later. So you need to define a class in order to use a method. You couldn’t just pass code blocks around.

Java is an object-oriented language, so you had to construct an object belonging to a class that has a method with the desired code

A “lambda expression” is a block of code that you can pass around so it can be executed later.

The Syntax of Lambda Expression

(Parameters) -> {body}

 (String first, String second) -> {
   if (first.length() < second.length()) return -1;
   else return 0;

even if you dont have parameters you should use (), example
() -> { for (int i = 0; i < 1000; i++) doWork(); }

in case the parameters types are known to the compiler you can ignore them, example:
(first, second) -> {...}

in case you have one parameter and the type is known for the compiler you can omit the brackets
first -> {....}

the parameters can have annotations or modifiers, example
(final String first, @NonNull String name) -> {....}

Functional Interface
1- any interface that has only one abstract method is a functional interface.
example: Runnable or Comparator

2- you can annotate a functional Interface with @FunctionalInterface

3- Lambda expression are used instead of functional interfaces.
for example: Arrays.sort(words, ...) the second parameter should be a Comparator, which is an interface with single abstract method (Functional Interface), this means you can use Lambda.
Arrays.sort(words, (first, second) ->, second.length())).

in the background, each call to the abstract method that exists in the Comparator will be replaced by a call to the lambda expression

4- Not like other functional languages, you cannot assign Lambda expression to objects, for example you cannot write String x = () -> { return "asdf";}

5- Lambda expression can be assigned only to Functional Interfaces. for example:
Comparator x = (String first, String second) -> {....}

6- java.util.function has some predefined functional interfaces that can be used, example is BiFunction.
BiFunction comp = (first, second) ->, second.length()); 

7- In case lambda expression throws an exception, the abstract method that lambda represents should throws this exception, otherwise a compilation error will happen. example
Runnable sleeper = () -> { System.out.println("Zzz"); Thread.sleep(1000); };

Thread.sleep() throws exception, however run() function in Runnable Interface (which is represented now by this lambda expression) doesnt throw exception ==> compiler error; to fix the issue handle the exception inside Lambda.

Method References
button.setOnAction(event -> System.out.println(event));
it can be written as

this is what is called method reference, you have different style of this
1- object::instanceMethod
2- Class::staticMethod
3- Class::instanceMethod

in case of 1 and 2,  Math::pow for example, means  (x, y) -> Math.pow(x, y).
however in 3, String::compareToIgnoreCase for example, means  (x, y) -> x.compareToIgnoreCase(y)

Constructor References
Same as Method reference but it is used to create new objects:
Stream<Button> stream =;

Variable Scope
consider Lambda as function so variables have the same behaviour, however we have this

public static void repeatMessage(String text, int count) {
     Runnable r = () -> { for (int i = 0; i < count; i++)
                                        { System.out.println(text); Thread.yield(); }
     new Thread(r).start();

as you can see that count and text variables are defined out of Lambda scope, you can still use them but they will be treated as Finals, which means you cannot change their values.
This behaviour was same in inner classes you can read the value of final variables.


public static void repeatMessage(String text, int count) {
 Runnable r = () -> {
 while (count > 0) {
 count--; // Error: Can’t mutate captured variable
 new Thread(r).start();

Default Methods
you can now define default methods in Interfaces, by that you can change the interface without changing all implemented classes to add the new method:

interface Person {
 long getId();
 default String getName() { return "John Q. Public"; }

- in case you are implementing 2 interfaces which have the same default method, the compiler will ask you to solve the conflict,

interface Named {
 default String getName() { return getClass().getName() + "_" + hashCode(); }

class Student implements Person, Named {
 public String getName() { return Person.super.getName(); }

Static Methods in Interfaces
you can add a static methods to interface now:

public interface Path {
 public static Path get(String first, String... more) {
 return FileSystems.getDefault().getPath(first, more);

JAVA SE 8 for The Really Impatient 
Chapter 2

1- From Iteration to Stream Operations
we used to use for statement to loop over a list,
List words = Arrays.asList(contents.split("[\\P{L}]+"));
int count = 0;
for (String w : words) {
 if (w.length() > 12) count++;

with stream you can do the same behavior like this
long count = -> w.length() > 12).count();

and if you want to do the process on parallel you use parallelStream()
long count = words.parallelStream().filter(w -> w.length() > 12).count();

very important to know:
1- A stream is not a data structure that stores elements; instead, it conveys elements from a source such as a data structure, an array, a generator function, or an I/O channel, through a pipeline of computational operations. (i.e. stream has no storage).
2- An operation on a stream produces a result, but does not modify its source. For example, filtering a Stream obtained from a collection produces a new Stream without the filtered elements, rather than removing elements from the source collection. (i.e. Stream operations don’t mutate their source)
3- Stream operations are lazy when possible. This means they are not executed until their result is needed. For example, if you only ask for the first five long words instead of counting them all, then the filter method will stop filtering after the fifth match.

2- Stream Creation
1- you can get a stream from collection using stream()
List words ...
long count = -> w.length() > 12).count();

2- you can create a stream from array using Stream.of or
int[] arr = {1, 2};
Stream<int[]> arr1 = Stream.of(arr);
IntStream stream2 =; 

3- you can create empty stream by Stream.empty()
Stream silence = Stream.empty();

4- you can create an infinite stream using the generate method:
Stream<String> echos = Stream.generate(() -> "Echo");
Whenever a stream value is needed, that function is called to produce a value
the previous stream has constant values.
another example
Stream<Double> randoms = Stream.generate(Math::random);

which is a stream of random numbers.

5- you can create  infinite sequences such as 0 1 2 3 ..., by using the iterate method
Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));
The first element in the sequence is the seed BigInteger.ZERO. The second element is f(seed),

3- The filter and map Methods
1- use filter to filter like this
List<String> wordList = ...;
Stream<String> words =;
Stream<String> longWords = words.filter(w -> w.length() > 12);

2- use map if you want to do something on the stream, for example
Stream lowercaseWords =;
convert all words to lower case.

4- Extracting Substreams and Combining Streams
1- limit()  to limit the stream, 
Stream<Double> randoms = Stream.generate(Math::random).limit(100);
this will limit the infinite stream to the first 100 

2- skip(), opposite of limit, the example below will return everything but the first 3 elements 
Stream<String> words = Stream.of(contents.split("[\\P{L}]+")).skip(3);

3- concatenate two streams with the static concat method of the Stream class
Stream<Character> combined = Stream.concat(
 characterStream("Hello"), characterStream("World"));

5- some other stream functions
Stream<String> uniqueWords  = Stream.of("merrily", "merrily", "merrily", "gently").distinct();

 // Only one "merrily" is retained

Stream<String> longestFirst =  words.sorted(Comparator.comparing(String::length).reversed());

Optional<String> largest = words.max(String::compareToIgnoreCase);
Optional<String> startsWithQ  = words.filter(s -> s.startsWith("Q")).findFirst();
Optional<String> startsWithQ = words.parallel().filter(s -> s.startsWith("Q")).findAny();

6- The Optional Type
An Optional object is either a wrapper for an object of type T or for no object. (it should be safer than null if it is used correctly)

you should know that Optional object throws exception if it is not used correctly, examples
Optional<T> optionalValue = ...;


The get method gets the wrapped element if it exists, or throws a NoSuchElementException if it doesn’t, so the code above is similar to
T value = ...;

you can write:
if (optionalValue.isPresent())

but this is similar to
if (value != null)

The key to using Optional effectively is to use a method that either consumes the correct value or produces an alternative

optionalValue.ifPresent(v -> Process v);
String result = optionalString.orElse(""); // The wrapped string, or "" if none
String result = optionalString.orElseGet(() -> System.getProperty("user.dir")); // The function is only called when needed
String result = optionalString.orElseThrow(NoSuchElementException::new); // Supply a method that yields an exception object

7- Creating Optional Values
public static Optional inverse(Double x) 
{ return x == 0 ? Optional.empty() : Optional.of(1 / x); }

8- Collecting Results
When you are done with a stream, you often just want to look at the results instead of reducing them to a value, You can call the iterator method, which yields an old-fashioned iterator that you can use to visit the elements. Or you can call toArray and get an array of the stream elements
String[] result = words.toArray(String[]::new);

you can also use the collect function with the Collector interface.
List<String> result = stream.collect(Collectors.toList());
Set<String> result = stream.collect(Collectors.toSet());

TreeSet<String> result = stream.collect(Collectors.toCollection(TreeSet::new));
Map<Integer, String> idToName = people.collect(Collectors.toMap(Person::getId, Person::getName));
Map<String, List<Locale>> countryToLocales = locales.collect(Collectors.groupingBy(Locale::getCountry));

and many other functions.

9- Primitive Type Streams

we have  IntStream, LongStream, and DoubleStream
IntStream stream = IntStream.of(1, 1, 2, 3, 5);

10- Parallel Streams

By default the streams are sequential, to make them parallel, use parallel() 
Stream parallelWords = Stream.of(wordArray).parallel();

JAVA SE 8: Chapter 3 & 4 & 5 Programming with Lambdas, JavaFX, The New Date and Time API

 in this chapter we talk about the usage scenarios of Lambdas:

1- Deferred Execution
lets take this example,

String test = this.something + "asdf" + "hi";
public void test(String test) {
 if (isConnected) {

as you can see test string is gonna be computed even though it might not be printed.

Lambdas can be used here to postpone the computation until we are sure that the value is gonna be printed.

info(logger, () -> "x: " + x + ", y: " + y)
public static void info(Logger logger, Supplier<String> message) {
 if (logger.isLoggable(Level.INFO));

2- popular functional interfaces

3 Returning Functions
you can have functions that returns lambdas

public static UnaryOperator<Color> brighten(double factor) {
 return c -> c.deriveColor(0, 1, factor, 1);

4- JavaFX:
this is the new swing version, it was started as a competitor to Flash, javaFX started in 2007, but the new version in java8 is more easy to use.

5-New Date and Time API
also java 8 introduced a new data time API

Chapter 6 Concurrency Enhancement

in java 5 the java.util.concurrent.atomic has been introduced, it has some atomic operations for incrementing a counter for example. Java 8 added some new fucntionality with lambda enabled version.

ConcurrentHashMap also has been improved with new funcitons, also they have introduced bulk operations on concurrent hash map that can safely execute even while other threads operate on the map. The bulk operations traverse the map and operate on the elements they find as they go along. No effort is made to freeze a snapshot of the map in time

Java also improved the Future<T> interface, The java.util.concurrent library provides a Future<T> interface to denote a value of type T that will be available at some point in the future.

Chapter 7 The Nashorn JavaScript Engine

For many years, Java bundled the Rhino JavaScript interpreter, an open source JavaScript interpreter written in Java, Oracle’s engineers realized that they could build a much more efficient JavaScript interpreter using the new JVM instructions designed for dynamic languages Thus, the Nashorn project was born

Chapter 8 Miscellaneous Goodies

Also java 8 introduced new functions for String, Number class, new Math funcitons, collections, working with files

Chapter 9: Java 7 Features That You May Have Missed

the most important thing in Java 7 was Use the try-with-resources statement with any object that implements AutoCloseable.

you can catch exception like this, catch (FileNotFoundException | UnknownHostException ex) with an or operator

NIO2 was improved alot to handle files

No comments:

Post a Comment