:: (ද්විත්ව බඩවැල්) ජාවා 8 හි ක්‍රියාකරු


966

මම ජාවා 8 ප්‍රභවය ගවේෂණය කරමින් සිටියදී කේතයේ මෙම විශේෂිත කොටස ඉතා පුදුම සහගත විය:

//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::maxක්රමයක් පෙන්නුම් කරන්නක් වගේ දෙයක්? සාමාන්‍ය staticක්‍රමයක් බවට පරිවර්තනය වන්නේ IntBinaryOperatorකෙසේද?


60
ඔබ සපයන ශ්‍රිතය මත පදනම්ව සම්පාදක ස්වයංක්‍රීයව ජනනය කරන අතුරු මුහුණත් ක්‍රියාත්මක කිරීම සින්ටැක්ටික් සීනි වේ (මුළු ලැම්බඩා දේම පවතින කේත පදනම් සමඟ භාවිතා කිරීම පහසු කිරීම සඳහා).
නීට්

4
java.dzone.com/articles/java-lambda-expressions-vs උදව් විය හැකිය, මාතෘකාව ගැන ගැඹුරින් සොයා බැලුවේ නැත
පොන්ටස් බැක්ලන්ඩ්

8
ඔබට අවශ්‍ය දේ සඳහා කිව නොහැකි නම් එය හරියටම “සින්ටැක්ටික් සීනි” නොවේ. එනම් "x යනු y සඳහා සින්ටැක්ටික් සීනි" යන්නයි.
ඉන්ගෝ

6
N ඉන්ගෝ එය මම භාවිතා කරන සෑම අවස්ථාවකම ලැම්බඩා නව වස්තුවක් නිර්මාණය කරයි. TestingLambda$$Lambda$2/8460669හා TestingLambda$$Lambda$3/11043253යාතිකා දෙකක් මත නිර්මාණය කරන ලදී.
නරේන්ද්‍ර පාතායි

14
ලැම්බඩාස් සහ ක්‍රම යොමු කිරීම් “සරල පැරණි නිර්නාමික අභ්‍යන්තර පන්ති” නොවේ. Programmmers.stackexchange.com/a/181743/59134 බලන්න . ඔව්, අවශ්‍ය නම්, නව පන්ති සහ අවස්ථා පියාසර කරන විට, අවශ්‍ය නම්, නමුත් අවශ්‍ය නම් පමණි.
ස්ටුවර්ට් මාර්ක්ස්

Answers:


1031

සාමාන්‍යයෙන් යමෙක් පහත දැක්වෙන reduceක්‍රමය භාවිතා Math.max(int, int)කරයි.

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

ඒ සඳහා හුදෙක් ඇමතුම් සඳහා සින්ටැක්ස් විශාල ප්‍රමාණයක් අවශ්‍ය වේ Math.max. ලැම්බඩා ප්‍රකාශන ක්‍රියාත්මක වන්නේ එතැනිනි. ජාවා 8 සිට එකම දේ වඩා කෙටි ආකාරයකින් කිරීමට අවසර ඇත:

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

කොහොමද මේ වැඩ කරන්නේ? ජාවා සම්පාදකයා "හඳුනා ගනී", ඔබට ints දෙකක් පිළිගෙන එකක් ආපසු ලබා දෙන ක්‍රමයක් ක්‍රියාත්මක කිරීමට අවශ්‍ය බව int. මෙය එකම සහ එකම අතුරු මුහුණතේ විධිමත් පරාමිතීන්ට සමාන වේ IntBinaryOperator( reduceඔබට ඇමතීමට අවශ්‍ය ක්‍රමයේ පරාමිතිය ). එබැවින් සම්පාදකයා ඔබ වෙනුවෙන් ඉතිරි දේ කරයි - එය ඔබට ක්‍රියාත්මක කිරීමට අවශ්‍ය යැයි උපකල්පනය කරයි IntBinaryOperator.

නමුත් Math.max(int, int)විධිමත් අවශ්‍යතා සපුරාලන බැවින් IntBinaryOperatorඑය කෙලින්ම භාවිතා කළ හැකිය. ජාවා 7 හි කිසිදු වාක්‍ය ඛණ්ඩයක් නොමැති බැවින් ක්‍රමවේදයක් තර්කයක් ලෙස සම්මත කිරීමට ඉඩ සලසයි (ඔබට ක්‍රම ප්‍රති results ල පමණක් ලබා දිය හැකිය, නමුත් කිසි විටෙකත් ක්‍රම යොමු යොමු නොවේ), ::සින්ටැක්ස් ජාවා 8 හි යොමු ක්‍රම සඳහා හඳුන්වා දෙන ලදී:

reduce(Math::max);

මෙය පරිවර්ථනය කරනු ලබන්නේ ධාවන වේලාවේදී ජේවීඑම් විසින් නොව සම්පාදකයා විසිනි! එය කේත ස්නිපෙට් තුන සඳහාම විවිධ බයිට් කේත නිපදවුවද, ඒවා අර්ථාන්විතව සමාන වේ, එබැවින් අවසාන දෙක IntBinaryOperatorඉහත ක්‍රියාත්මක කිරීමේ කෙටි (හා බොහෝ විට වඩා කාර්යක්ෂම) අනුවාද ලෙස සැලකිය හැකිය !

( ලැම්බඩා ප්‍රකාශනවල පරිවර්තනයද බලන්න )


497

::ක්‍රමය යොමු කිරීම ලෙස හැඳින්වේ. එය මූලික වශයෙන් තනි ක්‍රමයකට යොමු කිරීමකි. එනම් එය දැනට පවතින ක්‍රමවේදයක් නමින් හැඳින්වේ.

කෙටි පැහැදිලි කිරීම :
ස්ථිතික ක්‍රමයක් පිළිබඳ සඳහනක් පහත දැක්වේ:

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

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

squareවස්තු යොමු කිරීම් මෙන් ගමන් කළ හැකි අතර අවශ්‍ය විටදී එය අවුලුවන. ඇත්ත වශයෙන්ම, එය වස්තූන්ගේ “සාමාන්‍ය” ක්‍රම වෙත යොමු කිරීමක් ලෙස පහසුවෙන් භාවිතා කළ හැකිය static. උදාහරණයක් වශයෙන්:

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

Functionඉහත ක්‍රියාකාරී අතුරුමුහුණතකි . සම්පූර්ණයෙන් වටහා ::ගැනීම සඳහා ක්‍රියාකාරී අතුරුමුහුණත් තේරුම් ගැනීම වැදගත්ය. පැහැදිලිවම, ක්‍රියාකාරී අතුරුමුහුණතක් යනු එක් වියුක්ත ක්‍රමයක් සහිත අතුරු මුහුණතකි.

ක්රියාකාරී අතුරු මුහුණත් උදාහරණ ඇතුළත් Runnable, Callableහා ActionListener.

Functionඉහත දැක්වෙන්නේ එක් ක්‍රමයක් පමණක් සහිත ක්‍රියාකාරී අතුරුමුහුණතකි : apply. එය එක් තර්කයක් ගෙන ප්‍රති .ලයක් ලබා දෙයි.


හේතුව ::ගේ දවසක් වන්නේ බව :

ක්‍රම යොමු යනු ලැම්බඩා ප්‍රකාශන (...) හා සමාන ප්‍රතිකාරයක් වන ප්‍රකාශන වේ, නමුත් ක්‍රමවේදය ශරීරයක් ලබා දෙනවා වෙනුවට, පවතින ක්‍රමයක් නමින් හඳුන්වයි.

උදා: ලැම්බඩා ශරීරය ලිවීම වෙනුවට

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

ඔබට සරලව කළ හැකිය

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

ධාවන වේලාවේදී, මෙම squareක්‍රම දෙක එකිනෙකට සමාන ලෙස හැසිරේ. බයිට් කේතය එක හා සමාන විය හැකිය (කෙසේ වෙතත්, ඉහත අවස්ථාව සඳහා එකම බයිට් කේතය ජනනය වේ; ඉහත සම්පාදනය කර පරීක්ෂා කරන්න javap -c).

තෘප්තිමත් කිරීමට ඇති එකම ප්‍රධාන නිර්ණායකය: ඔබ සපයන ක්‍රමයට ඔබ වස්තු යොමු කිරීමක් ලෙස භාවිතා කරන ක්‍රියාකාරී අතුරුමුහුණතේ ක්‍රමයට සමාන අත්සනක් තිබිය යුතුය .

පහත දැක්වෙන්නේ නීති විරෝධී ය:

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

squareතර්කයක් අපේක්ෂා කරන අතර a double. මෙම getපාලන ක්රමය සැපයුම්කරු අගය නැවත නමුත් තර්කයක් ගත වන්නේ නැත. මේ අනුව, මෙය දෝෂයක් ඇති කරයි.

ක්‍රම යොමු කිරීමක් යනු ක්‍රියාකාරී අතුරු මුහුණතක ක්‍රමයයි. (සඳහන් කළ පරිදි, ක්‍රියාකාරී අතුරුමුහුණත් සඳහා තිබිය හැක්කේ එක් ක්‍රමයක් පමණි).

තවත් උදාහරණ කිහිපයක්: පාරිභෝගිකයාගේaccept ක්‍රමය ආදානයක් ගන්නා නමුත් කිසිවක් ආපසු නොදේ.

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

ඉහත, getRandomකිසිදු තර්කයක් ගෙන ආපසු a double. එබැවින් පහත දැක්වෙන නිර්ණායකයන් සපුරාලන ඕනෑම ක්‍රියාකාරී අතුරු මුහුණතක්: කිසිදු තර්කයක් ගෙන ආපසු පැමිණීමdouble භාවිතා කළ නොහැක.

තවත් උදාහරණයක්:

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

පරාමිතිගත වර්ග වලදී :

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;

ක්‍රම යොමුවලට විවිධ මෝස්තර තිබිය හැකි නමුත් මූලික වශයෙන් ඒවා සියල්ලම එකම දෙය වන අතර ලැම්බඩා ලෙස දෘශ්‍යමාන කළ හැකිය:

  1. ස්ථිතික ක්‍රමයක් ( ClassName::methName)
  2. විශේෂිත වස්තුවක නිදර්ශන ක්‍රමයක් ( instanceRef::methName)
  3. විශේෂිත වස්තුවක සුපිරි ක්‍රමයක් ( super::methName)
  4. විශේෂිත වර්ගයක අත්තනෝමතික වස්තුවක නිදර්ශන ක්‍රමය ( ClassName::methName)
  5. පන්ති ඉදිකිරීම්කරුවන්ගේ යොමුව ( ClassName::new)
  6. අරාව සාදන්නාගේ යොමුව ( TypeName[]::new)

වැඩි විස්තර සඳහා, http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html බලන්න .


6
පැහැදිලි කිරීම සඳහා ස්තූතියි. සාරාංශයක් ලෙස: '::' ක්‍රියාකාරී ඉන්ටර්ෆේස් (ලැම්බඩා) තෘප්තිමත් කරන ක්‍රමයක් උපුටා ගැනීම සඳහා භාවිතා කරන්න: ClassX :: staticMethodX, හෝ instanceX :: instanceMethodX "
jessarah

55

ඔව්, එය සත්‍යයකි. මෙම ::ක්රියාකරු ක්රමය පිලිබඳව සඳහන් කිරීම සඳහා භාවිතා කරනු ලබයි. එබැවින් කෙනෙකුට පන්ති වලින් ස්ථිතික ක්‍රම හෝ වස්තූන්ගෙන් ක්‍රම උපුටා ගත හැකිය. එකම ක්රියාකරු ඉදිකිරීම්කරුවන් සඳහා පවා භාවිතා කළ හැකිය. මෙහි සඳහන් සියලුම සිද්ධීන් පහත කේත නියැදියෙන් නිදර්ශනය කර ඇත.

ඔරකල් වෙතින් නිල ලියකියවිලි මෙතැනින් සොයාගත හැකිය .

මෙම ලිපියේ JDK 8 වෙනස්කම් පිළිබඳව ඔබට වඩා හොඳ දළ විශ්ලේෂණයක් ලබා ගත හැකිය . තුළ ක්රමය / ඉදිකිරීම් පිලිබඳව සඳහන් කොටස කේතය උදාහරණයක් ද සපයනු ලැබේ:

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

හොඳ පැහැදිලි කිරීමක් මෙහි සොයාගත හැකිය: doanduyhai.wordpress.com/2012/07/14/…
ඔලිම්පියු පොප්

1
Ic රිචාර්ඩ්ටිංගල් method(Math::max);යනු ආයාචනයක් වන අතර ක්‍රමවේදය අර්ථ දැක්වීම සමාන public static void method(IntBinaryOperator op){System.out.println(op.applyAsInt(1, 2));}වේ. එය භාවිතා කළ ආකාරය එයයි.
නරේන්ද්‍ර පාතායි

2
C # හුරුපුරුදු අයට එය DelegateType d = new DelegateType (MethodName) සමඟ සමාන වේ;
ඒඩ්‍රියන් සනෙස්කු

27

එය ටිකක් ප්‍රමාද බව පෙනේ, නමුත් මෙන්න මගේ ශත දෙකයි. නිර්නාමික ක්‍රම නිර්මාණය කිරීම සඳහා ලැම්බඩා ප්‍රකාශනයක් භාවිතා කරයි. එය දැනට පවතින ක්‍රමවේදයක් ඇමතීම හැර වෙන කිසිවක් නොකරයි, නමුත් ක්‍රමයට එහි නමෙන් කෙලින්ම යොමු කිරීම වඩාත් පැහැදිලිය. හා ක්රමය සඳහන් ක්රමය-යොමු ක්රියාකරු භාවිතා ඒක කරන්න අපට හැකි ::.

සෑම සේවකයෙකුටම නමක් සහ ශ්‍රේණියක් ඇති පහත සරල පන්තිය සලකා බලන්න.

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

කිසියම් ක්‍රමවේදයකින් ආපසු ලබා දුන් සේවකයින්ගේ ලැයිස්තුවක් අප සතුව ඇතැයි සිතමු. සේවකයින් ඔවුන්ගේ ශ්‍රේණිය අනුව වර්ග කිරීමට අපට අවශ්‍යය. නිර්නාමික පංතිය අපට භාවිතා කළ හැකි බව අපි දනිමු :

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

getDummyEmployee () යනු පහත දැක්වෙන ක්‍රමයකි:

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

සංසන්දකයා යනු ක්‍රියාකාරී අතුරුමුහුණතක් බව දැන් අපි දනිමු . ඒ ක්රියාකාරී අතුරුමුහුණත හරියටම එක් වියුක්ත ක්රමය (එය එකක් හෝ ඊට වැඩි පෙරනිමි හෝ ස්ථිතික ක්රම අඩංගු විය හැකිය නමුත්) සමග එක් වේ. ලැම්බඩා ප්‍රකාශනය ක්‍රියාත්මක කිරීම @FunctionalInterfaceමඟින් ක්‍රියාකාරී අතුරු මුහුණතකට තිබිය හැක්කේ එක් වියුක්ත ක්‍රමයක් පමණි. අපට ලැම්බඩා ප්‍රකාශනය පහත පරිදි භාවිතා කළ හැකිය:

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

එය සියල්ලම හොඳ බව පෙනේ, නමුත් පන්තිය Employeeද ඒ හා සමාන ක්‍රමයක් සපයන්නේ නම් :

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

මෙම අවස්ථාවේ දී ක්‍රමයේ නම භාවිතා කිරීම වඩාත් පැහැදිලි වනු ඇත. එබැවින් ක්‍රමවේදය යොමු කිරීම මඟින් අපට ක්‍රමයට සෘජුවම යොමු විය හැකිය:

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

අනුව ලේඛන ක්රමය යොමු වර්ග හතරක් ඇත:

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

26

::යනු ජාවා 8 හි ඇතුළත් කර ඇති නව ක්‍රියාකරු වන අතර එය දැනට පවතින පන්තියක ක්‍රමයක් යොමු කිරීමට භාවිතා කරයි. ඔබට පන්තියක ස්ථිතික ක්‍රම සහ ස්ථිතික නොවන ක්‍රම යොමු කළ හැකිය.

ස්ථිතික ක්‍රම යොමු කිරීම සඳහා, වාක්‍ය ඛණ්ඩය:

ClassName :: methodName 

ස්ථිතික නොවන ක්‍රම යොමු කිරීම සඳහා, වාක්‍ය ඛණ්ඩය වේ

objRef :: methodName

සහ

ClassName :: methodName

ක්‍රමයක් යොමු කිරීම සඳහා ඇති එකම පූර්වාවශ්‍යතාවය නම්, ක්‍රියාකාරී අතුරුමුහුණතක් තුළ එම ක්‍රමය පවතින අතර එය ක්‍රම යොමුව සමඟ අනුකූල විය යුතුය.

ක්‍රම යොමු කිරීම්, ඇගයීමේදී, ක්‍රියාකාරී අතුරුමුහුණතේ උදාහරණයක් සාදන්න.

හමු වූයේ: http://www.speakingcs.com/2014/08/method-references-in-java-8.html


22

මෙය ජාවා 8 හි ක්‍රමවේද යොමු කිරීමකි. ඔරකල් ප්‍රලේඛනය මෙහි ඇත.

ප්‍රලේඛනයේ සඳහන් පරිදි ...

ක්‍රමවේදය යොමු පුද්ගලයා පුද්ගලයා :: සංසන්දනය කිරීම යනු ස්ථිතික ක්‍රමයකට යොමු කිරීමකි.

පහත දැක්වෙන්නේ කිසියම් වස්තුවක නිදර්ශන ක්‍රමයකට යොමු කිරීමකි.

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

ක්‍රමවේදය යොමු කිරීම myComparisonProvider :: compareByName myComparisonProvider වස්තුවේ කොටසක් වන සංසන්දනාත්මක බයිනෙම් ක්‍රමය භාවිතා කරයි. JRE විසින් ක්‍රමයේ වර්ගයේ තර්ක විතර්ක කරයි, මේ අවස්ථාවේ දී (පුද්ගලයා, පුද්ගලයා).


2
නමුත් 'සංසන්දනය කරන්න' ක්‍රමය ස්ථිතික නොවේ.
අබ්බාස්

3
ඇබ්බාස් නොර් සංසන්දනය බයිනාම් නොවේ. එබැවින්, ඔබ මෙම ස්ථිතික නොවන ක්‍රම වෙත යොමු වන්නේ වස්තුවක් භාවිතා කරමින් විමර්ශන ක්‍රියාකරු හරහා ය. ඒවා ස්ථිතික නම්, ඔබට ComparisionProvider :: someStaticMethod
R

6

:: ක්‍රමවේදය සඳහා ජාවා 8 හි ක්‍රියාකරු හඳුන්වා දෙන ලදි. ක්‍රම යොමු කිරීමක් යනු ලැම්බඩා ප්‍රකාශනයක් සඳහා වූ කෙටිමං වාක්‍ය ඛණ්ඩයයි. ක්‍රම යොමුවක සාමාන්‍ය වාක්‍ය ඛණ්ඩය මෙන්න:

Object :: methodName

නිර්නාමික පංතියක් භාවිතා කිරීම වෙනුවට අපට ලැම්බඩා ප්‍රකාශන භාවිතා කළ හැකි බව අපි දනිමු . නමුත් සමහර විට, ලැම්බඩා ප්‍රකාශනය ඇත්ත වශයෙන්ම යම් ක්‍රමයකට කැඳවීමක් පමණි, උදාහරණයක් ලෙස:

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

කේතය වඩාත් පැහැදිලි කිරීම සඳහා, ඔබට එම ලැම්බඩා ප්‍රකාශනය ක්‍රම යොමු කිරීමක් බවට පත් කළ හැකිය:

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

3

:: :: ක්‍රම යොමු ලෙස හැඳින්වේ. පංති මිලදී ගැනීමේ ගණනය කිරීමේ ක්‍රමයක් ලෙස හැඳින්වීමට අපට අවශ්‍ය යැයි කියමු. එවිට අපට එය මෙසේ ලිවිය හැකිය:

Purchase::calculatePrice

එය ලැම්බඩා ප්‍රකාශනය ලිවීමේ කෙටි ආකාරයක් ලෙස ද දැකිය හැකිය. මන්දයත් ක්‍රම යොමු කිරීම් ලැම්බඩා ප්‍රකාශන බවට පරිවර්තනය වන බැවිනි.


මට කැදැලි ක්‍රම යොමු කළ හැකිද? උදා:

ඔබට ඒ ආකාරයෙන් කැදැලි ක්‍රමයක් යොමු කළ නොහැක
කිරිබි

3

මෙම මූලාශ්‍රය ඉතා සිත්ගන්නා සුළු බව මට පෙනී ගියේය.

ඇත්ත වශයෙන්ම, ද්විත්ව කොලොන් බවට හැරෙන්නේ ලැම්බඩා ය . ඩබල් කොලෝන් වඩාත් කියවිය හැකිය. අපි එම පියවර අනුගමනය කරමු:

පියවර 1:

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

පියවර 2:

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

පියවර 3:

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

3
පෙනෙන ආකාරයට Person::getAge()විය යුතුය Person::getAge.
ක්වෙර්ටි

2

return reduce(Math::max);වන සමාන නොවන කිරීමටreturn reduce(max());

නමුත් එයින් අදහස් වන්නේ, මේ වගේ දෙයක්:

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

ඔබ මේ ආකාරයට ලිවුවහොත් ඔබට යතුරු එබීම් 47 ක් ඉතිරි කළ හැකිය

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

2

මෙහි බොහෝ පිළිතුරු හොඳින් ::හැසිරීම පැහැදිලි :: කර ඇති හෙයින්, උදාහරණ විචල්‍යයන් සඳහා භාවිතා කරන්නේ නම් ක්‍රියාකරුට යොමු කිරීමේ ක්‍රියාකාරී අතුරුමුහුණතට සමාන අත්සනක් අවශ්‍ය නොවන බව පැහැදිලි කිරීමට මම කැමැත්තෙමි . ටෙස්ට් ඕබෙක්ට් වර්ගයක් ඇති ද්විමය ක්‍රියාකරු අපට අවශ්‍ය යැයි උපකල්පනය කරමු . සාම්ප්‍රදායික ආකාරයෙන් එය ක්‍රියාත්මක වන්නේ මේ ආකාරයට ය:

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

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

            return t;
        }
    };

ඔබ නිර්නාමික ක්‍රියාත්මක කිරීමේදී දකින පරිදි එයට TestObject තර්කයක් දෙකක් අවශ්‍ය වන අතර TestObject වස්තුවක් ද ලබා දෙයි. ::ක්රියාකරු භාවිතා කිරීමෙන් මෙම තත්වය තෘප්තිමත් කිරීම සඳහා අපට ස්ථිතික ක්රමයක් සමඟ ආරම්භ කළ හැකිය:

public class TestObject {


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

ඉන්පසු අමතන්න:

BinaryOperator<TestObject> binary = TestObject::testStatic;

හරි එය හොඳින් සම්පාදනය කළා. අපට නිදර්ශන ක්‍රමයක් අවශ්‍ය නම් කුමක් කළ යුතුද? උදාහරණ ක්‍රමය සමඟ TestObject යාවත්කාලීන කිරීමට ඉඩ දෙන්න:

public class TestObject {

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

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

දැන් අපට පහත උදාහරණයට ප්‍රවේශ විය හැකිය:

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

මෙම කේතය හොඳින් සම්පාදනය කරයි, නමුත් එකකට වඩා අඩු නොවේ:

BinaryOperator<TestObject> binary = TestObject::testInstance;

මගේ සූර්යග්‍රහණය මට පවසන්නේ "ටෙස්ට් ඕබෙක්ට් ... වර්ගයේ ස්ථිතික නොවන ටෙස්ට් ඉන්ස්ටාන්ස් (ටෙස්ට් ඕබෙක්ට්, ටෙස්ට් ඕබෙක්ට්) වෙත ස්ථිතික සඳහනක් කළ නොහැකි බවයි."

එහි නිදර්ශන ක්‍රමයක් ප්‍රමාණවත් තරම් සාධාරණයි, නමුත් අපි testInstanceපහත පරිදි අධික ලෙස පැටවුවහොත්:

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

අමතන්න:

BinaryOperator<TestObject> binary = TestObject::testInstance;

කේතය දඩය සම්පාදනය කරයි. මන්ද එය testInstanceද්විත්ව එකක් වෙනුවට තනි පරාමිතියක් සමඟ කැඳවනු ඇත. හරි ඉතින් අපේ පරාමිති දෙක මොකද වුණේ? මුද්‍රිත පිටපතට ඉඩ දී බලන්න:

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

ප්‍රතිදානය කරන:

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

හරි ඉතින් JVM param1.testInstance (param2) අමතන්න තරම් දක්ෂයි. අපට testInstanceවෙනත් සම්පතකින් භාවිතා කළ හැකි නමුත් ටෙස්ට් ඕබෙක්ට් නොවේ, එනම්:

public class TestUtil {

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

අමතන්න:

BinaryOperator<TestObject> binary = TestUtil::testInstance;

එය සම්පාදනය නොකරන අතර සම්පාදකයා මෙසේ කියයි: "TestUtil වර්ගය testInstance (TestObject, TestObject) යන්න අර්ථ දක්වන්නේ නැත" . එබැවින් සම්පාදකයා එකම වර්ගයේ නොවේ නම් ස්ථිතික යොමු කිරීමක් සොයනු ඇත. හරි, බහුමාපකය ගැන කුමක් කිව හැකිද? අපි අවසාන වෙනස් කිරීම් ඉවත් කර අපගේ SubTestObject පන්තිය එකතු කළහොත් :

public class SubTestObject extends TestObject {

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

}

අමතන්න:

BinaryOperator<TestObject> binary = SubTestObject::testInstance;

එය සම්පාදනය නොකරනු ඇත, සම්පාදකයා තවමත් ස්ථිතික යොමු කිරීමක් සොයනු ඇත. නමුත් පහත කේතය සමත් වන බැවින් එය හොඳින් සම්පාදනය කරනු ඇත - පරීක්ෂණයකි:

public class TestObject {

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

}

BinaryOperator<TestObject> binary = TestObject::testInstance;

* මම දැන් ඉගෙන ගන්නවා, ඒ නිසා මම උත්සාහ කර බැලුවෙමි, මා වැරදියි නම් මාව නිවැරදි කිරීමට නිදහස් වන්න


2

ජාවා -8 ප්‍රවාහයන්හි අඩු කරන්නා යනු සරල කෘතිවල අගයන් දෙකක් ආදානය ලෙස ගෙන යම් ගණනය කිරීමෙන් පසු ප්‍රති result ල ලබා දෙන ශ්‍රිතයකි. මෙම ප්‍රති result ලය ඊළඟ පුනරාවර්තනයේදී පෝෂණය වේ.

ගණිතය සම්බන්ධයෙන්: උපරිම ශ්‍රිතය, ක්‍රමය මඟින් උපරිම අගයන් දෙකක් ආපසු ලබා දෙන අතර අවසානයේ ඔබට අතේ විශාලතම සංඛ්‍යාවක් ඇත.


1

ධාවන වේලාවේදී ඔවුන් හැසිරෙන්නේ හරියටම එක හා සමානයි. බයිට් කේතය සමාන නොවිය හැකිය /

ධාවන වේලාවේදී ඔවුන් හැසිරෙන්නේ හරියටම සමාන ය. ක්‍රමය (ගණිතය :: උපරිම) ;, එය එකම ගණිතයක් ජනනය කරයි (ඉහත සඳහන් කර javap -c;


1

පැරණි ජාවා අනුවාද වල, "::" හෝ බැටළු පැටවා වෙනුවට ඔබට භාවිතා කළ හැකිය:

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

නැතහොත් ක්‍රමයට පිවිසීම:

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

1

ඒ නිසා මම මෙහි ටොන් ගණනක පිළිතුරු අවංකවම සංකීර්ණ කර ඇති අතර එය අඩු තක්සේරුවකි.

පිළිතුර ඉතා සරල ය: :: එය ක්‍රම යොමුව ලෙස හැඳින්වේ https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

ඒ නිසා මම මේසය වෙත අනුචලනය නොකරන්නේ නම්, සබැඳියේ, ඔබට සියලු තොරතුරු සොයාගත හැකිය.


දැන්, ක්‍රම යොමුව යනු කුමක්දැයි කෙටියෙන් බලමු:

A :: B පහත දැක්වෙන පේළිගත ලැම්බඩා ප්‍රකාශනය තරමක් ආදේශ කරයි : (පරාමිති ...) -> ඒබී (පරාමිති ...)

මෙය ඔබගේ ප්‍රශ්න සමඟ සහසම්බන්ධ වීමට, ජාවා ලැම්බඩා ප්‍රකාශනයක් තේරුම් ගැනීම අවශ්‍ය වේ. අමාරු නැත.

පේළිගත ලැම්බඩා ප්‍රකාශනය අර්ථ දක්වා ඇති ක්‍රියාකාරී අතුරුමුහුණතකට සමාන වේ (එය 1 ක්‍රමයට වඩා අඩු හා නොඅඩු අතුරු මුහුණතක්) . මා අදහස් කරන දේ කෙටියෙන් බලමු:

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

InterfaceX ක්‍රියාකාරී අතුරු මුහුණතක් විය යුතුය. ඕනෑම ක්‍රියාකාරී අතුරුමුහුණතක්, එම සම්පාදකයා සඳහා ඉන්ටර්ෆේස්එක්ස් හි වැදගත් වන්නේ ඔබ ආකෘතිය නිර්වචනය කිරීමයි:

InterfaceX මේ ඕනෑම එකක් විය හැකිය:

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

හෝ මේ

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

හෝ ඊට වඩා සාමාන්‍ය:

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

අපි මුලින් නිර්වචනය කළ පළමු ඉදිරිපත් කළ නඩුව සහ ඉන්ලයින් ලැම්බඩා ප්‍රකාශනය සලකා බලමු.

ජාවා 8 ට පෙර, ඔබට එය මේ ආකාරයෙන් අර්ථ දැක්විය හැකිය:

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

ක්රියාකාරීව, එය එකම දෙයයි. සම්පාදකයා මෙය වටහා ගන්නා ආකාරයෙහි වෙනස වැඩිය.

දැන් අපි පේළිගත කළ ලැම්බඩා ප්‍රකාශනය දෙස බැලුවෙමු, අපි ක්‍රම යොමුව වෙත ආපසු යමු (: :). ඔබට මේ වගේ පන්තියක් ඇති බව කියමු:

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

ක්රමය පටන් anyFunctions InterfaceX ලෙස එම වර්ග ඇත callMe , අපි ක්රමය විමර්ශන සහිත දෙකක් equivalate හැක.

අපට එය මෙසේ ලිවිය හැකිය:

InterfaceX o =  Q::anyFunction; 

එය මෙයට සමාන වේ:

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

ක්‍රම යොමු යොමුවල ඇති සිසිල් දෙයක් සහ වාසියක් නම්, මුලදී, ඔබ ඒවා විචල්‍යයන්ට අනුයුක්ත කරන තුරු, ඒවා ටයිප් රහිත ය. එබැවින් ඔබට ඒවා ඕනෑම සමාන පෙනුමක් ඇති (එකම අර්ථ දක්වා ඇති) ක්‍රියාකාරී අතුරුමුහුණතකට පරාමිතීන් ලෙස යැවිය හැකිය. ඔබේ නඩුවේ සිදුවන්නේ හරියටම එයයි


1

කුමක් සඳහාද යන්න පිළිබඳ පෙර පිළිතුරු තරමක් සම්පූර්ණයි ::ක්‍රමවේදය යොමු කරන්නේ . සාරාංශයක් ලෙස, එය ක්‍රියාත්මක නොකර ක්‍රමවේදයක් (හෝ ඉදිකිරීම්කරුවෙකු) වෙත යොමු කිරීමට එය ක්‍රමයක් සපයන අතර, ඇගයීමට ලක් කළ විට, එය ඉලක්ක වර්ගයේ සන්දර්භය සපයන ක්‍රියාකාරී අතුරුමුහුණතේ උදාහරණයක් නිර්මාණය කරයි.

පහත දැක්වෙන්නේ උපරිම අගය සහිත වස්තුවක් ArrayListWITH සමඟ සොයා ගැනීමට සහ ::ක්‍රම යොමු කිරීමකින් තොරව ය. පැහැදිලි කිරීම් පහත දැක්වෙන අදහස් දැක්වීම්වල ඇත.


භාවිතයෙන් තොරව ::

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

භාවිතය සමඟ ::

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

-2

ඩබල් කොලන් එනම් ::ක්‍රියාකරු ජාවා 8 හි ක්‍රමවේද යොමු කිරීමක් ලෙස හඳුන්වා දී ඇත . ක්‍රම යොමු කිරීම යනු ලැම්බඩා ප්‍රකාශනයේ ආකාරයකි, එය පවතින ක්‍රමය එහි නමෙන් යොමු කිරීමට භාවිතා කරයි.

classname :: methodName

උදා: -

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

ඩබල් කොලෝන් භාවිතා කිරීමෙන් ::

  • stream.forEach(System.out::println(element))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.