Qual é o propósito da palavra-chave padrão em Java?

97

Uma interface em Java é semelhante a uma classe, mas o corpo de uma interface pode incluir apenas métodos abstratos e finalcampos (constantes).

Recentemente, vi uma pergunta parecida com esta

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

De acordo com a definição da interface, apenas métodos abstratos são permitidos. Por que me permite compilar o código acima? Qual é a defaultpalavra - chave?

Por outro lado, quando eu estava tentando escrever o código abaixo, ele dizia modifier default not allowed here

default class MyClass{

}

ao invés de

class MyClass {

}

Alguém pode me dizer o propósito da defaultpalavra - chave? É permitido apenas dentro de uma interface? Como ele difere de default(sem modificador de acesso)?

Ravi
fonte
4
métodos padrão em interfaces foram adicionados em Java 8. Não é um modificador de acesso, é uma implementação padrão.
Eran
2
@Eran você não acha, introdução de método padrão violando a definição de interface? : s
Ravi
2
Isso mudou a definição da interface. Essa definição agora está desatualizada.
Louis Wasserman
2
Eles foram introduzidos para apoiar lambdas. Os detalhes de por que eles são necessários estão na proposta do espantalho para o Projeto Lambda.
velocista

Respostas:

76

É um novo recurso do Java 8 que permite interfacefornecer uma implementação. Descrito em Java 8 JLS-13.5.6. Declarações de método de interface que lê (em parte)

Adicionar um defaultmétodo ou alterar um método de abstractpara defaultnão quebra a compatibilidade com binários pré-existentes, mas pode causar um erro IncompatibleClassChangeErrorse um binário pré-existente tentar chamar o método. Este erro ocorre se o tipo de qualificação,, Té um subtipo de duas interfaces, Ie J, onde Ie Jdeclaram um defaultmétodo com a mesma assinatura e resultado, e nem Inem Jé uma subinterface do outro.

O que há de novo no JDK 8 diz (em parte)

Os métodos padrão permitem que novas funcionalidades sejam adicionadas às interfaces das bibliotecas e garantem a compatibilidade binária com o código escrito para versões mais antigas dessas interfaces.

Elliott Frisch
fonte
16
Parece que agora a interface e a classe abstrata são quase iguais. :)
Ravi
16
As interfaces @jWeaver ainda não podem ter construtores, campos, métodos privados ou implementações de equals / hashCode / toString.
Louis Wasserman
10
@Louis Wasserman: No Java 9, eles podem ter privatemétodos.
Holger
6
@Dan Pantry: os privatemétodos não fazem realmente parte da interface, mas podem servir como métodos auxiliares para as defaultimplementações ou em inicializadores constantes. Observe que eles já existem no Java 8, pois, quando você usa expressões lambda em interfaces, privatemétodos sintéticos são gerados. Portanto, o Java 9 permite que você use esse recurso para usos não sintéticos, não lambda também ...
Holger
14
@jWeaver A diferença entre interfaces e classes se reduz ao estado versus comportamento . As interfaces podem carregar comportamento, mas apenas classes podem ter estado. (Campos, construtores e métodos como equals / hashCode são sobre estado.)
Brian Goetz
29

Métodos padrão foram adicionados ao Java 8 principalmente para oferecer suporte a expressões lambda. Os designers (habilmente, na minha opinião) decidiram fazer a sintaxe lambdas para criar implementações anônimas de uma interface. Mas dados lambdas só podem implementar um único método, eles seriam limitados a interfaces com um único método, o que seria uma restrição bastante severa. Em vez disso, os métodos padrão foram adicionados para permitir o uso de interfaces mais complexas.

Se você precisar de algum convencimento da afirmação que defaultfoi introduzida devido aos lambdas, observe que a proposta do espantalho do Projeto Lambda, de Mark Reinhold, em 2009, menciona 'Métodos de extensão' como um recurso obrigatório a ser adicionado para suportar lambdas.

Aqui está um exemplo que demonstra o conceito:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

Muito artificial eu percebo, mas devo ilustrar como defaultsuporta lambdas. Por inverseser um padrão, ele pode ser facilmente substituído por uma classe de implementação, se necessário.

velocista
fonte
8
Isso não é realmente correto. Lambdas podem ser a causa próxima, mas na verdade foram apenas a palha que quebrou as costas do camelo. A verdadeira motivação era permitir a evolução da interface (permitindo que as interfaces existentes fossem evoluídas de forma compatível para suportar novos comportamentos); lambdas pode ter sido o fator que trouxe essa necessidade à tona, mas o recurso é mais geral do que isso.
Brian Goetz
@BrianGoetz: IMHO, Java e .NET teriam se beneficiado enormemente se os métodos padrão existissem desde o início. Se alguma operação comum pudesse ser executada em qualquer implementação de uma interface usando apenas membros da interface, mas algumas implementações provavelmente teriam uma maneira mais eficiente de fazê-las, a interface deve definir métodos para essas operações e fornecer implementações padrão para elas. A incapacidade de especificar implementações padrão induziu pressão para que as interfaces omitissem esses métodos e tornou impossível para eles adicioná-los posteriormente.
supercat
@BrianGoetz Concordo que os métodos padrão têm um valor significativo além dos lambdas. Mas eu estaria interessado em qualquer referência que você possa dar a esse valor mais amplo que conduz a decisão de incluí-los. Minha leitura é que lambdas foram o motivo principal (por isso usei a palavra "principalmente" em minha resposta).
velocista
2
Talvez este documento ajude: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html . A seção 10 diz claramente: "O objetivo dos métodos padrão (anteriormente referidos como métodos de extensão virtual ou métodos de defesa) é permitir que as interfaces sejam desenvolvidas de maneira compatível após sua publicação inicial." Os métodos compatíveis com Lambda são então citados como uma ilustração da evolução da interface.
Brian Goetz
2
@Kartik Você está fazendo a pergunta errada! Não escolhemos a sintaxe com base em "qual é o mínimo absoluto necessário para o compilador analisar o programa corretamente"; nós o escolhemos com base em "o que tornaria a intenção do programador mais imediatamente evidente para os leitores". Projetamos primeiro para usuários e, secundariamente, para compiladores (e, quando se trata de usuários, projetamos primeiro para leitura e depois para escrita.)
Brian Goetz
17

Algo que foi esquecido nas outras respostas foi seu papel nas anotações. Já em Java 1.5, a defaultpalavra - chave surgiu como um meio de fornecer um valor padrão para um campo de anotação.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

Seu uso foi sobrecarregado com a introdução do Java 8 para permitir a definição de um método padrão nas interfaces.

Outra coisa que foi esquecida: a razão pela qual a declaração default class MyClass {}é inválida é devido à forma como as classes são declaradas . Não há nenhuma disposição no idioma que permite que essa palavra-chave apareça lá. Ele não aparecer para declarações de métodos de interface , no entanto.

Makoto
fonte
16

Um novo conceito é introduzido no Java 8, chamado de métodos padrão. Os métodos padrão são aqueles métodos que têm alguma implementação padrão e ajudam na evolução das interfaces sem quebrar o código existente. Vejamos um exemplo:

 public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

 class SimpleInterfaceImpl implements SimpleInterface{

  @Override
  public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Not required to override to provide an implementation
  * for doSomeOtherWork.
  */

 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

e a saída é:

Implementação Do Some Work na classe
Implementação DoSomeOtherWork na interface

Saurabh Gaur
fonte
3

O novo recurso Java 8 ( métodos padrão ) permite que uma interface forneça uma implementação quando é rotulada com a defaultpalavra - chave.

Por exemplo:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

Teste de interface usa a palavra-chave padrão que permite à interface fornecer uma implementação padrão do método sem a necessidade de implementar esses métodos nas classes que usam a interface.

Compatibilidade com versões anteriores: imagine que sua interface é implementada por centenas de classes, modificar essa interface forçará todos os usuários a implementar o método recém-adicionado, embora não seja essencial para muitas outras classes que implementam sua interface.

Fatos e restrições:

1-Só pode ser declarado dentro de uma interface e não dentro de uma classe ou classe abstrata.

2-Deve fornecer um corpo

3-Não se presume ser público ou abstrato como outros métodos normais usados ​​em uma interface.

Ahmad Sanie
fonte
3

Os métodos padrão em uma interface nos permitem adicionar novas funcionalidades sem quebrar o código antigo.

Antes do Java 8, se um novo método fosse adicionado a uma interface, todas as classes de implementação dessa interface eram obrigadas a substituir esse novo método, mesmo que não usassem a nova funcionalidade.

Com o Java 8, podemos adicionar a implementação padrão para o novo método usando a defaultpalavra - chave antes da implementação do método.

Mesmo com classes anônimas ou interfaces funcionais, se virmos que algum código é reutilizável e não quisermos definir a mesma lógica em todo o código, podemos escrever implementações padrão dessas e reutilizá-las.

Exemplo

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }
Dickson o desenvolvedor
fonte
2

Uma explicação muito boa é encontrada nos Tutoriais Java ™ , parte da explicação é a seguinte:

Considere um exemplo que envolve fabricantes de carros controlados por computador que publicam interfaces padrão da indústria que descrevem quais métodos podem ser invocados para operar seus carros. E se esses fabricantes de carros controlados por computador adicionassem novas funcionalidades, como vôo, a seus carros? Esses fabricantes precisariam especificar novos métodos para permitir que outras empresas (como fabricantes de instrumentos eletrônicos de orientação) adaptassem seu software a carros voadores. Onde esses fabricantes de automóveis declarariam esses novos métodos de voo? Se eles os adicionarem às suas interfaces originais, os programadores que implementaram essas interfaces teriam que reescrever suas implementações. Se eles os adicionarem como métodos estáticos, os programadores os considerarão como métodos utilitários, não como métodos essenciais essenciais.

Os métodos padrão permitem adicionar nova funcionalidade às interfaces de suas bibliotecas e garantir compatibilidade binária com código escrito para versões anteriores dessas interfaces.

Riyafa Abdul Hameed
fonte
1

Os métodos padrão permitem que você adicione novas funcionalidades às interfaces de seus aplicativos. Também pode ser usado para ter uma herança múltipla . Além dos métodos padrão, você pode definir métodos estáticos nas interfaces. Isso torna mais fácil para você organizar métodos auxiliares

user3359139
fonte