Introdução a Interfaces Funcionais
Tags: java, lambda
Published: 2021-06-07 22:06:35

---
title: Introdução a Interfaces Funcionais
published: true
description: 
tags: java, lambda
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/btfg9r71crwds3eipgnv.jpg
---


O java 8 introduziu várias funcionalidades interessantes, como novas APIs de Stream, Optional, Date and Time e Functional Interfaces.

Este artigo tem o objetivo de fazer uma breve introdução sobre as Interfaces Funcionais e apresentar os tipos mais comuns disponíveis a partir do JDK 8.

Interfaces funcionais permitem trabalharmos com closures no Java. Closure é uma função que conhece o escopo na qual foi criada. Ou seja, a função tem acesso às suas variáveis e às variáveis e parâmetros da função externa que a criou. Com as interfaces funcionais, também é possível passarmos funções por parâmetros ou retorná-las.

Uma Interface Funcional deve obrigatoriamente possuir um e apenas um método abstrato, mas que pode ter outros métodos _default_.

Além disso, recomenda-se anotar a interface com `@FunctionalInterface`. Esta anotação irá ajudar o compilador a sinalizar um erro caso você tente adicionar mais de um método abstrato. Incluir essa anotação é opcional, desde que respeite a regra de ter apenas um método abstrato.

Exemplo:

```java
@FunctionalInterface
public interface Operacao {
    int calcular(int a, int b);
}
```

Para definir uma função a partir de uma interface, usamos expressões lambda. Lambda nada mais é do que uma função anônima, que não possui nome e nem está vinculada como um método de classe. Abaixo algumas diferentes formas de criar uma função usando expressão lambda:

1. **Com as chaves**: quando o corpo da função tiver várias instruções.
```java
Funcao fn = (a, b) -> {
    System.out.println("Realizando a soma..."); // instrução 1
    return a + b; // instrução 2
};
```
2. **Sem as chaves**: quando a função tiver apenas uma instrução. O resultado da instrução `a + b` será retornado na chamada da função.
```java
Funcao fn = (a, b) -> a + b;
```
3. **Sem os parênteses do argumento**: quando há apenas 1 parâmetro na função, podemos omitir os parênteses.
```java
Funcao fn = x -> x * 2;
```

Assim, utilizando o exemplo acima da interface `Operacao`, criamos várias operações matemáticas utilizando lambdas:

```java
Operacao soma = (a, b) -> a + b;
Operacao subtracao = (a, b) -> a - b;
Operacao divisao = (a, b) -> a / b;
Operacao multiplicacao = (a, b) -> a * b;

System.out.println(soma.calcular(1, 2)); // 3
System.out.println(subtracao.calcular(5, 1)); // 4
System.out.println(divisao.calcular(10, 5)); // 2
System.out.println(multiplicacao.calcular(2, 5)); // 10
```

Analisando o exemplo acima, podemos notar que a mesma interface foi utilizada para várias operações matemáticas e o código ficou bem reduzido e mais legível!

Mas se você não quer ficar criando interfaces funcionais no seu projeto, também pode utilizar das já disponiveis no próprio Java. Vamos conhecer algumas?

## `java.util.function.Function<T, R>`

Esta função recebe um parâmetro do tipo T e retorna um valor do tipo R.
```java
@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);
}
```

Exemplo:
```java
Function<Integer, Float> dividePorDois = x -> ((float) x / 2);

System.out.println(dividePorDois.apply(15)); // 7.5
```

## `java.util.function.Consumer<T>`
Esta função recebe um parâmetro do tipo T, mas não retorna nada.

```java
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}
```

Exemplo:
```java
Consumer<String> exibeMensagem = str -> System.out.println(str);
// ou
Consumer<String> exibeMensagem2 = System.out::println;

exibeMensagem.accept("Hello World!"); // Hello World!
exibeMensagem2.accept("Hello World!"); // Hello World!
```
Note que, como o método `println` possui a mesma assinatura de método da interface `Consumer<String>` (recebe uma String e não retorna nada) e há somente uma instrução na função, podemos passar a referência do próprio método `println`. Isso se chama [Method Reference](https://www.baeldung.com/java-method-references).

## `java.util.function.Supplier<T>`
Esta função não recebe parâmetros e retorna um valor do tipo T.

```java
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
```

Exemplo:
```java
Supplier<LocalDate> dataAtual = () -> LocalDate.now();

System.out.println(dataAtual.get()); // 2021-06-02
```

## `java.util.function.Predicate<T>`
Esta função recebe um parâmetro do tipo T e retorna um valor booleano.

```java
@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);
}
```

Exemplo:
```java
Predicate<LocalDate> maiorDeIdade = dataNascimento -> {
    return dataNascimento.until(LocalDate.now(), ChronoUnit.YEARS) >= 18;
};

System.out.println(maiorDeIdade.test(LocalDate.of(1985, 10, 5))); // true
```

As interfaces disponíveis no JDK abordadas neste artigo possuem especializações que permitem receber dois parâmetros (adicionando o prefixo `Bi`) ou trabalhar diretamente com tipos primitivos (adicionando o prefixo `Int`, `Long` ou `Double`). Exemplos: **Bi**Function, **Int**Function, **Long**Function e **Double**Function.

Vimos os quatro principais tipos de interfaces funcionais. Recomendo que você explore as diversas opções que a JDK fornece e aplicá-las sempre que possível nos projetos.

Os exemplos utilizados neste artigo estão no repositório: https://github.com/andrebuarque/functional-interfaces-java.

Até logo!