functional interfaces & lambda expressions Flashcards
any interface that has exactly one abstract method is called …
a functional interface
abstract method
methods from e.g. an interface that has a signature but not an implementation (the class that implements the interface will define the method with its own implementation - don’t forget annotation @Override)
is List a functional interface?
no - it does not have only one method, it has many methods. A functional interface must have one method.
can a developer create a new functional interface?
yes they can. Java libraries also provide many functional interfaces - they are called “the standard Java functional interfaces”. (we cover four in ATA)
What are the four functional interfaces from Java that are covered in ATA?
Function, Supplier, Consumer, Predicate
To implement an interface the standard way…
- The class header declares which interface it’s implementing
- The class implementation overrides each abstract method
- Create and document entire class
A great deal of effort just to use the single method inside!
(hint: instead, use lambda expressions)
lambda expressions provide…
a quick and easy way to implement a functional interface without expliciitly defining a class or even a formal method declaration.
syntax of a lambda expression
argument -> method implementation or (arg1, arg2) -> method implementation or () -> method implementation or (arg(s)) -> { mulit-line method implementation } Because each functional interface contains exactly one abstract method, lambda expressions allow us to implement only that one method (following the arrow) to satisfy the interface. We don't need to creat a class, and since the interface has only one method, we don't even need to name it!
three parts to lambda expression
- the method argument
- the arrow separator ->
- the method implementation
Function interface
public interface Function { R apply(T t); } takes an input object, returns an output object
why don’t we need to name the method we call in a lambda expression?
the lamda “operator” -> automatically calls the ONE method in the interface, that one method is defined on the right of the -> operator
Supplier interface
public interface Supplier { T get(); } no input, returns an output
Supplier examples
List participants = {"ace", "queen", "diamond"} Random random = new Random(); Supplier randomIndex = () -> random.nextInt(participants.size()); ------ public void callOnParticipant(Supplier index) { String person = participants.get(indexChooser.get()); System.out.println("Hello " + person); }
Supplier interface notes
- Supplier does not take input directly, but may access any variable within its scope
- called with empty parenthesis () -> the get method implementation
- it doesn’t “appear” to have a return but does!
note on keyword ‘return’ in lambda expressions
if you drop the curly braces from your one-line method implementation, and the functional interface that your lambda expression is implementing has a return value, you drop the keyword return. (most common usage of a lambda)
method reference
if your lambda expression simply calls a method, this syntax is a way to “compactify” it:
long form: key -> method(key) or item -> item==null etc
I. Reference to an instance method of a particular object: containingObject::instanceMethodName
e.g.: recommendationsServiceClient::getBookRecs
(from .build(CacheLoader.from(^^)
II. Reference to an instance method of an arbitrary object of a particular type: ContainingType::methodName
e.g.: list.removeIf(String::isEmpty)
III. Reference to a static method:
ContainingClass::staticMethodName
e.g.: list.removeIf(StringUtils::isBlank)
e.g.: PublishingConverter::toPublishRecord
Consumer interface
public interface Consumer {
void accept;
}
when are consumers used?
Consumers are commonly used when:
- performing an operation on each member of a data structure
- updating another data structure by calling Consumer on each element
example of Consumer
List names = fetchNames();
names.forEach(name -> System.out.println(“name: “ + name);
(note: forEach(Consumer action) is a List method)
fancier:
Consumer fancyLambda = myString -> System.out.println(“Hello there “ + myString “, how are you today?”);
names.forEach(fancyLambda);
Predicate interface
public interface Predicate { boolean test(T t); }
what is Predicate used for?
Predicate is often used to filter (in or out) elements from a data structure, or to conditionally perform some operation on elements of a data structure.
A Predicate performs a test on an objects, and specifies whether it meets a certain condition or not.
examples of Predicate
value -> value == null;
list. removeIf(value -> value == null);
(note: removeIf(Predicate filter) is a list method, it removes all elements of the collection that satisfy the given predicate. this method returns true if any element was removed.)
remove all palindromes from a list
List noPalindrome = fetchWords; noPalidrome.removeIf(text -> { String reverse = new StringBuffer(text).reverse.toString(); return text.equals(reverse); });
note:
1. with only one input, don’t need parentheis
2. the Predicate’s test(T t) method is inside the {} since multiple lines
3. the removeIf has regular parentheses () and end with ;
4. needs return since multiline (single line skips explicit return statement, it’s implied)
- ->( t -> { blabla; return boolean} );
If the input “satisfies the predicate” - means the test(input) returns true - the item is removed from the list.
**removeIf is a Collections method, which List inherits, so any collection can do this
can a Predicate have two inputs
no - the signature test(T t) accounts for one input
remove palindromes from list, defined as variable Predicate
Predicate noPalindrone = text -> {
String reverse = new StringBuffer.reverse().toString();
return text.equals(reverse);
};
question: is the ‘;’ correct at end?
Function to open a file for reading data
Function fileOpener = filename -> { File file = new File(filename); try { return new FileInputStream(file); } catch (FileNotFoundException e) { throw new IllegalArgumentException(e.getMessage.. } };
Checked exceptions in lambda expressions
lamda cannot throw checked exceptions (not in the interface signature). What you need to do is use a try/catch block and throw a runtime exception.
e.g.: catch a FileNotFoundException (is a checked exception) and throw new IllegalArgumentException (is a runtime exception)
alternatively: just log it (dangerous): logger.warn(“Can’t open missing file: “ + filename);
return null; //maybe return a default file?
“make sure you plan for handling checked exceptions”