Java 8: Expressões Lambda, Closures, Interfaces Funcionais e um pouco mais

Expressões lambda são a novidade do momento no ecossistema Java. Uma expressão lambda é um bloco de código que pode ser passado como parâmetro para ser executado mais tarde pelo código. Parece algo bem simples para todo o alvoroço da comunidade Java em torno dessa novidade, mas expressões lambda facilitam muitas coisas e as novidades envolvendo essa implementação na plataforma Java são muito interessantes, inclusive sobre o paradigma funcional envolto a lambdas.

Um dos primeiros aspectos de confusão em relação a lambdas é o paradigma de programação. Muita gente confunde essa novidade com voltar a programar de forma funcional. Isso é um grande equívoco, a programação funcional que vemos florescer não vem para substituir a orientação a objetos, mas vem para facilitar as coisas onde a programação funcional se sai melhor, como em eventos e concorrência. Esses pequenos blocos de código funcional se mesclam a orientação a objetos com o objetivo de simplificar as coisas, tornando o código mais elegante e robusto.

Motivação para uso de lambdas      

Existe uma série de padrões que possibilitam a execução de determinadas ações em um determinado momento no futuro. Considere a ordenação de Strings por tamanho implementada com um Comparator, ilustrada nas linhas de código a seguir:

package com.gabrielamorim;

import java.util.Arrays;
import java.util.Comparator;

public class Java8Test {

	public static void main(String[] args) {

		String[] words = {"ball", "book", "computer", "car", "elephant", "nice"};		

		Arrays.sort(words, new LengthComparator());

		for(String word : words) {
			System.out.println(word);
		}
	}
}

class LengthComparator implements Comparator<String> {

	@Override
	public int compare(String string1, String string2) {
		return Integer.compare(string1.length(), string2.length());
	}	
}

 

A classe LengthComparator é um Comparator que compara duas Strings por tamanho e é passado por parâmetro para o método Arrays.sort junto com um array contendo as Strings para serem ordenadas.

Esse tipo de código é trivial, mas como ficaria a mesma ordenação utilizando lambda? Ficaria assim:

package com.gabrielamorim;

import java.util.Arrays;
import java.util.Comparator;

public class Java8Test {

	public static void main(String[] args) {
		String[] words = {"ball", "book", "computer", "car", "elephant", "nice"};		

		Arrays.sort(words, (first, second) -> Integer.compare(first.length(), second.length()));

		for(String word : words) {
			System.out.println(word);
		}
	}
}

 

Muito mais simples e fácil de entender! Repare que nem é mais preciso da classe LenghtComparator , que existia apenas para comparar Strings por tamanho encapsulando o código responsável pela comparação.

Sintaxe Lambda

(parâmetros) -> { expressão }

 

Uma expressão lambda é um bloco de código junto com a especificação de variáveis que podem ser passadas para a mesma. A expressão lambda do exemplo acima é a que segue:

(String first, String second) -> Integer.compare(first.length(), second.length())

 

Caso a expressão seja composta por mais de uma linha de código, deve ser delimitada por chaves { }. Se a expressão não tiver parâmetros, ainda assim devem-se usar parênteses:

//expressão lambda sem parâmetros
() ->  { expressão }

 

Interfaces Funcionais

Há um novo conceito em Java, o de interface funcional. Uma interface funcional é uma interface com apenas um método abstrato. A interface Comparator é uma interface funcional, existe para encapsular apenas uma função.

Expressões lambda são convertidas em interfaces funcionais durante o tempo de execução e, na verdade, a conversão de uma expressão lambda em uma interface funcional é a única coisa que pode ser feito com expressões lambda em Java.

A expressão lambda deve respeitar o contrato da interface ao qual ela será convertida, deve declarar os mesmos parâmetros que e o tipo de retorno deve ser o mesmo. Se a interface não declarar que lança exceções, a expressão lambda também não pode lançar exceções checadas.

Escopo de variáveis e closures

As regras de escopo de variáveis são as mesmas para lambdas. Além disso, lambdas podem fazer uso de variáveis fora do bloco da expressão lambda. Como uma expressão lambda é um bloco de código a ser executado no futuro, quando ele for executado, as variáveis que ele utiliza podem não estar mais disponíveis. Essas variáveis são na verdade encapsuladas junto à expressão lambda em um objeto para serem utilizadas quando a expressão for executada. Variáveis encapsuladas junto à expressão lambda, conhecidas como free variables, é o conceito de closure.

1 Reply to “Java 8: Expressões Lambda, Closures, Interfaces Funcionais e um pouco mais”

Leave a Reply

Your email address will not be published. Required fields are marked *