Interfaces Funcionais Java - DoubleFunction

Por Gaspar Barancelli Junior em 11 de outubro de 2022

A partir da versão 8 do java foi introduzido o conceito de expressão lambda, que nada mais é que um bloco de código que pode receber parâmetros e também pode retornar um determinado valor.

Expressões lambdas são bem semelhantes a métodos, mas não precisam ter um nome e contém apenas o corpo da implementação.

Mas para que seja possível a utilização de lambdas, o java teve que introduzir o conceito de interfaces funcionais que por definição é uma interface que possui apenas um único método abstrato.

É importante lembrar que uma interface funcional pode possuir mais métodos, mas eles precisam ter uma implementação default.

Também podemos fazer com que o compilador do java garanta que determinada interface seja funcional. Com isso evitamos que nenhum outro desenvolvedor no futuro adicione outro método abstrato nessa interface e quebre o contrato de interface funcional, para isso basta adicionar a seguinte anotação na interface @FunctionalInterface.

DoubleFunction

Antes de entrarmos em detalhes sobre a interface funcional DoubleFunction aconselho você a dar uma olhada no meu outro post sobre a interface funcional Funcion.

Mas o que difere a interface Function para DoubleFunction, sendo que poderíamos tipar a interface Function com o tipo Double.

Aqui vem a sacada de mestre dos engenheiros da JVM.

Como tipos primitivos não podem ser argumentos de tipos genéricos, e pelo fato de que tipos primitivos consomem menos memória, há versões da interface Function para os tipos primitivos mais utilizados, como double, int e long.

Segue a implementação da interface DoubleFunction onde podemos observar que o parâmetro de entrada é do tipo double primitivo, podendo customizar apenas o tipo de retorno.

@FunctionalInterface
public interface DoubleFunction<R> {

   R apply(double value);

}

Para um maior entendimento de tudo que foi apresentado, vamos criar um cenário e implementar um exemplo para que o conhecimento aprendido neste post possa ser aplicado por você.

Cenário

Dado o valor total de uma venda, precisamos calcular a comissão do diretor, gerente, vendedor e assistente de prospecção.

  • Diretor - deve ter uma comissão de R$ 5,00 em vendas de até R$ 100,00, para vendas de até R$ 1.000,00 o diretor deve lucrar R$ 1,00 para cada R$ 30,00 vendidos, e para vendas acima de R$ 1.000,00 ele deve lucrar R$ 1,00 a cada R$ 25,00 vendidos.

  • Gerente - deve ter uma comissão de 9% em cima do valor total da venda.

  • Vendedor - deve ter uma comissão de 10% em cima do valor total da venda.

  • Assistente de prospecção - deve receber R$ 1,00 para vendas de até R$ 100,00, e para vendas acima de R$ 100,00 deve lucrar R$ 1,00 para cada R$ 50,00 vendidos.

Implementação

Quando estamos pensando em uma solução de implementação devemos estar cientes que nenhum cenário está escrito em pedra, em algum momento pode surgir uma nova regra ou uma mudança na regra existente. Tendo este pensamento e com o cenário mencionado anteriormente, acredito que a melhor opção de desenvolvimento seria a implementação de enum contendo os tipos de funções dos colaboradores o qual deve obrigar a implementação do cálculo da comissão, que nada mais é do que a implementação de uma interface funcional DoubleFunction.

import java.util.function.DoubleFunction;

public enum Colaboradores {

   DIRETOR(new CalculoComissaoDiretor()),
   ASSISTENTE_PROSPECCAO(new CalculoComissaoAssistenteProspeccao()),
   VENDEDOR(precoVenda -> precoVenda * 0.1),
   GERENTE(precoVenda -> precoVenda * 0.09);

   private final DoubleFunction<Double> calculoComissao;

   Colaboradores(DoubleFunction<Double> calculoComissao) {
       this.calculoComissao = calculoComissao;
   }

   public DoubleFunction<Double> getCalculoComissao() {
       return calculoComissao;
   }

}

Ao observarmos a implementação acima, estamos fazendo o uso de expressões lambdas na implementação do cálculo de comissão do vendedor e do gerente, já para o cálculo de comissão do diretor e do assistente de prospecção, onde a lógica para implementação contém um pouco mais de código, resolvi separar em outras duas classes, onde implemento a interface funcional DoubleFunction.

import java.util.function.DoubleFunction;

public class CalculoComissaoAssistenteProspeccao implements DoubleFunction<Double> {

   @Override
   public Double apply(double precoVenda) {
       if (precoVenda <= 100) {
           return 1D;
       }
       return (double) ((int) precoVenda / 50);
   }

}
import java.util.function.DoubleFunction;

public class CalculoComissaoDiretor implements DoubleFunction<Double> {

   @Override
   public Double apply(double precoVenda) {
       if (precoVenda <= 100) {
           return 5D;
       } else if (precoVenda <= 1_000) {
           return (double) ((int) precoVenda / 30);
       }
       return (double) ((int) precoVenda / 25);
   }

}

Caso surja um novo cargo na empresa que deve receber comissões nas vendas, basta adicionar um novo tipo no enum e utilizar uma regra de cálculo já existente ou implementar uma nova. Feito isso garantimos que nenhum desenvolvedor crie um novo cargo sem implementar a regra de comissão.

Conclusão

Neste post, descrevemos a interface funcional DoubleFunction que está presente na API do Java 8, e que ela pode ser usada como expresssão lambda.

O código fonte deste post está disponível neste repoistório no github.

// Compartilhe esse Post

💫
🔥 NOVO APP

Domine o Inglês em 30 dias!

Inteligência Artificial + Repetição Espaçada • Método cientificamente comprovado

✅ Grátis para começar 🚀 Resultados rápidos
×