Java 8 has enhanced functionality around functional programming.
--Functional interface --Method reference --Lambda expression --Stream API
Summarize what functional interfaces and method references do
Goal You will be able to read and use this source code.
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha");
strings.stream()
.filter(s -> !s.isEmpty())
.map(s -> s.substring(0, 1).toUpperCase() + s.substring(1))
.forEach(System.out::println);
// Bravo
// Charlie
// Alpha
}
What is a functional interface and what is it for? To understand it, it is necessary to understand the concept of ** first-class function **.
First-class function (first-class function) [1] is the nature of a programming language that can treat a function as a first-class object, or such a function. That is. -[First-class function-Wikipedia](https://ja.wikipedia.org/wiki/%E7%AC%AC%E4%B8%80%E7%B4%9A%E9%96%A2%E6% 95% B0)
First-class citizen?
First-class citizens (first-class objects) are an unlimited number of basic operations in a programming language, such as creation, assignment, arithmetic, and passing (as arguments / return values). It is an object that can be used. -[First Class Citizen--Wikipedia](https://ja.wikipedia.org/wiki/%E7%AC%AC%E4%B8%80%E7%B4%9A%E3%82%AA%E3% 83% 96% E3% 82% B8% E3% 82% A7% E3% 82% AF% E3% 83% 88)
I see
Java functions (methods) cannot be assigned to variables or used for return values / arguments. Java is a language that does not meet the properties of first-class functions.
First-class functions are essential for functional languages and are routinely used in the form of higher-order functions. -[First-class function-Wikipedia](https://ja.wikipedia.org/wiki/%E7%AC%AC%E4%B8%80%E7%B4%9A%E9%96%A2%E6% 95% B0)
** Behavior can be manipulated by functions from the outside. ** ** e.g. sort rules
List<String> strings = Arrays.asList("bravo", "charlie", "alpha");
Collections.sort(strings);
System.out.println(strings); // -> [alpha, bravo, charlie]
Collections.sort(strings, Comparator.reverseOrder());
System.out.println(strings); // -> [charlie, bravo, alpha]
Benri.
Isn't it the current code Java?
A design pattern conceived because a function is not available as a first-class citizen.
In Java, the Strategy pattern can be implemented using polymorphism with method overrides in classes. --Strategy pattern --Wikipedia
I will omit the details, but it looks like this.
public static <T> void sort(List<T> list, Comparator<? super T> c) {
if (c.compare(a, b) < 0) {
//a is smaller
}else {
//b is smaller
}
}
The sorting rule is determined according to the implementation class of the Comparator interface received as an argument. The practice that the method itself is not passed via an argument, but the method processing can be passed from the outside through the interface.
The actual sort process looks like this jdk/TimSort.java at master · openjdk/jdk
This design pattern does not need to be particularly noticeable in languages where functions are first-class citizens.
This pattern is implicitly used in languages where the function is a first-class citizen. --Strategy pattern --Wikipedia
Java can handle functions (methods) like first-class citizens by using interfaces.
From java8, the interface used to treat a function (method) as a first-class object, like the Comparator mentioned earlier, is called a ** functional interface **. Since the purpose is to treat functions (methods) as first-class citizens, there is only one abstract method for functional interfaces.
Some of the interfaces that have been provided in the past, such as Comparator and Runnable, have just been given new names. The function is the same as a normal interface. Annotation ** @ FunctionalInterface ** is now added to functional interfaces. e.g. java.lang.Runnable
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface {@code Runnable} is used
* to create a thread, starting the thread causes the object's
* {@code run} method to be called in that separately executing
* thread.
* <p>
* The general contract of the method {@code run} is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
jdk/FunctionalInterface.java at master · openjdk/jdk
@FunctionalInterface Annotations added for functional interfaces. Nothing happens at runtime (functional interfaces are functionally normal interfaces, so there is no special processing). At compile time, it checks if it meets the properties of a functional interface.
In other words, it is not absolutely necessary when using the functions of the functional interface. However, since it can be clearly stated that it is a functional interface rather than a normal interface, it seems that it should be added when creating a functional interface by yourself.
When handling a function (method) using a functional interface, the method to be handled is affected by the Java type system. Specifically, when dealing with different methods below, different functional interfaces must be used.
--Return type --Argument type --Number of arguments
java8 provides a standard functional interface that abstracts and makes available the presence / absence of return values and the types of arguments. Basically, this interface is sufficient, and it is said that you should consider using this interface. (Except for customary ones such as Runnable)
** Typical standard functional interface **
Interface name | Abstract method name | Example |
---|---|---|
Function<T,R> | R apply(T t) | Arrays::asList |
Predicate |
boolean test(T t) | Collections::isEmpty |
Consumer<T> | void accept(T t) | System.out::println |
Supplier<T> | T get() | Instant::now |
UnaryOperator<T> | T apply(T t) | String::toLowerCase |
BinaryOperator<T> | T apply(T t1, T t2) | BigInteger::add |
java.util.function (Java Platform SE 8 )
Let's create a process to process and output a character string. When calling the output process, the character string after the processing process is output by passing the processing process function together. Try to build a program that outputs after converting all to uppercase.
Output after executing the passed function.
The functional interface assumes a function that receives one string before change (String) and returns the string after change (String), and uses ʻUnaryOperator
static void print(String word, UnaryOperator<String> operator) {
String newWord = operator.apply(word);
System.out.println(newWord);
}
A function that converts to uppercase.
ʻImplement UnaryOperator
import java.util.function.UnaryOperator;
public class MyUpperOperator implements UnaryOperator<String> {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}
main If you pass the capitalization function created earlier and the character string to the print method, all capital letters will be output.
public static void main(String[] args) {
UnaryOperator<String> upperOperator = new MyUpperOperator();
print("hello world", upperOperator); // -> HELLO WORLD
}
It uses a functional interface, but it's just a Strategy pattern.
In the previous example, in fact, a more powerful writing style is possible.
By using a function called ** method reference **, it is possible to directly pass a method whose arguments and return values match without explicitly implementing a functional interface.
In the case of the previous example, since ʻUnaryOperator , if the method consists of one String and the return value is String, it can be passed directly as a method reference. You can assign the
toUpperCase ()method of the
String class directly to the ʻUnaryOperator <String>
instance.
(In the case of a method reference of an instance method, the receiver object is interpreted as the first argument. See the syntax below.)
When this happens, the calling source code appears to treat the function as a first-class citizen.
public static void main(String[] args) {
// UnaryOperator<String> upperOperator = new MyUpperOperator();
UnaryOperator<String> upperOperator = String::toUpperCase;
print("hello world", upperOperator); // -> HELLO WORLD
}
It seems that it uses the instruction ʻinvoke Dynamic` of the JVM. It seems that the class is dynamically generated and solved at runtime, not at compile time.
Notation of two consecutive semicolons. The content described on both sides of the semicolon can be roughly divided into four patterns depending on the type of method.
Target | grammar | Example |
---|---|---|
Class method | name of the class::Class method name | String::toString |
Instance method | Instance name::Instance method name | System.out::println |
Instance method * | name of the class::Instance method name | String::toUpperCase |
constructor | name of the class::new | String::new |
The previous example can be described very briefly. The MyUpperOperator class is no longer needed.
public static void main(String[] args) {
print("hello world", String::toUpperCase); // -> HELLO WORLD
}
Also, many of the stream APIs added in java8 require a functional interface, so this kind of processing can be done.
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "charlie", "alpha");
strings.stream()
.map(String::toUpperCase)// Function:Convert to uppercase
.forEach(System.out::println);// Consumer:output
// BRAVO
// CHARLIE
// ALPHA
}
It is necessary to declare the method in advance in order to handle it. It's good to use the provided methods, but you have to declare your own processing as a method one by one. I want to treat methods like literals.
An evaluation expression mechanism that can be assigned to a functional interface. You can write a method as an expression without declaring the method.
e.g. Function to add a period to a string
public static void main(String[] args) {
// UnaryOperator<String> upperOperator = String::toUpperCase;
UnaryOperator<String> periodOperator = (String s) -> { return s + "."; };
print("hello world", periodOperator); // -> hello world.
}
This is the basic form
(Formal argument string)-> {Processing body statement}
e.g.
(String s) -> { return s + "."; }
Various descriptions can be omitted only under specific conditions.
I will omit it because I think that various things will come out if I look it up.
e.g. In this case
UnaryOperator<String> periodOperator = s -> s + ".";
public static void main(String[] args) {
print("hello world", s -> s + "."); // -> hello world.
}
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha");
strings.stream()
.filter(s -> !s.isEmpty()) // Predicate:Remove empty string
.map(s -> s.substring(0, 1).toUpperCase() + s.substring(1)) // Function:Convert only the first character to uppercase
.forEach(System.out::println); // Consumer:output
// Bravo
// Charlie
// Alpha
}
An example of the latter is the process mentioned at the beginning of this article.
You will be able to read and use this source code.
Functional programming has been enhanced since java8.
--Functional interface --Method reference --Lambda expression
Revised 2nd Edition Perfect Java: Book Guide | Gijutsu-Hyoronsha Effective Java 3rd Edition-Maruzen Publishing Co., Ltd., a specialized book publisher of science, engineering, medicine, and humanities and social sciences
Recommended Posts