:: (ডাবল কোলন) জাভা 8 এ অপারেটর


955

আমি জাভা 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 যথাসাধ্য সাহায্য, গভীর করার বিষয়ে করলেন না
পন্ত Backlund

8
@ নেট এটি ঠিক "সিনট্যাকটিক চিনি" নয়, যদি না আপনি কীসের জন্য বলতে পারেন। যেমন "x হ'ল সিনট্যাকটিক চিনির জন্য" "
ইনগো

6
@ ইঙ্গো এটি যতবারই ব্যবহার করি ততবার লাম্বদার একটি নতুন অবজেক্ট তৈরি করে। TestingLambda$$Lambda$2/8460669এবং TestingLambda$$Lambda$3/11043253দুটি অনুরোধে তৈরি করা হয়েছিল।
নরেন্দ্র পাঠাই

13
ল্যাম্বডাস এবং পদ্ধতির উল্লেখগুলি "সাধারণ পুরানো বেনামে অভ্যন্তরীণ শ্রেণি" নয়। প্রোগ্রামার.সটাকেক্সচেঞ্জ / a/181743/ 59134 দেখুন । হ্যাঁ, যদি প্রয়োজন হয় তবে নতুন ক্লাস এবং ইনস্ট্যান্সগুলি ফ্লাইটে তৈরি করা হয়েছে, যদি প্রয়োজন হয় তবে কেবল প্রয়োজনে।
স্টুয়ার্ট

উত্তর:


1022

সাধারণত, কেউ নীচের মত 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));

কিভাবে কাজ করে? জাভা সংকলক "সনাক্ত করে", আপনি এমন একটি পদ্ধতি প্রয়োগ করতে চান যা দুটি গ্রহণ করে intএবং একটি ফেরত দেয় int। এটি ইন্টারফেসের এক এবং একমাত্র পদ্ধতির আনুষ্ঠানিক প্যারামিটারগুলির সমান IntBinaryOperator( reduceআপনি যে পদ্ধতির প্যারামিটারটি কল করতে চান)। সুতরাং সংকলকটি আপনার জন্য বিশ্রামটি করবে - এটি কেবল ধরে নেয় যে আপনি বাস্তবায়ন করতে চানIntBinaryOperator

কিন্তু Math.max(int, int) নিজেই এর আনুষ্ঠানিক প্রয়োজনীয়তা পূরণ করে IntBinaryOperator, এটি সরাসরি ব্যবহার করা যেতে পারে। জাভা 7-তে কোনও সিনট্যাক্স নেই যা কোনও পদ্ধতি নিজেই আর্গুমেন্ট হিসাবে পাস করার অনুমতি দেয় (আপনি কেবল পদ্ধতির ফলাফলগুলি কেবল পাস করতে পারেন, তবে কখনই পদ্ধতিটি উল্লেখ করতে পারবেন না), ::সিনট্যাক্সটি জাভা 8-তে রেফারেন্স পদ্ধতিতে প্রবর্তিত হয়েছিল:

reduce(Math::max);

নোট করুন যে এটি সংকলক দ্বারা ব্যাখ্যা করা হবে, রানটাইমে জেভিএম দ্বারা নয়! যদিও এটি তিনটি কোড স্নিপেটের জন্য আলাদা বাইকোড তৈরি করে, সেগুলি শব্দার্থগতভাবে সমান, সুতরাং শেষ দুটিটি সংক্ষিপ্ত (এবং সম্ভবত আরও দক্ষ) সংস্করণ হিসাবে বিবেচনা করা যেতে পারেIntBinaryOperator দুটিটি উপরের প্রয়োগের !

( ল্যাম্বদা এক্সপ্রেশনগুলির অনুবাদও দেখুন )


489

::যাকে মেথড রেফারেন্স বলা হয়। এটি মূলত একটি একক পদ্ধতির রেফারেন্স। অর্থাৎ এটি নামের দ্বারা একটি বিদ্যমান পদ্ধতি বোঝায়।

সংক্ষিপ্ত বিবরণ :
নীচে স্থির পদ্ধতির উল্লেখের উদাহরণ দেওয়া হল:

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একটি যুক্তি প্রত্যাশা করে এবং ক doublegetপদ্ধতি সরবরাহকারী একটি মান ফেরায় কিন্তু একটি আর্গুমেন্ট নেয় না। সুতরাং, এটি একটি ত্রুটি ফলাফল।

একটি পদ্ধতি রেফারেন্স একটি কার্যকরী ইন্টারফেসের পদ্ধতি বোঝায়। (যেমনটি উল্লেখ করা হয়েছে, ক্রিয়ামূলক ইন্টারফেসের প্রতিটি একটি করে পদ্ধতি থাকতে পারে)।

আরও কয়েকটি উদাহরণ: কনজিউমার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
ব্যাখ্যা করার জন্য আপনাকে ধন্যবাদ. সংক্ষেপে: '::' একটি ফাংশনাল ইনটারফেস (ল্যাম্বডা) কে সন্তুষ্ট করে এমন একটি পদ্ধতি বের করার জন্য ব্যবহার করুন: ক্লাসএক্স :: স্ট্যাটিকমেথডএক্স, বা উদাহরণস্বরূপ: দৃষ্টান্ত
মেঠোডেক্স

55

হ্যাঁ, এটা সত্য। ::অপারেটর পদ্ধতি উল্লেখ জন্য ব্যবহৃত হয়। সুতরাং, কেউ ক্লাস থেকে স্ট্যাটিক পদ্ধতিগুলি ব্যবহার করে বা অবজেক্ট থেকে পদ্ধতিগুলি ব্যবহার করতে পারে। একই অপারেটর এমনকি নির্মাণকারীদের জন্যও ব্যবহার করা যেতে পারে। এখানে উল্লিখিত সমস্ত ক্ষেত্রে নীচের কোড নমুনায় উদাহরণ দেওয়া হয়েছে।

ওরাকল থেকে সরকারী ডকুমেন্টেশন এখানে পাওয়া যাবে

আপনি এই নিবন্ধে জেডিকে 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
@ রিচার্ডটিঙ্গল method(Math::max);হ'ল অনুরোধ এবং পদ্ধতির সংজ্ঞাটি এর মতো হবে public static void method(IntBinaryOperator op){System.out.println(op.applyAsInt(1, 2));}। এটিই এর ব্যবহার।
নরেন্দ্র পাঠাই

2
সি # এর সাথে যারা পরিচিত তাদের ক্ষেত্রে এটি ডেলিগেটটাইপ d = নতুন ডেলিগেটটাইপ (মেথডনাম) এর সাথে একই;
অ্যাড্রিয়ান জানেস্কু

27

মনে হচ্ছে এটি একটু দেরীতে তবে এখানে আমার দুটি সেন্ট রয়েছে are একটি ল্যামডা অভিব্যক্তি বেনামী পদ্ধতি তৈরি করতে ব্যবহার করা হয়। এটি একটি বিদ্যমান পদ্ধতিটিকে কল করা ছাড়া কিছুই করে না, তবে সরাসরি নামটির দ্বারা পদ্ধতিটি উল্লেখ করা আরও পরিষ্কার। এবং পদ্ধতি রেফারেন্স আমাদের পদ্ধতি-রেফারেন্স অপারেটরটি ব্যবহার করে এটি সক্ষম করে ::

নিম্নলিখিত সাধারণ ক্লাসটি বিবেচনা করুন যেখানে প্রতিটি কর্মীর নাম এবং গ্রেড রয়েছে।

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

25

::জাভা 8 এ অন্তর্ভুক্ত একটি নতুন অপারেটর যা বিদ্যমান শ্রেণীর কোনও পদ্ধতি উল্লেখ করতে ব্যবহৃত হয়। আপনি কোনও শ্রেণীর স্থিতিশীল পদ্ধতি এবং অ স্থির পদ্ধতিগুলি উল্লেখ করতে পারেন।

স্থির পদ্ধতিগুলি উল্লেখ করার জন্য সিনট্যাক্সটি হ'ল:

ClassName :: methodName 

অ স্থির পদ্ধতি উল্লেখ করার জন্য বাক্য গঠনটি হ'ল

objRef :: methodName

এবং

ClassName :: methodName

কোনও পদ্ধতির রেফারেন্সের একমাত্র পূর্বশর্ত হ'ল পদ্ধতিটি কার্যকরী ইন্টারফেসে বিদ্যমান, যা অবশ্যই পদ্ধতির রেফারেন্সের সাথে সামঞ্জস্যপূর্ণ হতে হবে।

পদ্ধতি রেফারেন্সগুলি যখন মূল্যায়ন করা হয় তখন কার্যকরী ইন্টারফেসের একটি উদাহরণ তৈরি করে।

পাওয়া গেছে: http://www.speakingcs.com/2014/08/ স্মৃতি-সংক্রান্তীকরণ-in-java- 8.html


22

এটি জাভা ৮-এ একটি পদ্ধতির উল্লেখ The ওরাকল ডকুমেন্টেশনটি এখানে

ডকুমেন্টেশনে যেমন বলা হয়েছে ...

পদ্ধতি রেফারেন্স ব্যক্তি: তুলনাবাইএজ একটি স্থির পদ্ধতির একটি রেফারেন্স।

নিম্নলিখিতটি কোনও নির্দিষ্ট অবজেক্টের উদাহরণ পদ্ধতির রেফারেন্সের উদাহরণ:

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

পদ্ধতিটি রেফারেন্স মাই কম্পোরিজেনশনপ্রোভাইডার :: কম্প্যাইজওয়াইনেম মেথড মাই কম্পোরিজেনশন প্রোভাইডার অংশটির তুলনা করে বায়নেম মেথডকে অনুরোধ করে। জেআরই পদ্ধতি ধরণের আর্গুমেন্টগুলি অনুমান করে, যা এই ক্ষেত্রে (ব্যক্তি, ব্যক্তি)।


2
তবে পদ্ধতি 'তুলনামূলক বাই' স্থির নয়।
আব্বাস

3
@ আব্বাস নর তুলনামূলক ব্যয়াম সুতরাং, আপনি কোনও অবজেক্ট ব্যবহার করে রেফারেন্স অপারেটরের মাধ্যমে এই অ-স্থিতিশীল পদ্ধতিগুলি অ্যাক্সেস করতে পারেন। যদি তারা স্থির থাকে তবে আপনি ক্লাসের নাম তুলনাপ্রবণ হিসাবে ব্যবহার করতে পারেন :: কিছু স্ট্যাটিকমঠোড
আর

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

ধাপ ২:

// 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 । গতানুগতিক উপায়ে এটি এর মতো প্রয়োগ করা হয়েছে:

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

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

            return t;
        }
    };

আপনি বেনামে বাস্তবায়নে দেখেন এটির জন্য দুটি টেস্টোবজেক্ট আর্গুমেন্টের প্রয়োজন হয় এবং টেস্টোবজেক্ট অবজেক্টটিও প্রদান করে। ::অপারেটর ব্যবহার করে এই শর্তটি পূরণ করার জন্য আমরা একটি স্থিতিশীল পদ্ধতি দিয়ে শুরু করতে পারি:

public class TestObject {


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

এবং তারপরে কল করুন:

BinaryOperator<TestObject> binary = TestObject::testStatic;

ঠিক আছে এটি জরিমানা সংকলন। আমাদের যদি একটি উদাহরণ পদ্ধতি প্রয়োজন তবে কী হবে? উদাহরণ পদ্ধতি সহ টেস্টবজেক্টটি আপডেট করতে দেয়:

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

ঠিক আছে সুতরাং জেভিএম প্যারাম 1.টেস্টআইনস্ট্যান্স (প্যারাম 2) কল করার জন্য যথেষ্ট স্মার্ট। আমরা testInstanceঅন্য সংস্থান থেকে টেস্টবজেক্ট নয়, ব্যবহার করতে পারি , যেমন:

public class TestUtil {

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

এবং কল করুন:

BinaryOperator<TestObject> binary = TestUtil::testInstance;

এটি কেবল সংকলন করবে না এবং সংকলক বলবে: "টাইপ টেস্টUtil টেস্টইনস্ট্যান্স (টেস্টঅবজেক্ট, টেস্টঅবজেক্ট) সংজ্ঞায়িত করে না" । সুতরাং সংকলক স্থির রেফারেন্সটি সন্ধান করবে যদি এটি একই ধরণের না হয়। ঠিক আছে বহুবর্ষ সম্পর্কে কি? যদি আমরা চূড়ান্ত সংশোধনকারীগুলি সরিয়ে এবং আমাদের সাবটস্টঅবজেক্ট শ্রেণি যুক্ত করি:

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 স্ট্রিমে রিডিউসার সহজ কাজগুলিতে এমন একটি ফাংশন যা ইনপুট হিসাবে দুটি মান নেয় এবং কিছু গণনার পরে ফলাফল দেয়। এই ফলাফলটি পরবর্তী পুনরাবৃত্তিতে খাওয়ানো হয়।

ম্যাথের ক্ষেত্রে: সর্বাধিক ক্রিয়াকলাপ, পদ্ধতিটি সর্বোচ্চ দুটি পাস করে মান প্রদান করে এবং শেষ পর্যন্ত আপনার হাতে সবচেয়ে বেশি নম্বর থাকে।


1

রানটাইমের সময় তারা ঠিক একই রকম আচরণ করে by বাইটকোড একই / নাও হতে পারে (উপরের ইনসেসের জন্য, এটি একই বাইককোড উত্পন্ন করে (উপরের অংশটি অনুসরণ করুন এবং জাভা্যাপ-সি পরীক্ষা করুন;))

রানটাইমের সময় তারা ঠিক একই রকম আচরণ করে thodতিহ্যগত (গণিত :: সর্বাধিক); এটি একই গণিত উত্পন্ন করে (উপরের অংশীদার হন এবং জাভাপ-সি পরীক্ষা করুন))


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

সুতরাং আমি এখানে অনেকগুলি উত্তর দেখতে পাচ্ছি যা খোলামেলাভাবে অতি-জটিল an

উত্তরটি বেশ সহজ: :: এটিকে একটি পদ্ধতি রেফারেন্স বলা হয় https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

সুতরাং আমি লিঙ্কটিতে অনুলিপি-পেস্ট করব না, আপনি টেবিলে স্ক্রল করে নিলে আপনি সমস্ত তথ্য সন্ধান করতে পারেন।


এখন, আসুন একটি পদ্ধতি রেফারেন্স কি তা সংক্ষেপে দেখুন:

এ :: বি কিছুটা নিম্নলিখিত ইনলাইন ল্যাম্বডা এক্সপ্রেশনটি প্রতিস্থাপন করে : (প্যারাম ...) -> এ বি (প্যারাম ...)

এটি আপনার প্রশ্নের সাথে সম্পর্কিত করতে, জাভা লাম্বদা এক্সপ্রেশনটি বোঝা দরকার। যা শক্ত নয়।

একটি ইনলাইন ল্যাম্বডা এক্সপ্রেশন একটি সংজ্ঞায়িত ফাংশনাল ইন্টারফেসের সাথে সমান (এটি এমন একটি ইন্টারফেস যা এর বেশি এবং 1 পদ্ধতির চেয়ে কম নয়) । আমি কী বলতে চাইছি তা একটি সংক্ষিপ্ত নজর দিন:

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

ইন্টারফেসএক্স অবশ্যই একটি কার্যকরী ইন্টারফেস হতে হবে। যে কোনও কার্যকরী ইন্টারফেস, সেই সংকলকের জন্য ইন্টারফেসএক্সের জন্য গুরুত্বপূর্ণ বিষয়টি হ'ল আপনি ফর্ম্যাটটি সংজ্ঞায়িত করছেন:

ইন্টারফেসএক্স এর যে কোনও একটি হতে পারে:

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

যেহেতু যে কোনও ফাংশন ইন্টারফেসএক্স কলমির মতোই ধরণের রয়েছে has , আমরা সেই দুটি পদ্ধতির সাথে একটি মেথড রেফারেন্সের সাথে তুলনা করতে পারি।

আমরা এটি লিখতে পারি:

InterfaceX o =  Q::anyFunction; 

এবং এটি এর সমতুল্য:

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

মেথড রেফারেন্সগুলির একটি দুর্দান্ত জিনিস এবং সুবিধা হ'ল প্রথমে, আপনি যতক্ষণ না তাদের ভেরিয়েবলগুলিতে নির্ধারিত করেন ততক্ষণ এগুলি টাইপলেস। সুতরাং আপনি এগুলিকে কোনও সমতুল্য চেহারা (একই সংজ্ঞায়িত প্রকারের) কার্যকরী ইন্টারফেসের পরামিতি হিসাবে পাস করতে পারেন pass আপনার ক্ষেত্রে ঠিক যা ঘটে


1

পূর্ববর্তী উত্তরগুলি কি সম্পর্কে যথেষ্ট সম্পূর্ণ :: পদ্ধতির রেফারেন্সটি । সংক্ষিপ্তসার হিসাবে, এটি কোনও পদ্ধতি (বা নির্মাতাকে) কার্যকর না করে উল্লেখ করার উপায় সরবরাহ করে এবং যখন মূল্যায়ন করা হয়, এটি কার্যকরী ইন্টারফেসের একটি উদাহরণ তৈরি করে যা লক্ষ্য প্রকারের প্রসঙ্গ সরবরাহ করে।

নীচে দুটি সাথে উদাহরণ সহ সর্বাধিক মান সহ একটি অবজেক্ট সন্ধান ArrayListকরতে হবে এবং ::পদ্ধতি রেফারেন্সের ব্যবহার ছাড়াই । ব্যাখ্যা নীচে মন্তব্যে আছে।


ব্যবহার ছাড়া ::

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

-1

ডাবল কোলন অর্থাত্ ::অপারেটরটি জাভা 8 এ একটি পদ্ধতি রেফারেন্স হিসাবে প্রবর্তিত হয়েছিল । পদ্ধতি রেফারেন্স হ'ল ল্যাম্বডা এক্সপ্রেশনের একটি ফর্ম যা এটির নাম দ্বারা বিদ্যমান পদ্ধতিটি উল্লেখ করতে ব্যবহৃত হয়।

classname :: methodName

উদা: -

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

ডাবল কোলন ব্যবহার করে ::

  • stream.forEach(System.out::println(element))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.