Руководство Java Function
View more Tutorials:


В Java 8, Function - это functional interface, который представляет собой оператор, принимающий входное значение и возвращающий значение.
Исходный код interface Function:
Function interface
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Например:
FunctionEx1.java
package org.o7planning.ex;
import java.util.function.Function;
public class FunctionEx1 {
public static void main(String[] args) {
Function<String, Integer> func = (text) -> text.length();
int length = func.apply("Function interface tutorial");
System.out.println("Length: " + length);
}
}
Output:
Length: 27
Например: Обработка элементов объекта List для создания нового объекта List.
FunctionEx2.java
package org.o7planning.ex;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class FunctionEx2 {
public static void main(String[] args) {
Function<String, String> func = text -> text.toUpperCase();
List<String> list = Arrays.asList("Java", "C#", "Python");
List<String> newList = map(func, list);
newList.forEach(System.out::println);
}
public static <T,R> List<R> map(Function<T,R> mapper, List<T> list) {
List<R> result = new ArrayList<R>();
for(T t: list) {
R r = mapper.apply(t);
result.add(r);
}
return result;
}
}
Output:
JAVA
C#
PYTHON
Например: Использование Function для преобразования объекта List в объект Map:
FunctionEx3.java
package org.o7planning.ex;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class FunctionEx3 {
public static void main(String[] args) {
Function<String, Integer> func = text -> text.length();
List<String> list = Arrays.asList("Java", "C#", "Python");
Map<String, Integer> map = listToMap(func, list);
// @see: Map.forEach(BiConsumer).
map.forEach((t,r) -> System.out.println(t + " : " + r));
}
public static <T,R> Map<T,R> listToMap(Function<T,R> mapper, List<T> list) {
Map<T, R> result = new HashMap<T, R>();
for(T t: list) {
R r = mapper.apply(t);
result.put(t, r);
}
return result;
}
}
Output:
C# : 2
Java : 4
Python : 6
M.ref example 1:
Если статический метод принимает один параметр и возвращает значение, его ссылка может рассматриваться как Function.
Function_mref_ex1.java
package org.o7planning.ex;
import java.util.function.Function;
public class Function_mref_ex1 {
public static void main(String[] args) {
// A method of Math class: public static long round(double)
Function<Double, Long> func1 = Math::round; // Method reference
Function<Double, Long> func2 = value -> Math.round(value);
System.out.println(func1.apply(100.7));
System.out.println(func2.apply(100.7));
}
}
Output:
101
101
M.ref example 2:
Если нестатический метод (non-static method), не принимает параметров и возвращает значение, то его ссылку можно рассматривать как Function.
Function_mref_ex2.java
package org.o7planning.ex;
import java.util.function.Function;
public class Function_mref_ex2 {
public static void main(String[] args) {
// A method of String class: public int length()
Function<String, Integer> func1 = String::length; // Method reference
Function<String, Integer> func2 = text -> text.length();
System.out.println(func1.apply("Java")); // 4
System.out.println(func2.apply("Java")); // 4
}
}
M.ref example 3:
Далее, взгляните на класс CurrencyFormatter ниже:
- Метод CurrencyFormatter.usd(double) имеет параметр типа Double и возвращает String. Таким образом, его ссылку CurrencyFormatter::usd можно рассматривать как Function<Double,String>.
CurrencyFormatter.java
package org.o7planning.tax;
public class CurrencyFormatter {
// Dollar
public static String usd(double amount) {
return "$" + amount;
}
// Euro
public static String euro(double amount) {
return "€" + amount;
}
// Vietnam Dong.
public static String vnd(double amount) {
return amount + "VND";
}
}
TaxCalcExample.java
package org.o7planning.tax;
import java.util.function.Function;
public class TaxCalcExample {
public static void main(String[] args) {
double amount = 1000;
String format = formatCurrency("VN", amount);
System.out.println("VN: " + format);
format = formatCurrency("US", amount);
System.out.println("US: " + format);
format = formatCurrency("EU", amount);
System.out.println("EU: " + format);
}
public static String formatCurrency(String countryCode, double amount) {
if ("VN".equals(countryCode)) {
Function<Double, String> formatter = CurrencyFormatter::vnd; // Method reference
return _formatCurrency(formatter, amount);
}
if ("US".equals(countryCode)) {
return _formatCurrency(CurrencyFormatter::usd, amount);
}
if ("EU".equals(countryCode)) {
return _formatCurrency(CurrencyFormatter::euro, amount);
}
throw new RuntimeException("No formatter for " + countryCode);
}
private static String _formatCurrency(Function<Double, String> formatter, double amount) {
return formatter.apply(amount);
}
}
Output:
VN: 1000.0VND
US: $1000.0
EU: €1000.0
Как вы знаете, constructor используется для создания объекта, это означает, что он возвращает значение. Таким образом, если constructor имеет один параметр, его ссылка будет рассматриваться как Function.
Student.java
package org.o7planning.cr;
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ConstructorReferenceTest.java
package org.o7planning.cr;
import java.util.function.Function;
public class ConstructorReferenceTest {
public static void main(String[] args) {
Function<String, Student> f1 = Student::new; // Constructor Reference
Function<String, Student> f2 = (name) -> new Student(name); // Lambda Expression
System.out.println(f1.apply("Tom").getName());
System.out.println(f2.apply("Jerry").getName());
}
}
Output:
Tom
Jerry
Ниже приведен список методов в package java.util, использующих interface Function:
static <T,U extends Comparable<? super U>> Comparator<T> |
Comparator.comparing(Function<? super T,? extends U> keyExtractor) |
static <T,U> Comparator<T> | Comparator.comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator) |
V | Hashtable.computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) |
V | HashMap.computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) |
default V | Map.computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) |
<U> Optional<U> | Optional.flatMap(Function<? super T,Optional<U>> mapper) |
<U> Optional<U> | Optional.map(Function<? super T,? extends U> mapper) |
default <U extends Comparable<? super U>> Comparator<T> |
Comparator.thenComparing(Function<? super T,? extends U> keyExtractor) |
default <U> Comparator<T> | Comparator.thenComparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator) |
Узнать больше:
Вот определение метода Function.compose:
@FunctionalInterface
public interface Function<T,R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
// Other default methods ..
}
И мы перепишем этот метод более простым для понимания способом:
@FunctionalInterface
public interface Function<T,R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> {
T t = before.apply(v);
R r = this.apply(t);
return r;
};
}
// Other default methods ..
}

Например:
FunctionEx6.java
package org.o7planning.ex;
import java.util.function.Function;
public class FunctionEx6 {
public static void main(String[] args) {
Function<String, Integer> func = content -> content.length();
Function<Article, String> before = article -> article.getContent();
Article article = new Article("Java Tutorial", "Java Tutorial Content...");
int contentLength = func.compose(before).apply(article);
System.out.println("The length of the article content: " + contentLength);
}
}
class Article {
private String title;
private String content;
public Article(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
}
Output:
The length of the article content: 24
Вот определение метода Function.andThen:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
// Other default methods ..
}
И мы перепишем этот метод более простым для понимания способом:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> {
R r = this.apply(t);
V v = after.apply(r);
return v;
};
}
// Other default methods ..
}

Например:
FunctionEx7.java
package org.o7planning.ex;
import java.util.function.Function;
public class FunctionEx7 {
public static void main(String[] args) {
Function<Post, String> func = post -> post.getContent();
Function<String, Integer> after = content -> content.length();
Post post = new Post("Java Tutorial", "Java Tutorial Content...");
int contentLength = func.andThen(after).apply(post);
System.out.println("The length of the post content: " + contentLength);
}
}
class Post {
private String title;
private String content;
public Post(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
}
Output:
The length of the post content: 24
Статический метод Function.identity(): Возвращает функцию, которая всегда возвращает свой входной аргумент.
static <T> Function<T, T> identity() {
return t -> t;
}
Например: Преобразует массив в объект Set, содержащий неповторяющиеся элементы.
FunctionEx8.java
package org.o7planning.ex;
import java.util.Arrays;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FunctionEx8 {
public static void main(String[] args) {
String[] names = new String[] { //
"Peter", "Martin", "John", "Peter", //
"Vijay", "Martin", "Peter", "Arthur" };
Set<String> set = Arrays.asList(names).stream() //
.map(Function.identity()).collect(Collectors.toSet());
set.forEach(System.out::println);
}
}
Output:
Vijay
Arthur
John
Martin
Peter
Приведенный выше пример эквивалентен приведенному ниже примеру:
FunctionEx8a.java
package org.o7planning.ex;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
public class FunctionEx8a {
public static void main(String[] args) {
String[] names = new String[] { //
"Peter", "Martin", "John", "Peter", //
"Vijay", "Martin", "Peter", "Arthur" };
Set<String> set = Arrays.asList(names).stream() //
.map(t -> t).collect(Collectors.toSet());
set.forEach(System.out::println);
}
}