Introduction to the
Java 8 introduces lambda expressions, which essentially represent an anonymous function.
Prior to Java 8, using anonymous functions required a new class implementation, but with lambda expressions, everything became very brief.
Let’s look at an example from the thread pool earlier:
//ExecutorService using class
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable() {
@Override
public void run(a) {
log.info("new runnable"); }});Copy the code
Executorservice.submit takes a Runnable class, and in the example above we created a new Runnable class and implemented its run () method.
The above example, if rewritten as a lambda expression, would look like this:
//ExecutorService using lambda
executorService.submit(()->log.info("new runnable"));
Copy the code
As simple as it seems, lambda expressions can be used to omit anonymous class constructs and make them more readable.
So can all anonymous classes be refactored using lambda expressions? Also is not.
Let’s look at the features of the Runnable class:
@FunctionalInterface
public interface Runnable
Copy the code
The Runnable class has an @functionalInterface annotation on it. This annotation is the Functional Interface that we will talk about today.
Functional Interface
FunctionalInterface is an Interface annotated with @functionalInterface. It is characterized by an abstract method that only one subclass must implement. If the abstract method is preceded by the default keyword, it is not evaluated.
This also makes sense because Functional Interface, when rewritten as a lambda expression, does not specify which method to implement, which can be problematic if you have more than one method to implement.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
Copy the code
Functional Interface is usually in the java.util.function package.
Functional Interface can be divided into several types, depending on the parameters and return values of the methods to be implemented.
Function: One return value for one argument
The Function interface defines a method that takes one argument and returns one.
@FunctionalInterface
public interface Function<T.R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);Copy the code
Function is usually used when working with collection classes.
Map<String, Integer> nameMap = new HashMap<>();
Integer value = nameMap.computeIfAbsent("name", s -> s.length());
Copy the code
In the example above we call the map’s computeIfAbsent method, passing in a Function.
The above example could be made even shorter:
Integer value1 = nameMap.computeIfAbsent("name", String::length);
Copy the code
Function does not specify the type of argument and return value. If you need to pass in specific arguments, you can use IntFunction, LongFunction, DoubleFunction:
@FunctionalInterface
public interface IntFunction<R> {
/**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
R apply(int value);
}
Copy the code
ToIntFunction, ToLongFunction, ToDoubleFunction can be used if you need to return specific parameters:
@FunctionalInterface
public interface ToDoubleFunction<T> {
/**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
double applyAsDouble(T value);
}
Copy the code
If you want to specify both parameters and return values, You can use DoubleToIntFunction, DoubleToLongFunction, IntToDoubleFunction, IntToLongFunction, LongToIntFunction, LongToDoubleFunction:
@FunctionalInterface
public interface LongToIntFunction {
/**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
int applyAsInt(long value);
}
Copy the code
BiFunction: Receives two arguments, one return value
BiFunction: BiFunction, ToDoubleBiFunction, ToIntBiFunction, ToLongBiFunction, etc.
@FunctionalInterface
public interface BiFunction<T.U.R> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);
Copy the code
Let’s look at an example of BiFunction:
//BiFunction
Map<String, Integer> salaries = new HashMap<>();
salaries.put("alice".100);
salaries.put("jack".200);
salaries.put("mark".300);
salaries.replaceAll((name, oldValue) ->
name.equals("alice")? oldValue : oldValue +200);
Copy the code
Supplier: Function without parameters
If none of the parameters are needed, Supplier can be used:
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get(a);
}
Copy the code
Consumer: Accepts an argument without returning a value
Consumer takes an argument but does not return any value. Let’s look at the definition of Consumer:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
Copy the code
Take a look at a Consumer application:
//Consumer
nameMap.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));
Copy the code
Predicate: Accepts a parameter and returns a Boolean
Predicate takes a single argument and returns a Boolean:
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
Copy the code
This is great if used for filtering collection classes:
//Predicate
List<String> names = Arrays.asList("A"."B"."C"."D"."E");
List<String> namesWithA = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
Copy the code
Operator: Receives and returns the same type
Operator receives and returns the same type. There are many types of operators: UnaryOperator BinaryOperator, DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator, DoubleBinaryOperator, IntBinaryOperator, LongBinaryOperator, etc.
@FunctionalInterface
public interface IntUnaryOperator {
/**
* Applies this operator to the given operand.
*
* @param operand the operand
* @return the operator result
*/
int applyAsInt(int operand);
Copy the code
Let’s look at an example of a BinaryOperator:
//Operator
List<Integer> values = Arrays.asList(1.2.3.4.5);
int sum = values.stream()
.reduce(0, (i1, i2) -> i1 + i2);
Copy the code
conclusion
Functional Interface is a useful new feature that I want you to get your head around.
Examples of this article: github.com/ddean2009/l…
For more, visit www.flydean.com