Operador :: (dois pontos) no Java 8

956

Eu estava explorando a fonte Java 8 e achei esta parte específica do código muito surpreendente:

//defined in IntPipeline.java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
    return evaluate(ReduceOps.makeInt(op));
}

@Override
public final OptionalInt max() {
    return reduce(Math::max); //this is the gotcha line
}

//defined in Math.java
public static int max(int a, int b) {
    return (a >= b) ? a : b;
}

É Math::maxalgo como um ponteiro de método? Como um staticmétodo normal é convertido IntBinaryOperator?

Narendra Pathai
fonte
60
É açúcar sintático ter as implementações de interface de geração automática do compilador com base na função que você fornece (para tornar todo o lambda mais fácil de usar com as bases de código existentes).
Neet
4
java.dzone.com/articles/java-lambda-expressions-vs pode ajudar, não parecia profundo no tópico
Pontus Backlund
8
@ Neet não é exatamente "açúcar sintático", a menos que você possa dizer o quê. ie "x é açúcar sintático para y".
Ingo
6
@Ingo cria um novo objeto lambda toda vez que eu o uso. TestingLambda$$Lambda$2/8460669e TestingLambda$$Lambda$3/11043253foram criados em duas invocações.
Narendra Pathai 15/11
13
As referências de método e lambdas não são "classes internas anônimas simples". Consulte programmers.stackexchange.com/a/181743/59134 . Sim, se necessário, novas classes e instâncias são criadas dinamicamente, se necessário, mas somente se necessário.
Stuart Marcas

Respostas:

1022

Geralmente, alguém poderia chamar o reducemétodo usando Math.max(int, int)o seguinte:

reduce(new IntBinaryOperator() {
    int applyAsInt(int left, int right) {
        return Math.max(left, right);
    }
});

Isso requer muita sintaxe para apenas chamar Math.max. É aí que as expressões lambda entram em cena. Desde o Java 8, é permitido fazer a mesma coisa de uma maneira muito mais curta:

reduce((int left, int right) -> Math.max(left, right));

Como é que isso funciona? O compilador java "detecta" que você deseja implementar um método que aceita dois se intretorna um int. Isso é equivalente aos parâmetros formais do primeiro e único método de interface IntBinaryOperator(o parâmetro do método que reducevocê deseja chamar). Portanto, o compilador faz o resto por você - apenas assume que você deseja implementar IntBinaryOperator.

Mas como Math.max(int, int)ele cumpre os requisitos formais de IntBinaryOperator, pode ser usado diretamente. Como o Java 7 não possui nenhuma sintaxe que permita que um método seja transmitido como argumento (você só pode passar resultados de métodos, mas nunca referências a métodos), a ::sintaxe foi introduzida no Java 8 para referenciar métodos:

reduce(Math::max);

Observe que isso será interpretado pelo compilador, não pela JVM em tempo de execução! Embora produza bytecodes diferentes para todos os três trechos de código, eles são semanticamente iguais, portanto os dois últimos podem ser considerados versões curtas (e provavelmente mais eficientes) da IntBinaryOperatorimplementação acima!

(Veja também a tradução de expressões lambda )

isnot2bad
fonte
489

::é chamado de Referência de método. É basicamente uma referência a um único método. Ou seja, refere-se a um método existente por nome.

Breve explicação :
Abaixo está um exemplo de uma referência a um método estático:

class Hey {
     public static double square(double num){
        return Math.pow(num, 2);
    }
}

Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);

squarepode ser transmitido como referências a objetos e acionado quando necessário. De fato, ele pode ser usado tão facilmente quanto uma referência a métodos "normais" de objetos static. Por exemplo:

class Hey {
    public double square(double num) {
        return Math.pow(num, 2);
    }
}

Hey hey = new Hey();
Function<Double, Double> square = hey::square;
double ans = square.apply(23d);

Functionacima é uma interface funcional . Para entender completamente ::, é importante entender também as interfaces funcionais. Claramente, uma interface funcional é uma interface com apenas um método abstrato.

Exemplos das interfaces funcionais incluem Runnable, Callablee ActionListener.

Functionacima é uma interface funcional com apenas um método: apply. É preciso um argumento e produz um resultado.


A razão porque :: s são impressionantes é que :

As referências de método são expressões que têm o mesmo tratamento que expressões lambda (...), mas em vez de fornecer um corpo de método, elas referem um método existente por nome.

Por exemplo, em vez de escrever o corpo lambda

Function<Double, Double> square = (Double x) -> x * x;

Você pode simplesmente fazer

Function<Double, Double> square = Hey::square;

Em tempo de execução, esses dois square métodos se comportam exatamente da mesma forma que o outro. O bytecode pode ou não ser o mesmo (embora, para o caso acima, o mesmo bytecode seja gerado; compile o acima e verifique com javap -c).

O único critério importante a satisfazer é: o método que você fornece deve ter uma assinatura semelhante ao método da interface funcional usada como referência de objeto .

O abaixo é ilegal:

Supplier<Boolean> p = Hey::square; // illegal

squareespera um argumento e retorna a double. O getmétodo em Fornecedor retorna um valor, mas não aceita um argumento. Assim, isso resulta em um erro.

Uma referência de método refere-se ao método de uma interface funcional.(Como mencionado, as interfaces funcionais podem ter apenas um método cada).

Mais alguns exemplos: o acceptmétodo no Consumidor recebe uma entrada, mas não retorna nada.

Consumer<Integer> b1 = System::exit;   // void exit(int status)
Consumer<String[]> b2 = Arrays::sort;  // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)

class Hey {
    public double getRandom() {
        return Math.random();
    }
}

Callable<Double> call = hey::getRandom;
Supplier<Double> call2 = hey::getRandom;
DoubleSupplier sup = hey::getRandom;
// Supplier is functional interface that takes no argument and gives a result

Acima, getRandomnão aceita argumentos e retorna a double. Portanto, qualquer interface funcional que atenda aos critérios de: não aceite argumentos e retornedouble pode ser usada.

Outro exemplo:

Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Predicate<String> pred = set::contains;
boolean exists = pred.test("leo");

No caso de tipos parametrizados :

class Param<T> {
    T elem;
    public T get() {
        return elem;
    }

    public void set(T elem) {
        this.elem = elem;
    }

    public static <E> E returnSame(E elem) {
        return elem;
    }
}

Supplier<Param<Integer>> obj = Param<Integer>::new;
Param<Integer> param = obj.get();
Consumer<Integer> c = param::set;
Supplier<Integer> s = param::get;

Function<String, String> func = Param::<String>returnSame;

As referências de método podem ter estilos diferentes, mas, fundamentalmente, todas significam a mesma coisa e podem simplesmente ser visualizadas como lambdas:

  1. Um método estático ( ClassName::methName)
  2. Um método de instância de um objeto específico (instanceRef::methName )
  3. Um super método de um objeto específico (super::methName )
  4. Um método de instância de um objeto arbitrário de um tipo específico (ClassName::methName )
  5. Uma referência de construtor de classe (ClassName::new )
  6. Uma referência de construtor de matriz ( TypeName[]::new)

Para referência adicional, consulte http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html .

Jatin
fonte
6
Obrigado pela explicação. Em resumo: '::' use para extrair um método que satisfaz uma FunctionalInterface (lambda): ClassX :: staticMethodX, ou INSTANCEX :: instanceMethodX"
jessarah
55

Sim, é verdade. O ::operador é usado para referência ao método. Então, pode-se extrair estática métodos de classes usando-os ou métodos de objetos. O mesmo operador pode ser usado mesmo para construtores. Todos os casos mencionados aqui são exemplificados no exemplo de código abaixo.

A documentação oficial da Oracle pode ser encontrada aqui .

Você pode ter uma visão geral melhor das alterações do JDK 8 neste artigo. Na seção de referência de método / construtor , também é fornecido um exemplo de código:

interface ConstructorReference {
    T constructor();
}

interface  MethodReference {
   void anotherMethod(String input);
}

public class ConstructorClass {
    String value;

   public ConstructorClass() {
       value = "default";
   }

   public static void method(String input) {
      System.out.println(input);
   }

   public void nextMethod(String input) {
       // operations
   }

   public static void main(String... args) {
       // constructor reference
       ConstructorReference reference = ConstructorClass::new;
       ConstructorClass cc = reference.constructor();

       // static method reference
       MethodReference mr = cc::method;

       // object method reference
       MethodReference mr2 = cc::nextMethod;

       System.out.println(cc.value);
   }
}
Olimpiu POP
fonte
uma boa explicação é a encontrada aqui: doanduyhai.wordpress.com/2012/07/14/…
Olimpiu POP
1
@RichardTingle method(Math::max);é invocação e definição de método seria semelhante public static void method(IntBinaryOperator op){System.out.println(op.applyAsInt(1, 2));}. É assim que é usado.
Narendra Pathai
2
Para aqueles familiarizados com C #, é semelhante ao DelegateType d = new DelegateType (MethodName);
Adrian Zanescu
27

Parece um pouco tarde, mas aqui estão meus dois centavos. Uma expressão lambda é usada para criar métodos anônimos. Ele não faz nada além de chamar um método existente, mas é mais claro fazer referência ao método diretamente por seu nome. E a referência de método nos permite fazer isso usando o operador de referência de método ::.

Considere a seguinte classe simples, em que cada funcionário tem um nome e uma nota.

public class Employee {
    private String name;
    private String grade;

    public Employee(String name, String grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }
}

Suponha que tenhamos uma lista de funcionários retornada por algum método e que desejemos classificar os funcionários por nota. Sabemos que podemos fazer uso da classe anônima como:

    List<Employee> employeeList = getDummyEmployees();

    // Using anonymous class
    employeeList.sort(new Comparator<Employee>() {
           @Override
           public int compare(Employee e1, Employee e2) {
               return e1.getGrade().compareTo(e2.getGrade());
           }
    });

onde getDummyEmployee () é algum método como:

private static List<Employee> getDummyEmployees() {
        return Arrays.asList(new Employee("Carrie", "C"),
                new Employee("Fanishwar", "F"),
                new Employee("Brian", "B"),
                new Employee("Donald", "D"),
                new Employee("Adam", "A"),
                new Employee("Evan", "E")
                );
    }

Agora sabemos que o Comparator é uma interface funcional. UMA Interface Funcional é aquela com exatamente um método abstrato (embora possa conter um ou mais métodos estáticos ou padrão). A expressão Lambda fornece implementação @FunctionalInterfacepara que uma interface funcional possa ter apenas um método abstrato. Podemos usar a expressão lambda como:

employeeList.sort((e1,e2) -> e1.getGrade().compareTo(e2.getGrade())); // lambda exp

Parece tudo de bom, mas e se a classe Employeetambém fornecer um método semelhante:

public class Employee {
    private String name;
    private String grade;
    // getter and setter
    public static int compareByGrade(Employee e1, Employee e2) {
        return e1.grade.compareTo(e2.grade);
    }
}

Nesse caso, o uso do próprio nome do método será mais claro. Portanto, podemos nos referir diretamente ao método usando a referência do método como:

employeeList.sort(Employee::compareByGrade); // method reference

De acordo com os documentos, existem quatro tipos de referências de método:

+----+-------------------------------------------------------+--------------------------------------+
|    | Kind                                                  | Example                              |
+----+-------------------------------------------------------+--------------------------------------+
| 1  | Reference to a static method                          | ContainingClass::staticMethodName    |
+----+-------------------------------------------------------+--------------------------------------+
| 2  |Reference to an instance method of a particular object | containingObject::instanceMethodName | 
+----+-------------------------------------------------------+--------------------------------------+
| 3  | Reference to an instance method of an arbitrary object| ContainingType::methodName           |
|    | of a particular type                                  |                                      |  
+----+-------------------------------------------------------+--------------------------------------+
| 4  |Reference to a constructor                             | ClassName::new                       |
+------------------------------------------------------------+--------------------------------------+
akhil_mittal
fonte
25

::é um novo operador incluído no Java 8 que é usado para referenciar um método de uma classe existente. Você pode consultar métodos estáticos e métodos não estáticos de uma classe.

Para referenciar métodos estáticos, a sintaxe é:

ClassName :: methodName 

Para referenciar métodos não estáticos, a sintaxe é

objRef :: methodName

E

ClassName :: methodName

O único pré-requisito para referenciar um método é que o método exista em uma interface funcional, que deve ser compatível com a referência do método.

As referências de método, quando avaliadas, criam uma instância da interface funcional.

Encontrado em: http://www.speakingcs.com/2014/08/method-references-in-java-8.html

Sreenath
fonte
22

Esta é uma referência de método no Java 8. A documentação do oracle está aqui .

Conforme declarado na documentação ...

A referência do método Person :: compareByAge é uma referência a um método estático.

A seguir, é apresentado um exemplo de referência a um método de instância de um objeto específico:

class ComparisonProvider {
    public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }

    public int compareByAge(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName); 

A referência do método myComparisonProvider :: compareByName chama o método compareByName que faz parte do objeto myComparisonProvider. O JRE infere os argumentos do tipo de método, que neste caso são (Pessoa, Pessoa).

david99world
fonte
2
mas o método 'compareByAge' não é estático.
abbas
3
@abbas Nem é compareByName. Portanto, você acessa esses métodos não estáticos através do operador de referência usando um objeto. Se eles eram estáticos, você poderia usar o nome da classe como ComparisionProvider :: someStaticMethod
Seshadri R
6

:: O operador foi introduzido no java 8 para referências de métodos. Uma referência de método é a sintaxe abreviada de uma expressão lambda que executa apenas UM método. Aqui está a sintaxe geral de uma referência de método:

Object :: methodName

Sabemos que podemos usar expressões lambda em vez de usar uma classe anônima. Mas, às vezes, a expressão lambda é realmente apenas uma chamada para algum método, por exemplo:

Consumer<String> c = s -> System.out.println(s);

Para tornar o código mais claro, você pode transformar essa expressão lambda em uma referência de método:

Consumer<String> c = System.out::println;
Vaibhav9518
fonte
3

O :: é conhecido como referências de método. Digamos que queremos chamar um método calculado da classe Purchase. Então podemos escrever como:

Purchase::calculatePrice

Também pode ser vista como uma forma curta de escrever a expressão lambda Como as referências do método são convertidas em expressões lambda.

Sonu
fonte
Posso fazer referências de método aninhado? Por exemplo, groupingBy (Order :: customer :: name)
você não pode fazer uma referência método aninhada dessa forma
Kirby
3

Achei essa fonte muito interessante.

De fato, é o Lambda que se transforma em um cólon duplo . O cólon duplo é mais legível. Seguimos essas etapas:

PASSO 1:

// We create a comparator of two persons
Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());

PASSO 2:

// We use the interference
Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());

ETAPA 3:

// The magic using method reference
Comparator c = Comparator.comparing(Person::getAge);
Houssem Badri
fonte
3
Parece que Person::getAge()deveria ser Person::getAge.
Qwertiy
2

return reduce(Math::max);é NOT EQUAL parareturn reduce(max());

Mas isso significa, algo como isto:

IntBinaryOperator myLambda = (a, b)->{(a >= b) ? a : b};//56 keystrokes I had to type -_-
return reduce(myLambda);

Você pode salvar 47 pressionamentos de tecla se escrever assim

return reduce(Math::max);//Only 9 keystrokes ^_^
Jude Niroshan
fonte
2

Como muitas respostas aqui explicam o bom ::comportamento, além disso, gostaria de esclarecer que o :: operador não precisa ter exatamente a mesma assinatura que a Interface Funcional de referência, se for usada para variáveis ​​de instância . Vamos supor que precisamos de um BinaryOperator que tenha o tipo de TestObject . De maneira tradicional, é implementado assim:

BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {

        @Override
        public TestObject apply(TestObject t, TestObject u) {

            return t;
        }
    };

Como você vê na implementação anônima, ele requer dois argumentos TestObject e retorna um objeto TestObject também. Para satisfazer essa condição usando o ::operador, podemos começar com um método estático:

public class TestObject {


    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

e depois chame:

BinaryOperator<TestObject> binary = TestObject::testStatic;

Ok, compilou bem. E se precisarmos de um método de instância? Permite atualizar TestObject com o método de instância:

public class TestObject {

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Agora podemos acessar a instância como abaixo:

TestObject testObject = new TestObject();
BinaryOperator<TestObject> binary = testObject::testInstance;

Esse código compila bem, mas abaixo de um não:

BinaryOperator<TestObject> binary = TestObject::testInstance;

Meu eclipse me diz "Não é possível fazer uma referência estática para o método não estático testInstance (TestObject, TestObject) do tipo TestObject ..."

É justo o método de instância, mas se sobrecarregarmos testInstancecomo abaixo:

public class TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

E ligue para:

BinaryOperator<TestObject> binary = TestObject::testInstance;

O código será compilado corretamente. Porque ele chamará testInstancecom um único parâmetro em vez de um duplo. Ok, então o que aconteceu com nossos dois parâmetros? Permite imprimir e ver:

public class TestObject {

    public TestObject() {
        System.out.println(this.hashCode());
    }

    public final TestObject testInstance(TestObject t){
        System.out.println("Test instance called. this.hashCode:" 
    + this.hashCode());
        System.out.println("Given parameter hashCode:" + t.hashCode());
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Qual saída:

 1418481495  
 303563356  
 Test instance called. this.hashCode:1418481495
 Given parameter hashCode:303563356

Ok, então a JVM é inteligente o suficiente para chamar param1.testInstance (param2). Podemos usar a testInstancepartir de outro recurso, mas não o TestObject, ou seja:

public class TestUtil {

    public final TestObject testInstance(TestObject t){
        return t;
    }
}

E ligue para:

BinaryOperator<TestObject> binary = TestUtil::testInstance;

Ele não será compilado e o compilador dirá: "O tipo TestUtil não define testInstance (TestObject, TestObject)" . Portanto, o compilador procurará uma referência estática se não for do mesmo tipo. Ok, e o polimorfismo? Se removermos os modificadores finais e adicionarmos a classe SubTestObject :

public class SubTestObject extends TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

}

E ligue para:

BinaryOperator<TestObject> binary = SubTestObject::testInstance;

Ele não será compilado também, o compilador ainda procurará por referência estática. Mas o código abaixo será compilado, pois está passando no teste is-a:

public class TestObject {

    public SubTestObject testInstance(Object t){
        return (SubTestObject) t;
    }

}

BinaryOperator<TestObject> binary = TestObject::testInstance;

* Estou apenas estudando, então descobri, tente e veja, sinta-se à vontade para me corrigir se estiver errado

HRgiger
fonte
2

No java-8, o Streams Reducer em trabalhos simples é uma função que recebe dois valores como entrada e retorna o resultado após algum cálculo. esse resultado é alimentado na próxima iteração.

no caso da função Math: max, o método continua retornando no máximo dois valores passados ​​e, no final, você tem o maior número disponível.

Pramod
fonte
1

No tempo de execução, eles se comportam exatamente da mesma maneira.

No tempo de execução, eles se comportam exatamente do mesmo modo. (Math :: max) ;, gera a mesma matemática (cumpra acima e verifique javap -c;))

Alfa khatoon
fonte
1

Nas versões Java mais antigas, em vez de "::" ou lambd, você pode usar:

public interface Action {
    void execute();
}

public class ActionImpl implements Action {

    @Override
    public void execute() {
        System.out.println("execute with ActionImpl");
    }

}

public static void main(String[] args) {
    Action action = new Action() {
        @Override
        public void execute() {
            System.out.println("execute with anonymous class");
        }
    };
    action.execute();

    //or

    Action actionImpl = new ActionImpl();
    actionImpl.execute();
}

Ou passando para o método:

public static void doSomething(Action action) {
    action.execute();
}
Kamil Tomasz Jarmusik
fonte
1

Então , vejo aqui toneladas de respostas que são francamente super complicadas, e isso é um eufemismo.

A resposta é bem simples: :: é chamado de Referências de método https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

Portanto, não copio e colo, no link, você pode encontrar todas as informações se rolar para baixo até a tabela.


Agora, vamos dar uma rápida olhada no que é uma referência de método:

A :: B substitui um pouco a seguinte expressão lambda embutida : (params ...) -> AB (params ...)

Para correlacionar isso com suas perguntas, é necessário entender uma expressão java lambda. O que não é difícil.

Uma expressão lambda embutida é semelhante a uma interface funcional definida (que é uma interface que não possui mais e não menos que 1 método) . Vamos dar uma olhada no que quero dizer:

InterfaceX f = (x) -> x*x; 

InterfaceX deve ser uma interface funcional. Qualquer interface funcional, a única coisa importante sobre o InterfaceX para esse compilador é que você defina o formato:

InterfaceX pode ser qualquer um destes:

interface InterfaceX
{
    public Integer callMe(Integer x);
}

ou isto

interface InterfaceX
{
    public Double callMe(Integer x);
}

ou mais genérico:

interface InterfaceX<T,U>
{
    public T callMe(U x);
}

Vamos pegar o primeiro caso apresentado e a expressão lambda embutida que definimos anteriormente.

Antes do Java 8, você poderia defini-lo da seguinte maneira:

 InterfaceX o = new InterfaceX(){
                     public int callMe (int x, int y) 
                       {
                        return x*x;
                       } };

Funcionalmente, é a mesma coisa. A diferença está mais na maneira como o compilador percebe isso.

Agora que vimos a expressão lambda embutida, vamos retornar às referências de método (: :). Digamos que você tenha uma classe como esta:

class Q {
        public static int anyFunction(int x)
             {
                 return x+5;
             } 
        }

Como o método anyFunctions possui os mesmos tipos que o InterfaceX callMe , podemos equivaler os dois a uma Referência de método.

Podemos escrever assim:

InterfaceX o =  Q::anyFunction; 

e isso é equivalente a isso:

InterfaceX o = (x) -> Q.anyFunction(x);

Uma coisa interessante e a vantagem das referências de método são que, a princípio, até você atribuí-las a variáveis, elas não têm tipo. Assim, você pode passá-los como parâmetros para qualquer interface funcional de aparência equivalente (tem os mesmos tipos definidos). O que é exatamente o que acontece no seu caso

Nertan Lucian
fonte
1

As respostas anteriores são bastante completas sobre o que :: referência de método faz. Para resumir, ele fornece uma maneira de se referir a um método (ou construtor) sem executá-lo e, quando avaliado, cria uma instância da interface funcional que fornece o contexto do tipo de destino.

Abaixo estão dois exemplos para encontrar um objeto com o valor máximo em ArrayListWITH e SEM o uso da ::referência de método. As explicações estão nos comentários abaixo.


SEM o uso de ::

import java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

class ByVal implements Comparator<MyClass> {
    // no need to create this class when using method reference
    public int compare(MyClass source, MyClass ref) {
        return source.getVal() - ref.getVal();
    }
}

public class FindMaxInCol {
    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, new ByVal());
    }
}

Com o uso de ::

import java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

public class FindMaxInCol {
    static int compareMyClass(MyClass source, MyClass ref) {
        // This static method is compatible with the compare() method defined by Comparator. 
        // So there's no need to explicitly implement and create an instance of Comparator like the first example.
        return source.getVal() - ref.getVal();
    }

    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, FindMaxInCol::compareMyClass);
    }
}
Liutong Chen
fonte
-1

O cólon duplo, ou seja, o ::operador é introduzido no Java 8 como uma referência de método . A referência de método é uma forma de expressão lambda usada para referenciar o método existente por seu nome.

classname :: methodName

ex:-

  • stream.forEach(element -> System.out.println(element))

Usando Double Colon ::

  • stream.forEach(System.out::println(element))
ishant kulshreshtha
fonte