- Conheça a interface funcional
Primeiro, apresente a interface funcional. Uma interface funcional é uma interface que tem apenas um método abstrato (pode haver vários métodos não abstratos). Interfaces funcionais comuns incluem Runnable, Comparable, etc.
@FunctionalInterface
public interface Runnable {
void run();
}
public interface Comparable<T> {
int compareTo(T var1);
}
Após jdk1.8, interfaces funcionais comuns (Função, Consumidor, Predicado, Fornecedor, BiFunction, IntBinaryOperator) e suas interfaces funcionais derivadas no pacote java.util.function foram adicionadas.
public interface Consumer<T> {
void accept(T var1);
}
public interface Function<T, R> {
R apply(T var1);
}
public interface Predicate<T> {
boolean test(T var1);
}
public interface Supplier<T> {
T get();
}
public interface BiFunction<T, U, R> {
R apply(T var1, U var2);
}
public interface IntBinaryOperator {
int applyAsInt(int var1, int var2);
}
Todas as interfaces funcionais acima usam genéricos, a diferença está na assinatura do método. Portanto, este artigo usa apenas as duas primeiras interfaces funcionais como exemplos. Os outros princípios são semelhantes. Primeiro, use a Função como exemplo:
public class FunctionClient {
String clientPrint() {
return "this is functionClient test";
}
public static void main(String[] args) {
FunctionInterface functionInterface = new FunctionInterface();
//第一种写法
System.out.println(functionInterface.functionTest(FunctionClient::clientPrint));
//第二种写法
System.out.println((String) functionInterface.functionTest(functionClient -> functionClient.clientPrint()));
}
}
class FunctionInterface {
FunctionClient functionClient = new FunctionClient();
<R> R functionTest(Function<FunctionClient, R> function) {
return function.apply(functionClient);
}
}
A interface funcional usada aqui é Function, que corresponde ao método apply. O FunctionTest na classe FunctionalInterface é usado para simular a interface que os desenvolvedores de SDK fornecem aos desenvolvedores de software. O parâmetro de entrada desta interface é Function e o parâmetro de saída é R :
<R> R functionTest(Function<FunctionClient, R> function) {
return function.apply(functionClient);
}
Quando o objeto de função chama o método apply, ele realmente executa o código atrás da seta, que é functionClient.clientPrint (). O parâmetro de entrada de functionTest é a expressão "functionClient -> functionClient.clientPrint ())". O tipo executado no lado direito da seta é o tipo de valor de retorno da interface funcional. Como functionClient.clientPrint () retorna String, então aqui está R Também se refere especificamente ao tipo String.
Além do objeto FunctionClient especificado acima, é possível usar tipos comuns em vez da classe FunctionClient no lado esquerdo da seta?
public class FunctionClient {
String clientPrint() {
return "this is functionClient test";
}
public static void main(String[] args) {
FunctionInterface functionInterface = new FunctionInterface();
Function<String, String> function = "This is left param." -> new FunctionClient().clientPrint();//报错行
System.out.println(functionInterface.functionTest(function));
}
}
class FunctionInterface {
<R> R functionTest(Function<String, R> function) {
return function.apply("This is FunctionalInterface");
}
}
O código acima não será compilado porque Function não pode aceitar o tipo String e outras constantes. Como o lado esquerdo da seta representa o parâmetro de entrada de um método, o parâmetro de entrada só pode ser uma variável para o método, portanto, um erro será relatado se for definido diretamente como uma constante.
Então, como representar uma cena sem parâmetros? Basta definir uma variável não declarada no lado esquerdo da seta:
Function<String, String> function = s -> new FunctionClient().clientPrint();
Para a atribuição de uma interface funcional, o lado esquerdo da seta só precisa passar o número correspondente de nomes de variáveis não atribuídas.Se não houver parâmetro de entrada, basta usar ().
Se houver apenas um valor de retorno e nenhum parâmetro, você pode usar a interface do Fornecedor:
public class FunctionClient {
String clientPrint() {
return "this is functionClient test";
}
public static void main(String[] args) {
FunctionInterface functionInterface = new FunctionInterface();
Supplier<String> function = () -> new FunctionClient().clientPrint();
System.out.println(functionInterface.functionTest(function));
}
}
class FunctionInterface {
<R> R functionTest(Supplier<R> function) {
return function.get();
}
}
- Quais são as vantagens da programação funcional?
Simplifique o código, como:
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("Runnable");
}
};
//第一次简化,函数式编程(语句lambda形式)
Runnable runnable2 = () -> {
System.out.println("Runnable");
};
//第二次简化,函数式编程(表达式lambda形式)
Runnable runnable3 = () -> System.out.println("Runnable");
又比如:
Consumer<Integer> consumer = i -> System.out.println(i);
List<Integer> arrayList = new ArrayList<>(){
{
add(1);
add(2);
add(4);
}
};
arrayList.forEach(consumer);
- A relação entre lambda, programação funcional e callbacks
1. Lambda é uma implementação de uma interface funcional, que pode ser entendida como açúcar sintático.
2. O retorno de chamada não tem limite no número de métodos na interface, mas as interfaces funcionais podem especificar apenas um método abstrato.
3. As definições de método de programação funcional e retorno de chamada estão no chamador e as entradas de ambos são interfaces, mas uma delas é uma interface normal e a outra é uma interface funcional.
4. Os métodos de programação funcional e callback são executados no receptor, o primeiro executa o único método correspondente, como o apply, enquanto o segundo pode corresponder a vários métodos, basta executar o método correspondente.
5. Ambos podem usar lambda para definir a implementação do método no chamador.
6. A implementação da programação funcional é um retorno de chamada especial.