Médio Java

Métodos default e interface funcional

Enunciado

Crie uma interface funcional Operacao com o método int calcular(int a, int b). Adicione um método default int calcularComZero(int a) que usa calcular(a, 0). No main, use lambdas para criar uma soma e uma multiplicação, e chame tanto calcular quanto calcularComZero.

Requisitos

  • A interface Operacao deve ser anotada com @FunctionalInterface e ter um único método abstrato.
  • Deve conter um método default int calcularComZero(int a) que chama calcular(a, 0).
  • O main deve criar lambdas para soma e multiplicação e imprimir os resultados de calcular e calcularComZero.

Código inicial

@FunctionalInterface
interface Operacao {
    int calcular(int a, int b);

    // TODO: adicione o método default calcularComZero
}

public class Main {
    public static void main(String[] args) {
        // TODO: crie lambdas e teste os métodos
    }
}

Saída esperada

Soma 5+3: 8
Soma 5+0: 5
Multiplicacao 5*3: 15
Multiplicacao 5*0: 0
Ver dica

Lembre-se de que o método default pode chamar o método abstrato da própria interface. Para a multiplicação, calcularComZero(5) deve retornar 0.

Mostrar solução
@FunctionalInterface
interface Operacao {
    int calcular(int a, int b); // único método abstrato

    // Método default que reutiliza o método abstrato
    default int calcularComZero(int a) {
        return calcular(a, 0);
    }
}

public class Main {
    public static void main(String[] args) {
        // Lambda para soma
        Operacao soma = (a, b) -> a + b;
        // Lambda para multiplicação
        Operacao multiplicacao = (a, b) -> a * b;

        System.out.println("Soma 5+3: " + soma.calcular(5, 3));
        System.out.println("Soma 5+0: " + soma.calcularComZero(5));
        System.out.println("Multiplicacao 5*3: " + multiplicacao.calcular(5, 3));
        System.out.println("Multiplicacao 5*0: " + multiplicacao.calcularComZero(5));
    }
}

Passo a passo

  1. A anotação @FunctionalInterface garante que a interface tenha exatamente um método abstrato. Se adicionarmos outro, o compilador reclama.
  2. O método calcular(int a, int b) é o contrato principal que as lambdas vão implementar.
  3. O método default int calcularComZero(int a) fornece uma implementação padrão que chama calcular(a, 0). Classes que implementam Operacao não precisam redefini-lo.
  4. No main, criamos duas lambdas: soma e multiplicacao. Cada uma implementa o método abstrato calcular.
  5. Chamamos calcular diretamente nas lambdas para obter os resultados esperados.
  6. Chamamos calcularComZero, que usa internamente a lambda correspondente, passando 0 como segundo argumento.

Por que funciona

Interfaces funcionais permitem que lambdas sejam atribuídas a variáveis do tipo da interface. O método default calcularComZero é herdado por qualquer implementação (incluindo lambdas) e pode chamar o método abstrato, que será resolvido dinamicamente para a lambda específica. Isso mostra como métodos default adicionam comportamento sem quebrar implementações existentes.

Erros comuns

  • Adicionar outro método abstrato à interface: int subtrair(int a, int b); faz o compilador acusar que @FunctionalInterface não é mais válida. Remova a anotação ou torne o método default.
  • Esquecer a palavra-chave default no método com implementação: int calcularComZero(int a) { ... } não compila, pois métodos de interface sem corpo são abstratos.
  • Tentar usar uma lambda sem que a interface seja funcional: se houver dois métodos abstratos, a lambda não pode ser usada.

Outra forma de resolver

Poderia usar classes anônimas em vez de lambdas:

Operacao soma = new Operacao() {
    @Override
    public int calcular(int a, int b) {
        return a + b;
    }
};

Lambdas são preferíveis por serem mais concisas e legíveis quando a interface é funcional.

Saída esperada

Soma 5+3: 8
Soma 5+0: 5
Multiplicacao 5*3: 15
Multiplicacao 5*0: 0