Por décadas tem sido o caso que interfaces eram única única (apenas) para especificar assinaturas de método. Disseram-nos que este era o "caminho certo para fazer as coisas ™".
Então o Java 8 saiu e disse:
Bem, agora você pode definir métodos padrão. Tenho que correr, tchau.
Estou curioso para saber como isso está sendo digerido por desenvolvedores Java experientes e por aqueles que começaram recentemente (nos últimos anos) a desenvolvê-lo. Também estou pensando em como isso se encaixa na ortodoxia e prática do Java.
Estou criando um código experimental e, enquanto fazia refatoração, acabei com uma interface que simplesmente estende uma interface padrão (Iterable) e adiciona dois métodos padrão. E vou ser sincero, me sinto muito bem com isso.
Eu sei que isso é um pouco aberto, mas agora que já houve algum tempo para o Java 8 ser usado em projetos reais, existe uma ortodoxia em torno do uso de métodos padrão ainda? O que eu vejo principalmente quando são discutidos é sobre como adicionar novos métodos a uma interface sem prejudicar os consumidores existentes. Mas que tal usar isso desde o início, como no exemplo que eu dei acima. Alguém já teve problemas com o fornecimento de implementações em suas interfaces?
fonte
java.util.function.Function
uso de métodos padrão em uma interface totalmente nova.Respostas:
Um ótimo caso de uso é o que eu chamo de interfaces "alavanca": interfaces que possuem apenas um pequeno número de métodos abstratos (idealmente 1), mas oferecem muita "alavancagem", pois fornecem muitas funcionalidades: Você precisa implementar 1 método em sua classe, mas obter muitos outros métodos "de graça". Pense de uma interface de recolha, por exemplo, com um sumário único
foreach
método edefault
métodos comomap
,fold
,reduce
,filter
,partition
,groupBy
,sort
,sortBy
, etc.Aqui estão alguns exemplos. Vamos começar com
java.util.function.Function<T, R>
. Ele tem um único método abstratoR apply<T>
. E possui dois métodos padrão que permitem compor a função com outra função de duas maneiras diferentes, antes ou depois. Ambos os métodos de composição são implementados usando apenasapply
:Você também pode criar uma interface para objetos comparáveis, algo como isto:
Ou uma estrutura de coleções extremamente simplificada, em que todas as operações de coleções retornam
Collection
, independentemente do tipo original:Isso se torna muito interessante em combinação com lambdas, porque essa interface "alavanca" pode ser implementada por uma lambda (é uma interface SAM).
É o mesmo caso de uso para o qual foram adicionados os métodos de extensão em C in, mas os métodos padrão têm uma vantagem distinta: são métodos de instância "adequados", o que significa que eles têm acesso a detalhes de implementação privados da interface (os
private
métodos de interface estão chegando no Java 9), enquanto os métodos de extensão são apenas açúcar sintático para métodos estáticos.Caso o Java receba a injeção de interface, também permitiria o patch de macaco modular, com escopo seguro e de tipo seguro. Isso seria muito interessante para implementadores de linguagem na JVM: no momento, por exemplo, o JRuby herda ou agrupa classes Java para fornecer a eles semântica adicional em Ruby, mas, idealmente, eles querem usar as mesmas classes. Com Injeção de Interface e Métodos Padrão, eles podem injetar, por exemplo, uma
RubyObject
interfacejava.lang.Object
, para que JavaObject
e RubyObject
sejam exatamente a mesma coisa .fonte
Comparable
interface com um abstratocompareTo
método e padrãolessThan
,lessThanOrEqual
,greaterThan
,greaterThanOrEqual
,isBetween
, eclamp
métodos, todas implementadas em termos decompareTo
. Ou, apenas observejava.util.function.Function
: ele possui umapply
método abstrato e dois métodos de composição padrão, ambos implementados em termos deapply
. Tentei dar um exemplo deCollection
interface, mas conseguir que tudo seja do tipo seguro é complicado e muito longo para esta resposta - tentarei dar uma chance a uma versão que não seja do tipo e que não preserve o tipo. Fique ligado.