Java 8 Flashcards
Behavior parameterization
Behavior parameterization is a useful pattern to easily adapt to changing requirements and saves on engineering efforts in the future
This is the ability for a method to take multiple different behaviors as parameters and use them internally to accomplish different behaviors.
Behavior parameterization steps
- Model your selection criteria (predicate):
public interface ApplePredicate{boolean test (Apple apple); }} - Now declare multiple implementations of ApplePredicate to represent different selection criteria
This is related to the strategy design pattern
Strategy pattern
strategy design pattern lets you define a family of algorithms, encapsulate each algorithm (called a strategy), and select an algorithm at run-time.
Verbose language
the programmer must write a lot of code to do minimal job
Boilerplate code
boilerplate refers to sections of code that have to be included in many places with little or no alteration.
Examples of methods that can be parameterized with different behaviors in Java API
The Java API contains many methods that can be parameterized with different behaviors, which
include sorting, threads, and GUI handling.
Lambda expression
A lambda expression can be understood as a concise representation of an anonymous function that can be passed around: - Anonymous— it doesn’t have an explicit name like a method would normally have: less to write and think about! - Function— lambda isn’t associated with a particular class like a method is.But like a method, a lambda has a list of parameters, a body, a return type, and a possible list of exceptions that can be thrown. - Passed around— A lambda expression can be passed as argument to a method or stored in a variable. - Concise— You don’t need to write a lot of boilerplate like you do for anonymous classes
Why lambda expresions
code will be clearer and more flexible.
- you no longer have to write clumsy code using anonymous classes to benefit from behavior parameterization!
-Lambda expressions let you provide the implementation of the abstract method of a functional interface directly inline and treat the whole expression as an instance of a functional interface (more technically speaking, an instance of a concrete implementation of the functional interface).
You can achieve the same thing with an anonymous inner class, although it’s clumsier
Where can you use lambdas
You can use a lambda expression in the context of a
functional interface.
filter(inventory, (Apple a) -> “green”.equals(a.getColor()));
In the code shown here, you can pass a lambda as second argument to the method filter because it expects a Predicate, which is a functional interface
Functional interface. Examples from Java Api
= an interface that specifies exactly one abstract method.
Examples: Comparator, Runnable, ActionListener, Callable
@FunctionalInterface - used to indicate that the interface is intended to be a functional interface.
Why we need functional interfaces?
Functional interfaces are useful because the signature of the abstract method can describe the
signature of a lambda expression.
Function descriptor
The signature of the abstract method of the functional interface essentially describes the
signature of the lambda expression. We call this abstract method a function descriptor
Lambdas in practice
+ behavior parameterization
+ execute around pattern -the setup and cleanup phases are always similar and surround the important code doing the processing. This is called the execute around pattern,
New functional interfaces in Java 8
Most popular:
- Predicate - need to represent a boolean expression that uses an item
- Consumer - when perform some operations on a item
- Function - when maping information from an input object to an output
Predicate T -> boolean Consumer T -> void Function T -> R Supplier () -> T UnaryOperator T -> T BinaryOperator (T, T) -> T Bi(Predicate/Consumer/Function)
Boxing, Unboxing, Autoboxing
Performance cost
in Java there’s a mechanism to convert a primitive type into a corresponding reference type. This mechanism is called boxing.
The opposite approach (that is, converting a reference type into a corresponding primitive type) is called unboxing.
Java also has an autoboxing mechanism to facilitate the task for programmers: boxing and unboxing operations are done automatically.
But this comes with a performance cost. Boxed values are essentially a wrapper around primitive types and are stored on the heap. Therefore, boxed values use more memory and require additional memory lookups to fetch the wrapped primitive value.