:: (dubbele dubbele punt) operator in Java 8

Ik was de Java 8-bron aan het verkennen en vond dit specifieke deel van de code erg verrassend:

//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;
}

Is Math::maxzoiets als een methodeaanwijzer?
Hoe wordt een normale staticmethode geconverteerd naar IntBinaryOperator?


Antwoord 1, autoriteit 100%

Meestal zou men de methode reduceaanroepen met behulp van Math.max(int, int)als volgt:

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

Dat vereist veel syntaxis om gewoon Math.maxaan te roepen. Dat is waar lambda-expressies in het spel komen. Sinds Java 8 is het toegestaan om hetzelfde te doen op een veel kortere manier:

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

Hoe werkt dit? De java-compiler “detecteert”, dat u een methode wilt implementeren die twee ints accepteert en één intretourneert. Dit komt overeen met de formele parameters van de enige echte methode van interface IntBinaryOperator(de parameter van methode reducedie je wilt aanroepen). Dus de compiler doet de rest voor je – hij gaat er gewoon van uit dat je IntBinaryOperatorwilt implementeren.

Maar aangezien Math.max(int, int)zelf voldoet aan de formele vereisten van IntBinaryOperator, kan het direct worden gebruikt. Omdat Java 7 geen syntaxis heeft waarmee een methode zelf als argument kan worden doorgegeven (u kunt alleen methoderesultaten doorgeven, maar nooit methodeverwijzingen), werd de syntaxis ::in Java 8 geïntroduceerd om referentiemethoden:

reduce(Math::max);

Merk op dat dit tijdens runtime door de compiler wordt geïnterpreteerd, niet door de JVM! Hoewel het verschillende bytecodes produceert voor alle drie de codefragmenten, zijn ze semantisch gelijk, dus de laatste twee kunnen worden beschouwd als korte (en waarschijnlijk efficiëntere) versies van de IntBinaryOperator-implementatie hierboven!

(Zie ook Vertaling van Lambda-expressies)


Antwoord 2, autoriteit 49%

::heet Method Reference. Het is in feite een verwijzing naar een enkele methode. d.w.z. het verwijst naar een bestaande methode op naam.

Korte uitleg:
Hieronder ziet u een voorbeeld van een verwijzing naar een statische methode:

class Hey {
     public static double square(double num){
        return Math.pow(num, 2);
    }
}
Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);

squarekan net als objectreferenties worden doorgegeven en indien nodig worden geactiveerd. In feite kan het net zo gemakkelijk worden gebruikt als een verwijzing naar “normale” methoden van objecten als staticmethoden. Bijvoorbeeld:

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);

Functionhierboven is een functionele interface. Om ::volledig te begrijpen, is het ook belangrijk om functionele interfaces te begrijpen. Duidelijk een functionele interfaceis een interface met slechts één abstracte methode.

Voorbeelden van functionele interfaces zijn onder meer Runnable, Callableen ActionListener.

Functionhierboven is een functionele interface met slechts één methode: apply. Er is één argument voor nodig en het levert een resultaat op.


De reden waarom ::s geweldig zijn, is dat:

Methodeverwijzingen zijn expressies die dezelfde behandeling hebben als lambda-expressies (…), maar in plaats van een methode-body te geven, verwijzen ze naar een bestaande methode bij naam.

Bijvoorbeeld in plaats van het lambdalichaam te schrijven

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

Je kunt het gewoon doen

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

Tijdens runtime gedragen deze twee square-methoden zich exact hetzelfde als elkaar. De bytecode kan wel of niet hetzelfde zijn (hoewel in het bovenstaande geval dezelfde bytecode wordt gegenereerd; compileer het bovenstaande en controleer met javap -c).

Het enige belangrijke criterium waaraan moet worden voldaan is: de methode die u opgeeft, moet een soortgelijke handtekening hebben als de methode van de functionele interface die u gebruikt als objectreferentie.

Het onderstaande is illegaal:

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

squareverwacht een argument en retourneert een double. De get-methode in Leverancierretourneert een waarde maar accepteert geen argument. Dit resulteert dus in een fout.

Een methodeverwijzing verwijst naar de methode van een functionele interface.(Zoals gezegd kunnen functionele interfaces elk slechts één methode hebben).

Nog enkele voorbeelden: de methode acceptin Consumentneemt een invoer maar geeft niets terug.

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

Hierboven, getRandomaccepteert geen argument en retourneert een double. Dus elke functionele interface die voldoet aan de criteria van: neem geen argument en retourneer doublekan worden gebruikt.

Nog een voorbeeld:

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

In het geval van geparametriseerde typen:

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;

Methodereferenties kunnen verschillende stijlen hebben, maar in wezen betekenen ze allemaal hetzelfde en kunnen ze eenvoudig worden gevisualiseerd als lambda’s:

  1. Een statische methode (ClassName::methName)
  2. Een instantiemethode van een bepaald object (instanceRef::methName)
  3. Een supermethode van een bepaald object (super::methName)
  4. Een instantiemethode van een willekeurig object van een bepaald type (ClassName::methName)
  5. A Class Constructor Reference (ClassName::new)
  6. Een array-constructorreferentie (TypeName[]::new)

Zie http: // cr. OpenJDK.JAVA.net/~BRIANGOETZ/LAMBDA/LAMBDA-STATE-FINAL.HTML .


Antwoord 3, Autoriteit 5%

Ja, dat is waar. De ::Operator wordt gebruikt voor de methode referenties. Dus, men kan statisch methoden uit klassen extraheren door deze of methoden van objecten te gebruiken. Dezelfde operator kan zelfs voor constructeurs worden gebruikt. Alle hier genoemde gevallen zijn ondertekend in het onderstaande codemonster.

De officiële documentatie van Oracle is te vinden hier .

U kunt een beter overzicht hebben van de JDK 8-wijzigingen in dit -artikel. In de -methode / constructeur referenties sectie is ook een codevoorbeeld verstrekt:

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);
   }
}

Antwoord 4, Autoriteit 3%

Het lijkt het weinig laat, maar hier zijn mijn twee cent. A Lambda-expressie wordt gebruikt om anonieme methoden te maken. Het doet niets anders dan een bestaande methode, maar het is duidelijker om door de naam rechtstreeks naar de methode te verwijzen. En Methode Referentie stelt ons in staat om dat te doen met behulp van methode-referentie-operator ::.

Overweeg de volgende eenvoudige klasse waarbij elke medewerker een naam en cijfer heeft.

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;
    }
}

Stel dat we een lijst met werknemers hebben die zijn geretourneerd door een methode en we willen de werknemers sorteren op hun cijfer. We weten dat we gebruik kunnen maken van anonieme klasse als:

   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());
           }
    });

waarbij getDummyEmployee() een methode is als:

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")
                );
    }

Nu weten we dat Comparatoreen functionele interface. Een functionele interfaceis degene met precies één abstracte methode (hoewel deze een of meer standaard- of statische methoden kan bevatten). Lambda-expressie biedt implementatie van @FunctionalInterface, zodat een functionele interface slechts één abstracte methode kan hebben. We kunnen lambda-expressie gebruiken als:

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

Het lijkt allemaal goed, maar wat als de klasse Employeeook een vergelijkbare methode biedt:

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);
    }
}

In dit geval is het duidelijker om de naam van de methode zelf te gebruiken. Daarom kunnen we rechtstreeks naar methode verwijzen door methodeverwijzing te gebruiken als:

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

Volgens docszijn er vier soorten methodeverwijzingen :

+----+-------------------------------------------------------+--------------------------------------+
|    | 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                       |
+------------------------------------------------------------+--------------------------------------+

Antwoord 5, autoriteit 3%

::is een nieuwe operator in Java 8 die wordt gebruikt om naar een methode van een bestaande klasse te verwijzen. Je kunt verwijzen naar statische methoden en niet-statische methoden van een klasse.

Voor het verwijzen naar statische methoden is de syntaxis:

ClassName :: methodName 

Voor het verwijzen naar niet-statische methoden is de syntaxis

objRef :: methodName

En

ClassName :: methodName 

De enige voorwaarde voor het verwijzen van een methode is dat die methode bestaat in een functionele interface, die compatibel moet zijn met de methodeverwijzing.

Methodeverwijzingen creëren, wanneer geëvalueerd, een instantie van de functionele interface.

Gevonden op: http://www.spokecs.com/2014/ 08/method-references-in-java-8.html


Antwoord 6, autoriteit 2%

Dit is een methodeverwijzing in Java 8. De Oracle-documentatie is hier .

Zoals vermeld in de documentatie…

De methodereferentie Person::compareByAge is een verwijzing naar een statische
methode.

Het volgende is een voorbeeld van een verwijzing naar een instantiemethode van a
bepaald object:

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); 

De methodeverwijzing myComparisonProvider::compareByName roept de methode CompareByName op
dat is onderdeel van het object myComparisonProvider. De JRE leidt daaruit af dat de
methode type argumenten, in dit geval (Persoon, Persoon).


Antwoord 7

:: Operatoris geïntroduceerd in Java 8 voor methodereferenties. Een methodeverwijzing is de verkorte syntaxis voor een lambda-expressie die slechts EEN methode uitvoert. Hier is de algemene syntaxis van een methodeverwijzing:

Object :: methodName

We weten dat we lambda-expressieskunnen gebruiken in plaats van een anonieme klas gebruiken. Maar soms is de lambda-expressie eigenlijk gewoon een aanroep van een methode, bijvoorbeeld:

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

Om de code duidelijker te maken, kun je die lambda-expressie omzetten in een methodereferentie:

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

Antwoord 8

De :: staat bekend als methodereferenties. Laten we zeggen dat we een methode berekenPrice van de klasse Aankoop willen aanroepen. Dan kunnen we het schrijven als:

Purchase::calculatePrice

Het kan ook worden gezien als een korte vorm van het schrijven van de lambda-expressie, omdat methodeverwijzingen worden omgezet in lambda-expressies.


Antwoord 9

Ik vond deze bronerg interessant.

In feite is het de Lambdadie verandert in een Dubbele dubbele punt.
De dubbele dubbele punt is beter leesbaar.
We volgen die stappen:

STAP1:

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

STAP2:

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

STAP3:

// The magic using method reference
Comparator c = Comparator.comparing(Person::getAge);

Antwoord 10

Dus Ik zie hier talloze antwoorden die eerlijk gezegd te ingewikkeld zijn, en dat is een understatement.

Het antwoord is vrij eenvoudig: :: het heet een Method Referenceshttps://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

Dus ik zal niet kopiëren en plakken, op de link kun je alle informatie vinden als je naar de tabel scrolt.


Laten we nu even kijken naar wat een methodereferentie is:

A::benigszinsvervangt de volgende inline lambda-expressie: (params …) -> A.b(params …)

Om dit te correleren met uw vragen, is het noodzakelijk om een Java lambda-expressie te begrijpen. Wat niet moeilijk is.

Een inline lambda-expressie is vergelijkbaar met een gedefinieerdefunctionele interface (een interface die niet meer en niet minder dan 1 methode heeft).
Laten we even kijken wat ik bedoel:

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

InterfaceX moet een functionele interface zijn. Elke functionele interface, het enige wat belangrijk is aan InterfaceX voor die compiler is dat je het formaat definieert:

InterfaceX kan dit allemaal zijn:

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

of dit

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

of algemener:

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

Laten we de eerste casus nemen en de inline lambda-expressie die we eerder hebben gedefinieerd.

Vóór Java 8 had je het op dezelfde manier kunnen definiëren:

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

Functioneel gezien is het hetzelfde. Het verschil zit hem meer in hoe de compiler dit waarneemt.

Nu we de inline lambda-expressie hebben bekeken, gaan we terug naar Method References (::). Laten we zeggen dat je een klas als deze hebt:

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

Aangezien de methode Anyfunctions dezelfde typen heeft als Interfacx CallMe , kunnen we die twee equivaleren met een methode-referentie.

We kunnen het als volgt schrijven:

InterfaceX o =  Q::anyFunction; 

en dat is overeen met dit:

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

Een cool ding en voordeel van methode-referenties zijn dat in eerste instantie totdat u ze aan variabelen toewijst, typeert u typisch. U kunt ze dus passeren als parameters voor een equivalent uitziende (heeft dezelfde gedefinieerde typen) functionele interface. Wat precies is wat er in uw zaak gebeurt


Antwoord 11

return reduce(Math::max);is niet gelijk op return reduce(max());

Maar het betekent, zoiets als volgt:

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

U kunt slechts 47 toetsaanslagen beslaan Als u dit als deze schrijft

return reduce(Math::max);//Only 9 keystrokes ^_^

Antwoord 12

Aangezien veel antwoorden hier het gedrag van ::goed hebben uitgelegd, zou ik bovendien willen verduidelijken dat de ::operator niet exact dezelfde handtekening hoeft te hebben als de verwijzende Functionele interface als deze bijvoorbeeld wordt gebruikt voor variabelen. Laten we aannemen dat we een BinaryOperatornodig hebben die het type TestObjectheeft. Op de traditionele manier wordt het als volgt geïmplementeerd:

BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {
        @Override
        public TestObject apply(TestObject t, TestObject u) {
            return t;
        }
    };

Zoals je ziet in anonieme implementatie vereist het twee TestObject-argumenten en retourneert het ook een TestObject-object. Om aan deze voorwaarde te voldoen door de operator ::te gebruiken, kunnen we beginnen met een statische methode:

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

en bel dan:

BinaryOperator<TestObject> binary = TestObject::testStatic;

Ok, het is goed gecompileerd. Hoe zit het als we een instantiemethode nodig hebben? Laten we TestObject updaten met de instantiemethode:

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

Nu hebben we toegang tot exemplaar zoals hieronder:

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

Deze code compileert prima, maar onder één niet:

BinaryOperator<TestObject> binary = TestObject::testInstance;

Mijn Eclipse vertel me “kan geen statische verwijzing doen naar de niet-statische methode-testinstantie (TestObject, TestObject) van het type TestObject …”

Eerlijk genoeg is het een instantie-methode, maar als we overbelasten testInstancezoals hieronder:

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;
    }
}

en bel:

BinaryOperator<TestObject> binary = TestObject::testInstance;

De code compileert gewoon prima. Omdat het testInstancemet één parameter zal bellen in plaats van dubbele. Oké, wat gebeurde er met onze twee parameter? Laat afdrukken en zie:

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;
    }
}

Wat zal het volgende opleveren:

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

Ok, dus JVM is slim genoeg om param1.testInstance(param2) aan te roepen. Kunnen we testInstancevan een andere bron gebruiken, maar niet TestObject, d.w.z.:

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

En bel:

BinaryOperator<TestObject> binary = TestUtil::testInstance;

Het compileert gewoon niet en de compiler zegt: “Het type TestUtil definieert testInstance(TestObject, TestObject) niet”. De compiler zoekt dus naar een statische referentie als deze niet van hetzelfde type is. Oké, hoe zit het met polymorfisme? Als we de laatste modifiers verwijderen en onze klasse SubTestObjecttoevoegen:

public class SubTestObject extends TestObject {
    public final TestObject testInstance(TestObject t){
        return t;
    }
}

En bel:

BinaryOperator<TestObject> binary = SubTestObject::testInstance;

Het compileert niet zo goed, de compiler zoekt nog steeds naar statische referentie. Maar onderstaande code zal prima compileren omdat het een test doorstaat:

public class TestObject {
    public SubTestObject testInstance(Object t){
        return (SubTestObject) t;
    }
}
BinaryOperator<TestObject> binary = TestObject::testInstance;

*Ik ben net aan het studeren, dus ik ben erachter gekomen door te proberen en te zien, corrigeer me gerust als ik het mis heb


Antwoord 13

In java-8 is Streams Reducer in eenvoudige werken een functie die twee waarden als invoer neemt en na enige berekening het resultaat oplevert. dit resultaat wordt in de volgende iteratie ingevoerd.

in het geval van de functie Math:max, blijft de methode het maximum van twee doorgegeven waarden retourneren en uiteindelijk heb je het grootste aantal in de hand.


Antwoord 14

In oudere Java-versies kunt u in plaats van “::” of lambd het volgende gebruiken:

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();
}

Of doorgeven aan de methode:

public static void doSomething(Action action) {
    action.execute();
}

Antwoord 15

De dubbele dubbele punt (::) operator, in Java ook wel methode-referentie-operator genoemd, wordt gebruikt om een methode aan te roepen door ernaar te verwijzen met behulp van zijn klasse. Ze gedragen zich precies zoals de lambda-uitdrukkingen. Het enige verschil met lambda-expressies is dat dit een directe verwijzing naar de methode op naam gebruikt in plaats van een gemachtigde voor de methode te geven.

Syntaxis:

<Class name>::<method name>

Dit symbool kan worden gebruikt in plaats van Lamda-uitdrukkingen

Programma:

// Java code to print the elements of Stream
// without using double colon operator
import java.util.stream.*;
class MyClass {
    public static void main(String[] args)
    {
        // Get the stream
        Stream<String> stream
            = Stream.of("Testing","Program");
        // Print the stream
        stream.forEach(s -> System.out.println(s));
    }
}

Uitvoer:

Testing
Program

De regel stream.forEach(s -> System.out.println(s));kan worden vervangen door

stream.forEach(System.out::println);

Ook de eerste methode wordt meestal gebruikt tijdens het programmeren.


Antwoord 16

Tijdens runtime gedragen ze zich exact hetzelfde. De bytecode kan wel/niet hetzelfde zijn (Voor bovenstaande Incase genereert het dezelfde bytecode (vul hierboven in en controleer javaap -c;))

Tijdens runtime gedragen ze zich exact hetzelfde.methode(math::max);,het genereert dezelfde wiskunde (vul hierboven in en controleer javap -c;))


Antwoord 17

De vorige antwoorden zijn vrij compleet met betrekking tot wat ::Method-referentie doet. Om samen te vatten, biedt het een manier om te verwijzen naar een methode (of constructor) zonder het uit te voeren, en wanneer geëvalueerd, maakt het een exemplaar van de functionele interface die de context Target Type biedt.

Hieronder staan ​​twee voorbeelden om een ​​object te vinden met de maximale waarde in een ArrayListmet en zonder het gebruik van ::methode-referentie. Verklaringen zijn in de onderstaande opmerkingen.


Zonder het gebruik van ::

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());
    }
}

Met het gebruik van ::

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);
    }
}

Antwoord 18

Double Colon I.E. ::Operator wordt geïntroduceerd in Java 8 als een methode-referentie . Methode Referentie is een vorm van Lambda-expressie die wordt gebruikt om de bestaande methode door de naam te verwijzen.

ClassName :: MethodName

ex: –

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

Met behulp van Double Colon ::

  • stream.forEach(System.out::println(element))

Other episodes