DEV Community

As expressões lambda em ação

Alguns exemplos simples que colocam em prática os conceitos básicos das expressões lambda:

Exemplo 1 - Comparação de implementação sem e com lambda

Sem utilização de lambda:

interface MyValueSemLambda1 {
double getValue(); // Método abstrato
}
class MyValueImpl implements MyValueSemLambda1{
private double value;
// Construtor para inicializar o atributo value
public MyValueImpl(double value) {
this.value = value;
}
// Implementação do método getValue
@Override
public double getValue() {
return this.value;
}
}
public class MyValueSemLambda {
public static void main(String[] args) {
MyValueSemLambda1 myVal = new MyValueImpl(98.6); // Atribuindo valor ao atributo
System.out.println("Value: " + myVal.getValue()); // Imprime 98.6
}
}

Com utilização de lambda:

interface MyValueCompara {
double getValue();
}
public class MyValueComparacao {
public static void main(String[] args) {
// Expressão lambda sem atributo, mas retornando um valor
MyValueCompara myVal = () -> 98.6;
System.out.println("Value: " + myVal.getValue()); // Imprime 98.6
}
}

Exemplo 2 - LambdaDemo

// Uma interface funcional.
interface MyValue {
double getValue();
}
// Outra interface funcional.
interface MyParamValue {
double getValue(double v);
}
class LambdaDemo {
public static void main(String args[])
{
MyValue myVal; // declara uma referência de interface
// Aqui, a expressão lambda é simplesmente uma expressão de constante.
// Quando ela é atribuída a myVal, é construída a instância
// de uma classe em que a expressão lambda implementa o
// método getValue() de MyValue.
myVal = () -> 98.6; Uma expressão lambda simples
// Chama getValue(), que é fornecido pela
// expressão lambda atribuída anteriormente.
System.out.println("A constant value: " + myVal.getValue());
// Agora, cria uma expressão lambda parametrizada e a atribui
// a uma referência de MyParamValue. Essa expressão lambda retorna
// o recíproco de seu argumento.
MyParamValue myPval = (n) -> 1.0 / n; Uma expressão lambda
que tem um parâmetro
// Chama getValue() por intermédio da referência de myPval.
System.out.println("Reciprocal of 4 is " + myPval.getValue(4.0));
System.out.println("Reciprocal of 8 is " + myPval.getValue(8.0));
// Uma expressão lambda deve ser compatível com o método definido
// pela interface funcional. Logo, essas instruções não funcionarão:
// myVal = () -> "three"; // Erro! String não é compatível com double!
// myPval = () -> Math.random(); // Erro! O parâmetro é necessário!
}
}

Saída:
A constant value: 98.6
Reciprocal of 4 is 0.25
Reciprocal of 8 is 0.125

  • A expressão lambda deve ser compatível com o método abstrato que implementa.

Exemplo de incompatibilidades:

  • Um valor String não pode ser usado se o tipo de retorno esperado for double.

  • Um método que requer um parâmetro não pode ser usado sem fornecê-lo.

  • Uma interface funcional pode ser usada com qualquer expressão lambda compatível.

Exemplo 3 - NumericTest

Teste de Divisibilidade: Verifica se o primeiro número é divisível pelo segundo.
Comparação de Tamanho: Determina se o primeiro número é menor que o segundo.
Comparação de Valores Absolutos: Retorna true se os valores absolutos dos dois números forem iguais.

  • Em main( ), três testes diferentes são criados com o uso de expressões lambda.

// Interface funcional que usa dois parâmetros int e
// retorna um resultado boolean.
interface NumericTest {
boolean test(int n, int m);
}
class LambdaDemo2 {
public static void main(String args[])
{
// Esta expressão lambda determina se um número
// é fator de outro.
NumericTest isFactor = (n, d) -> (n % d) == 0;
if(isFactor.test(10, 2))
System.out.println("2 is a factor of 10");
if(!isFactor.test(10, 3))
System.out.println("3 is not a factor of 10");
System.out.println();
// Esta expressão lambda retorna true se o
// primeiro argumento for menor do que o segundo.
NumericTest lessThan = (n, m) -> (n < m);
if(lessThan.test(2, 10))
System.out.println("2 is less than 10");
if(!lessThan.test(10, 2))
System.out.println("10 is not less than 2");
System.out.println();
// Esta expressão lambda retorna true se os
// valores absolutos dos argumentos forem iguais.
NumericTest absEqual = (n, m) -> (n < 0 ? -n : n) == (m < 0 ? -m : m);
if(absEqual.test(4, -4))
System.out.println("Absolute values of 4 and -4 are equal.");
if(!lessThan.test(4, -5))
System.out.println("Absolute values of 4 and -5 are not equal.");
System.out.println();
}
}

Saída:
2 is a factor of 10
3 is not a factor of 10
2 is less than 10
10 is not less than 2
Absolute values of 4 and -4 are equal.
Absolute values of 4 and -5 are not equal.

  • Expressões lambda compatíveis podem ser usadas com a mesma interface funcional.

  • A mesma variável de referência pode ser reutilizada para diferentes expressões lambda.

  • Reutilizar variáveis facilita a leitura e economiza recursos no código.

  • No exemplo a mesma interface é usada para diferentes implementações:

NumericTest myTest;
myTest = (n, d) -> (n % d) == 0; //implementação 1
if(myTest.test(10, 2))
System.out.println("2 is a factor of 10");
// ...
myTest = (n, m) -> (n < m); //implementação 2
if(myTest.test(2, 10))
System.out.println("2 is less than 10");
//...
myTest = (n, m) -> (n < 0 ? -n : n) == (m < 0 ? -m : m); //implementação 3
if(myTest.test(4, -4))
System.out.println("Absolute values of 4 and -4 are equal.");
// ...

Clareza com variáveis de referência

Usar variáveis de referência diferentes (ex.: isFactor, lessThan, absEqual) ajuda a identificar claramente qual expressão lambda cada variável representa.

Especificação de múltiplos parâmetros

Parâmetros múltiplos em expressões lambda são separados por vírgulas em uma lista entre parênteses no lado esquerdo do operador lambda.
Exemplo: (n, d) -> (n % d) == 0.

Uso de diferentes tipos em expressões lambda

Não há restrição quanto ao tipo dos parâmetros ou do retorno em métodos abstratos de interfaces funcionais.
Tipos de dados não primitivos, como String, podem ser usados em expressões lambda.

Exemplo de teste com strings

Uma interface funcional pode ser usada para testar condições específicas relacionadas a strings, como verificar se uma string está contida em outra.

// Uma interface funcional que testa dois strings.
interface StringTest {
boolean test(String aStr, String bStr);
}
class LambdaDemo3 {
public static void main(String args[])
{
// Esta expressão lambda determina se um string faz
// parte de outro.
StringTest isIn = (a, b) -> a.indexOf(b) != -1;
String str = "This is a test";
System.out.println("Testing string: " + str);
if(isIn.test(str, "is a"))
System.out.println("'is a' found.");
else
System.out.println("'is a' not found.");
if(isIn.test(str, "xyz"))
System.out.println("'xyz' Found");
else
System.out.println("'xyz' not found");
}
}

Saída:
Testing string: This is a test
'is a' found.
'xyz' not found

Interface funcional StringTest

Define um método abstrato test(String aStr, String bStr) que retorna um valor boolean.

Implementação com expressão lambda

A expressão lambda (a, b) -> a.indexOf(b) != -1 verifica se uma string (b) está contida em outra (a).

Inferência de tipos em parâmetros

Os parâmetros a e b são inferidos como do tipo String, permitindo o uso de métodos da classe String, como indexOf.

O programa testa a string "This is a test" para verificar se contém os substrings "is a" e "xyz", imprimindo os resultados conforme o caso.

Top comments (0)