O operador de dois pontos em Java 8

O operador de dois pontos em Java 8

1. Visão geral

Neste artigo rápido, discutiremosdouble colon operator (::) no Java 8 e examinaremos os cenários onde o operador pode ser usado.

Leitura adicional:

Perguntas da entrevista do Java 8 (+ respostas)

Um conjunto de perguntas populares da entrevista relacionadas ao Java8 e, é claro, respostas.

Read more

Guia para Java 8 opcional

Guia rápido e prático para opcional em Java 8

Read more

Novos recursos no Java 8

Uma breve introdução aos novos recursos do Java 8; o foco está nos métodos de interface estáticos e padrão, nas referências de método estático e em Opcional.

Read more

2. De Lambdas para Operador de Dois Pontos

Com expressões Lambdas, vimos que o código pode se tornar muito conciso.

Por exemplo, paracreate a comparator, a seguinte sintaxe é suficiente:

Comparator c = (Computer c1, Computer c2) -> c1.getAge().compareTo(c2.getAge());

Então, com inferência de tipo:

Comparator c = (c1, c2) -> c1.getAge().compareTo(c2.getAge());

Mas podemos tornar o código acima ainda mais expressivo e legível? Vamos dar uma olhada:

Comparator c = Comparator.comparing(Computer::getAge);

Usamos o operador:: como abreviação para lambdas chamando um método específico - por nome. E, no final, o resultado é, obviamente, uma sintaxe ainda mais legível.

3. Como funciona?

Simplificando, quando estamos usando uma referência de método - a referência de destino é colocada antes do delimitador::e o nome do método é fornecido depois dele.

Por exemplo:

Computer::getAge;

Estamos vendo uma referência de método para o métodogetAge definido na classeComputer.

Podemos então operar com essa função:

Function getAge = Computer::getAge;
Integer computerAge = getAge.apply(c1);

Observe que estamos referenciando a função - e, em seguida, aplicando-a ao tipo certo de argumento.

4. Referências de método

Podemos fazer bom uso desse operador em alguns cenários.

4.1. Um método estático

Primeiro, vamos fazer uso dea static utility method:

List inventory = Arrays.asList(
  new Computer( 2015, "white", 35), new Computer(2009, "black", 65));
inventory.forEach(ComputerUtils::repair);

4.2. Um método de instância de um objeto existente

A seguir, vamos dar uma olhada em um cenário interessante -referencing a method of an existing object instance.

Vamos usar a variávelSystem.out - um objeto do tipoPrintStream que suporta o métodoprint:

Computer c1 = new Computer(2015, "white");
Computer c2 = new Computer(2009, "black");
Computer c3 = new Computer(2014, "black");
Arrays.asList(c1, c2, c3).forEach(System.out::print);

4.3. Um método de instância de um objeto arbitrário de um tipo específico

Computer c1 = new Computer(2015, "white", 100);
Computer c2 = new MacbookPro(2009, "black", 100);
List inventory = Arrays.asList(c1, c2);
inventory.forEach(Computer::turnOnPc);

Como você pode ver, estamos nos referindo ao métodoturnOnPc não em uma instância específica, mas no próprio tipo.

Na linha 4, o método de instânciaturnOnPc será chamado para cada objeto deinventory.

E isso naturalmente significa que - parac1, o métodoturnOnPc será chamado na instânciaComputer e parac2 na instânciaMacbookPro.

4.4. Um Super Método de um Objeto Particular

Suponha que você tenha o seguinte método na superclasseComputer:

public Double calculateValue(Double initialValue) {
    return initialValue/1.50;
}

e este na subclasseMacbookPro:

@Override
public Double calculateValue(Double initialValue){
    Function function = super::calculateValue;
    Double pcValue = function.apply(initialValue);
    return pcValue + (initialValue/10) ;
}

Uma chamada para o métodocalculateValue em uma instânciaMacbookPro:

macbookPro.calculateValue(999.99);

também produzirá uma chamada paracalculateValue na superclasseComputer.

5. Referências de construtor

5.1. Crie uma nova instância

Fazer referência a um construtor para instanciar um objeto pode ser bastante simples:

@FunctionalInterface
public interface InterfaceComputer {
    Computer create();
}

InterfaceComputer c = Computer::new;
Computer computer = c.create();

E se você tiver dois parâmetros em um construtor?

BiFunction c4Function = Computer::new;
Computer c4 = c4Function.apply(2013, "white");

Se os parâmetros forem três ou mais, você deverá definir uma nova interface Funcional:

@FunctionalInterface
interface TriFunction {
    R apply(A a, B b, C c);
    default  TriFunction andThen( Function after) {
        Objects.requireNonNull(after);
        return (A a, B b, C c) -> after.apply(apply(a, b, c));
    }
}

Em seguida, inicialize seu objeto:

TriFunction  c6Function = Computer::new;
Computer c3 = c6Function.apply(2008, "black", 90);

5.2. Criar uma matriz

Finalmente, vamos ver como criar uma matriz de objetosComputer com cinco elementos:

Function  computerCreator = Computer[]::new;
Computer[] computerArray = computerCreator.apply(5);

6. Conclusão

Como estamos começando a ver, o operador de dois pontos duplos - introduzido no Java 8 - será muito útil em alguns cenários e especialmente em conjunto com Streams.

Também é muito importante dar uma olhada nas interfaces funcionais para uma melhor compreensão do que acontece nos bastidores.

Osource code completo para o exemplo está disponível emthis GitHub project - este é um projeto Maven e Eclipse para que possa ser importado e usado como está.