জাভাতে কোন ফাংশন পয়েন্টারের নিকটতম বিকল্পটি কী?


299

আমার কাছে একটি পদ্ধতি রয়েছে যা কোডের দশটি লাইন। আমি আরও একটি পদ্ধতি তৈরি করতে চাই যা ঠিক একই কাজ করে, একটি ছোট গণনা ব্যতীত কোডের একটি লাইন পরিবর্তন করতে চলেছে। এটি একটি লাইন প্রতিস্থাপনের জন্য একটি ফাংশন পয়েন্টারে পাস করার জন্য এটি একটি নিখুঁত অ্যাপ্লিকেশন, তবে জাভাতে ফাংশন পয়েন্টার নেই। আমার সেরা বিকল্প কি?


5
জাভা 8-এ লাম্বদা এক্সপ্রেশন থাকবে । আপনি এখানে ল্যাম্বদা এক্সপ্রেশন সম্পর্কে আরও পড়তে পারেন ।
মারিয়াস

4
@ মারিয়াস আমি ল্যাম্বডা এক্সপ্রেশনগুলি ফাংশন পয়েন্টার হিসাবে গণনা করা বেশ মনে করি না। অপারেটর, অপরপক্ষে ...::
হাট সঙ্গে দ্য গাই

দেরী মন্তব্যের জন্য দুঃখিত;) - সাধারণত, আপনার এটির জন্য কোনও ফাংশন পয়েন্টার লাগবে না। শুধু একটি টেম্পলেট পদ্ধতি ব্যবহার করুন! ( En.wikipedia.org/wiki/Template_method_pattern )
isnot2bad

2
@ isnot2bad - নিবন্ধটি দেখার জন্য, ওভারকিলের মতো মনে হচ্ছে - এখানে দেওয়া উত্তরের চেয়ে জটিল। বিশেষত, টেম্পলেট পদ্ধতিতে প্রতিটি বিকল্প গণনার জন্য একটি সাবক্লাস তৈরি করা প্রয়োজন । আমি দেখতে পাচ্ছি না ওপিকে এমন কিছু বলা আছে যা সাবক্লাসগুলির প্রয়োজন ; তিনি কেবল কয়েকটি পদ্ধতি তৈরি করতে এবং বেশিরভাগ বাস্তবায়নের ভাগ করতে চান । গৃহীত উত্তরগুলি যেমন দেখায়, এটি জাভা 8 এর আগেও ল্যাম্বডাসের সাথে সহজেই "স্থানে" (প্রতিটি পদ্ধতির অভ্যন্তরে) সম্পন্ন হয়।
টুলমেকারস্টেভ

@ টলমেকারস্টেভ গ্রহণযোগ্য সমাধানটির জন্য প্রতি গণনা শ্রেণিতেও প্রয়োজনীয় (যদিও এটি কেবল একটি বেনামে অভ্যন্তর শ্রেণি)। এবং বেনামে অভ্যন্তরীণ ক্লাসগুলি ব্যবহার করে টেম্পলেট পদ্ধতির প্যাটার্নটিও উপলব্ধি করা যায়, সুতরাং এটি ওভারহেড সম্পর্কিত (জাভা 8 এর পূর্বে) গ্রহণযোগ্য সমাধানের চেয়ে অনেক বেশি আলাদা নয়। সুতরাং এটি ব্যবহারের প্যাটার্ন এবং বিশদ বিবরণ সংক্রান্ত আরও প্রশ্ন, যা আমরা জানি না। আমি গৃহীত উত্তরের প্রশংসা করি এবং ভেবে দেখার জন্য আরও একটি সম্ভাবনা যোগ করতে চাই।
isnot2bad

উত্তর:


269

নামবিহীন অভ্যন্তর শ্রেণি

বলুন যে আপনি এমন একটি Stringপ্যারাম দিয়ে একটি ফাংশন পাস করতে চান যা একটি ফেরত দেয় int
প্রথমে আপনাকে কোনও ইন্টারফেসটিকে তার একমাত্র সদস্য হিসাবে সংজ্ঞায়িত করতে হবে, যদি আপনি কোনও বিদ্যমানটিকে পুনরায় ব্যবহার করতে না পারেন।

interface StringFunction {
    int func(String param);
}

পয়েন্টারটি গ্রহণ করে এমন একটি পদ্ধতি StringFunctionযেমন উদাহরণটি গ্রহণ করবে :

public void takingMethod(StringFunction sf) {
   int i = sf.func("my string");
   // do whatever ...
}

এবং তাই বলা হবে:

ref.takingMethod(new StringFunction() {
    public int func(String param) {
        // body
    }
});

সম্পাদনা: জাভা 8-এ, আপনি এটি ল্যাম্বডা এক্সপ্রেশন সহ কল ​​করতে পারেন:

ref.takingMethod(param -> bodyExpression);

13
এটি "কমান্ড প্যাটার্ন" এর উদাহরণ,। en.wikipedia.org/wiki/Command_Pattern
রাক্ষস Psalm33

3
@ ওগ্রে গীতসংস্থান 33 আপনি কীভাবে এটি ব্যবহার করেন তার উপর নির্ভর করে এই কৌশলটি কৌশল প্যাটার্নও হতে পারে। কৌশল প্যাটার্ন এবং কমান্ড প্যাটার্ন মধ্যে পার্থক্য
ররি ও'কেনে

2
এখানে জাভা ৫ ,,, এবং a এর জন্য একটি ক্লোজার বাস্তবায়ন রয়েছে m
মিমি

@ সেক্রেট সার্ভিস: এই লিঙ্কটি মারা গেছে।
লরেন্স ডল

@ লরেন্সডল হ্যাঁ, এটি। আমি যে ক্লাসটি ব্যবহার করছি তার একটি পেস্টবিন এখানে। পেস্টবিন.com
মিমি

32

প্রতিটি "ফাংশন পয়েন্টার" এর জন্য, আমি একটি ছোট ফান্টারের ক্লাস তৈরি করব যা আপনার গণনা কার্যকর করে। একটি ইন্টারফেস সংজ্ঞায়িত করুন যা সমস্ত শ্রেণিগুলি প্রয়োগ করবে এবং আপনার বৃহত্তর ফাংশনে objects অবজেক্টগুলির উদাহরণগুলি প্রেরণ করবে। এটি " কমান্ড প্যাটার্ন " এবং " কৌশল প্যাটার্ন " এর সংমিশ্রণ ।

@ এসব্লুন্ডির উদাহরণটি ভাল।


28

যখন একটি পূর্বনির্ধারিত সংখ্যার বিভিন্ন গণনার আপনি সেই এক লাইনে করতে পারেন, এনুম ব্যবহার করা কোনও কৌশল নিদর্শন বাস্তবায়নের জন্য দ্রুত, তবুও পরিষ্কার উপায় way

public enum Operation {
    PLUS {
        public double calc(double a, double b) {
            return a + b;
        }
    },
    TIMES {
        public double calc(double a, double b) {
            return a * b;
        }
    }
     ...

     public abstract double calc(double a, double b);
}

স্পষ্টতই, কৌশল পদ্ধতি ঘোষণার পাশাপাশি প্রতিটি বাস্তবায়নের ঠিক এক উদাহরণ সমস্ত একক শ্রেণি / ফাইলে সংজ্ঞায়িত করা হয়।


24

আপনাকে এমন একটি ইন্টারফেস তৈরি করতে হবে যা আপনাকে চারপাশে যেতে চান এমন ফাংশন সরবরাহ করে। উদাহরণ:

/**
 * A simple interface to wrap up a function of one argument.
 * 
 * @author rcreswick
 *
 */
public interface Function1<S, T> {

   /**
    * Evaluates this function on it's arguments.
    * 
    * @param a The first argument.
    * @return The result.
    */
   public S eval(T a);

}

তারপরে, যখন আপনাকে কোনও ফাংশন পাস করার দরকার হয়, আপনি সেই ইন্টারফেসটি প্রয়োগ করতে পারেন:

List<Integer> result = CollectionUtilities.map(list,
        new Function1<Integer, Integer>() {
           @Override
           public Integer eval(Integer a) {
              return a * a;
           }
        });

পরিশেষে, মানচিত্রের ফাংশনটি ফাংশন 1 এ পাস হিসাবে নিম্নলিখিতটি ব্যবহার করে:

   public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn, 
         Map<K, S> m1, Map<K, T> m2, Map<K, R> results){
      Set<K> keySet = new HashSet<K>();
      keySet.addAll(m1.keySet());
      keySet.addAll(m2.keySet());

      results.clear();

      for (K key : keySet) {
         results.put(key, fn.eval(m1.get(key), m2.get(key)));
      }
      return results;
   }

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


4
এই "উত্তর" সমাধান সেটের চেয়ে সমস্যা সেটটির সাথে বেশি সম্পর্কিত
tchrist

18

পদ্ধতি ব্যবহার করে রেফারেন্স ::অপারেটর

আপনি পদ্ধতি আর্গুমেন্টে পদ্ধতি উল্লেখগুলি ব্যবহার করতে পারেন যেখানে পদ্ধতিটি কার্যকরী ইন্টারফেস গ্রহণ করে । একটি কার্যকরী ইন্টারফেস এমন কোনও ইন্টারফেস যা কেবলমাত্র একটি বিমূর্ত পদ্ধতি থাকে st (একটি কার্যক্ষম ইন্টারফেসে এক বা একাধিক ডিফল্ট পদ্ধতি বা স্ট্যাটিক পদ্ধতি থাকতে পারে))

IntBinaryOperatorএকটি কার্যকরী ইন্টারফেস। এর বিমূর্ত পদ্ধতিটি, applyAsIntদুটি টিকে intএর পরামিতি হিসাবে গ্রহণ করে এবং একটি প্রদান করে intMath.maxএছাড়াও দুটি intগুলি গ্রহণ করে এবং একটি প্রদান করে int। এই উদাহরণে, A.method(Math::max);তোলে parameter.applyAsIntতার দুটি ইনপুট মান পাঠাতে Math.maxএবং যে ফল আসতে Math.max

import java.util.function.IntBinaryOperator;

class A {
    static void method(IntBinaryOperator parameter) {
        int i = parameter.applyAsInt(7315, 89163);
        System.out.println(i);
    }
}
import java.lang.Math;

class B {
    public static void main(String[] args) {
        A.method(Math::max);
    }
}

সাধারণভাবে, আপনি ব্যবহার করতে পারেন:

method1(Class1::method2);

পরিবর্তে:

method1((arg1, arg2) -> Class1.method2(arg1, arg2));

যা সংক্ষিপ্ত:

method1(new Interface1() {
    int method1(int arg1, int arg2) {
        return Class1.method2(arg1, agr2);
    }
});

আরও তথ্যের জন্য, জাভা 8 এবং জাভা ভাষার নির্দিষ্টকরণ §15.13 এ :: (ডাবল কোলন) অপারেটরটি দেখুন


15

আপনি এটিও করতে পারেন (যা কিছুটা বিরল অনুষ্ঠানে বোঝা যায়)। ইস্যুটি (এবং এটি একটি বড় সমস্যা) হ'ল আপনি কোনও শ্রেণি / ইন্টারফেস ব্যবহারের সমস্ত প্রকারভেদ হারাতে পারেন এবং পদ্ধতিটি বিদ্যমান নেই এমন ক্ষেত্রে আপনাকে মোকাবেলা করতে হবে।

এটিতে "উপকার" রয়েছে যা আপনি অ্যাক্সেস বিধিনিষেধ উপেক্ষা করে ব্যক্তিগত পদ্ধতিগুলি কল করতে পারেন (উদাহরণে দেখানো হয় না, তবে আপনি এমন পদ্ধতিগুলিতে কল করতে পারেন যা সংকলক সাধারণত কল করতে দেয় না)।

আবার এটি একটি বিরল ঘটনা যা এটি উপলব্ধি করে তবে এই উপলক্ষগুলিতে এটি একটি দুর্দান্ত সরঞ্জাম।

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Main
{
    public static void main(final String[] argv)
        throws NoSuchMethodException,
               IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        final String methodName;
        final Method method;
        final Main   main;

        main = new Main();

        if(argv.length == 0)
        {
            methodName = "foo";
        }
        else
        {
            methodName = "bar";
        }

        method = Main.class.getDeclaredMethod(methodName, int.class);

        main.car(method, 42);
    }

    private void foo(final int x)
    {
        System.out.println("foo: " + x);
    }

    private void bar(final int x)
    {
        System.out.println("bar: " + x);
    }

    private void car(final Method method,
                     final int    val)
        throws IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        method.invoke(this, val);
    }
}

1
আমি এটি মেনু হ্যান্ডলিং / জিইউআই জন্য কখনও কখনও ব্যবহার করি কারণ বেনামি অভ্যন্তর শ্রেণীর সিনট্যাক্সের চেয়ে পদ্ধতি সিনট্যাক্সটি এত সহজ। এটি পরিষ্কার, তবে আপনি প্রতিবিম্বের জটিলতা যুক্ত করছেন যা কিছু লোক খনন করতে চায় না, তাই নিশ্চিত হয়ে নিন যে আপনি এটি সঠিকভাবে পেয়েছেন এবং প্রতিটি সম্ভাব্য ত্রুটি শর্তের জন্য পরিষ্কার, পাঠ্য ত্রুটি রয়েছে।
বিল কে

জেনারিকগুলি ব্যবহার করে আপনি এটি নিরাপদে টাইপ করতে পারেন এবং আপনার প্রতিবিম্বের প্রয়োজন নেই।
লুইজি প্লিঞ্জ

1
আমি কীভাবে জেনেরিকগুলি ব্যবহার করে এবং প্রতিবিম্বটি ব্যবহার না করে আপনাকে কোনও স্ট্রিংয়ের মধ্যে থাকা নামের দ্বারা কোনও পদ্ধতিতে কল করতে দেয় তা দেখতে আমি ব্যর্থ হয়েছি?
তোফুবিয়ার

1
@ লুইগিপ্লিনজ - আপনি যা বলতে চান তার একটি কোড স্নিপেট সরবরাহ করতে পারেন?
নির্মাতা স্টিভ

13

আপনার যদি মাত্র একটি লাইন আলাদা থাকে তবে আপনি কোনও প্যারামিটার যুক্ত করতে পারেন যেমন একটি পতাকা এবং যদি (পতাকা) বিবৃতি যা একটি লাইন বা অন্যটিকে কল করে।


1
জাভাস্কুলের উত্তরটি আরও দুটি গণনার বৈকল্পিক হলে এটি করার একটি ক্লিনার উপায় বলে মনে হয়। অথবা যদি কেউ পদ্ধতিটিতে কোডটি এম্বেড করতে চায় তবে পদ্ধতিটি যে বিভিন্ন ক্ষেত্রে পরিচালনা করে তার জন্য একটি এনুম এবং একটি সুইচ।
টুলমেকারস্টেভ

1
@ টুলমেকারস্টেভ সত্য, যদিও আজ আপনি জাভা ৮
পিটার লরে

12

আপনার কাছে জাভা 7 এর কাজ বন্ধ হওয়ার সাথে জড়িত থাকার বিষয়ে শুনতে আগ্রহীও হতে পারেন:

জাভাতে বন্ধের বর্তমান অবস্থা কী?

http://g अनुसरण.blogspot.com/2006/08/closures-for-java.html http://tech.puredanger.com/java7/# সমাপ্তি


দরকারী লিঙ্কগুলির জন্য +1, যদিও আমি মনে করি জাভাতে ক্লোজার যুক্ত করা সম্পূর্ণরূপে অসহায়।
মাইকেরা

11

অপারেটরটি ব্যবহার করে নতুন জাভা 8 ফাংশনাল ইন্টারফেস এবং পদ্ধতি রেফারেন্স::

জাভা 8 " @ ফাংশনাল ইন্টারফেস " পয়েন্টার সহ পদ্ধতি রেফারেন্সগুলি (মাইক্লাস :: নতুন) বজায় রাখতে সক্ষম । একই পদ্ধতির নামের প্রয়োজন নেই, কেবল একই পদ্ধতির স্বাক্ষর প্রয়োজন।

উদাহরণ:

@FunctionalInterface
interface CallbackHandler{
    public void onClick();
}

public class MyClass{
    public void doClick1(){System.out.println("doClick1");;}
    public void doClick2(){System.out.println("doClick2");}
    public CallbackHandler mClickListener = this::doClick;

    public static void main(String[] args) {
        MyClass myObjectInstance = new MyClass();
        CallbackHandler pointer = myObjectInstance::doClick1;
        Runnable pointer2 = myObjectInstance::doClick2;
        pointer.onClick();
        pointer2.run();
    }
}

তো, আমাদের এখানে কী আছে?

  1. ফাংশনাল ইন্টারফেস - এটি ইন্টারফেস, এনটোটেড বা @FunctionalInterface এর সাথে নয় , যেখানে কেবলমাত্র একটি পদ্ধতি ঘোষণা রয়েছে।
  2. পদ্ধতির রেফারেন্স - এটি কেবল বিশেষ বাক্য গঠন, এটির মতো দেখতে, অবজেক্টআইএনস্ট্যান্স :: পদ্ধতি নাম , এর চেয়ে বেশি কিছুই কম নয়।
  3. ব্যবহারের উদাহরণ - কেবল একটি অ্যাসাইনমেন্ট অপারেটর এবং তারপরে ইন্টারফেস পদ্ধতি কল।

আপনি কেবলমাত্র এবং কেবলমাত্র তালিকার জন্য ফাংশনাল ইন্টারফেস ব্যবহার করবেন!

কারণ এই জাতীয় অন্যান্য সমস্ত ফাংশন পয়েন্টারগুলি কোড পঠনযোগ্যতা এবং বুঝতে সক্ষমতার জন্য সত্যই খারাপ। যাইহোক, সরাসরি পদ্ধতির উল্লেখগুলি কখনও কখনও কার্যকর হয়, উদাহরণস্বরূপ ভবিষ্যদ্বাণী সহ।

বেশ কয়েকটি পূর্বনির্ধারিত ফাংশনাল ইন্টারফেস রয়েছে:

Runnable              -> void run( );
Supplier<T>           -> T get( );
Consumer<T>           -> void accept(T);
Predicate<T>          -> boolean test(T);
UnaryOperator<T>      -> T apply(T);
BinaryOperator<T,U,R> -> R apply(T, U);
Function<T,R>         -> R apply(T);
BiFunction<T,U,R>     -> R apply(T, U);
//... and some more of it ...
Callable<V>           -> V call() throws Exception;
Readable              -> int read(CharBuffer) throws IOException;
AutoCloseable         -> void close() throws Exception;
Iterable<T>           -> Iterator<T> iterator();
Comparable<T>         -> int compareTo(T);
Comparator<T>         -> int compare(T,T);

পূর্ববর্তী জাভা সংস্করণগুলির জন্য আপনার পেয়ারা গ্রন্থাগারগুলি চেষ্টা করা উচিত, যা অ্যাড্রিয়ান পেট্রেস্কু উপরে উল্লিখিত হিসাবে একই রকম কার্যকারিতা এবং বাক্য গঠন রয়েছে।

অতিরিক্ত গবেষণার জন্য জাভা 8 চিটশিটে দেখুন

এবং জাভা ভাষার স্পেসিফিকেশন §15.13 লিঙ্কটির জন্য দ্য দি গাই দ্য হ্যাটকে ধন্যবাদ


7
" কারণ অন্য সমস্ত ... কোডের পাঠযোগ্যতার জন্য সত্যই খারাপ " এটি ছাড়াও সম্পূর্ণ ভিত্তিহীন দাবি এবং ভুল।
লরেন্স ডল

9

@ এসব্লুন্ডির উত্তর দুর্দান্ত, তবে বেনামে অভ্যন্তরীণ শ্রেণীর দুটি ছোট ত্রুটি রয়েছে, প্রাথমিক কারণ হচ্ছে তারা পুনরায় ব্যবহারযোগ্য হবে না এবং মাধ্যমিকটি একটি বিশাল বাক্য গঠন।

সুন্দর জিনিসটি হ'ল তার প্যাটার্নটি মূল শ্রেণিতে কোনও পরিবর্তন ছাড়াই পুরো ক্লাসে প্রসারিত হয় (গণনা সম্পাদনকারী)।

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

f(x,y)=x*y

তবে কখনও কখনও আপনার একটি প্রয়োজন যা:

f(x,y)=x*y*2

এবং সম্ভবত তৃতীয়টি হ'ল:

f(x,y)=x*y/2

দুটি বেনামে অভ্যন্তরীণ ক্লাস করা বা "পাসস্ট্র্রু" প্যারামিটার যুক্ত করার পরিবর্তে আপনি একটি একক বাস্তব শ্রেণি তৈরি করতে পারেন যা আপনি ইনস্ট্যান্ট করেন:

InnerFunc f=new InnerFunc(1.0);// for the first
calculateUsing(f);
f=new InnerFunc(2.0);// for the second
calculateUsing(f);
f=new InnerFunc(0.5);// for the third
calculateUsing(f);

এটি কেবল ক্লাসে ধ্রুবক সংরক্ষণ করবে এবং ইন্টারফেসে নির্দিষ্ট পদ্ধতিতে এটি ব্যবহার করবে।

প্রকৃতপক্ষে, যদি আপনার জানা যায় যে আপনার ফাংশনটি সংরক্ষণ করা / পুনঃব্যবহৃত হবে না, আপনি এটি করতে পারেন:

InnerFunc f=new InnerFunc(1.0);// for the first
calculateUsing(f);
f.setConstant(2.0);
calculateUsing(f);
f.setConstant(0.5);
calculateUsing(f);

তবে অপরিবর্তনীয় শ্রেণি নিরাপদ - আমি এই পরিবর্তনীয় মত একটি বর্গ তৈরি করার ন্যায়সঙ্গততা নিয়ে আসতে পারি না।

আমি সত্যিই কেবল এটি পোস্ট করেছি কারণ যখনই আমি বেনাম অভ্যন্তরীণ শ্রেনী শুনতে পেলাম - আমি প্রচুর অপ্রয়োজনীয় কোডটি দেখেছি যা "প্রয়োজনীয়" ছিল কারণ প্রোগ্রামার যখন প্রথম কাজটি করেছিল তখন বেনামে চলে যেত যখন তাকে আসল ক্লাস ব্যবহার করা উচিত ছিল এবং কখনই না তার সিদ্ধান্ত নিয়ে পুনর্বিবেচনা করেছেন।


তাই না? ওপি বিভিন্ন গণনা (আলগোরিদম; যুক্তি) সম্পর্কে কথা বলছে ; আপনি বিভিন্ন মান (ডেটা) দেখাচ্ছে । আপনি কোনও নির্দিষ্ট কেস দেখান যেখানে পার্থক্যটিকে একটি মানতে সংযুক্ত করা যায় তবে সমস্যাটি উত্থাপিত হওয়ার এটি একটি অযৌক্তিক সরলীকরণ।
টুলমেকারস্টেভ

6

গুগল পেয়ারা লাইব্রেরিগুলি , যা খুব জনপ্রিয় হয়ে উঠছে, একটি জেনেরিক ফাংশন এবং প্রিডিকেট অবজেক্ট রয়েছে যে তারা তাদের এপিআইয়ের অনেকগুলি অংশে কাজ করেছে।


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

4

আমার কাছে কৌশল কৌশল হিসাবে মনে হচ্ছে। Fluffycat.com জাভা নিদর্শনগুলি দেখুন।


4

জাভাতে প্রোগ্রামিং করার সময় আমি যে জিনিসগুলি সত্যিই মিস করি সেগুলির একটি হ'ল ফাংশন কলব্যাক্স। একটি পরিস্থিতি যেখানে এগুলি নিজেকে উপস্থাপন করে রাখার প্রয়োজনটি ছিল ক্রমবর্ধমান স্তরক্রমগুলি প্রক্রিয়াজাতকরণ যেখানে আপনি প্রতিটি আইটেমের জন্য কিছু নির্দিষ্ট ক্রিয়া সম্পাদন করতে চান। ডিরেক্টরি ট্রি হাঁটার মতো, বা ডেটা স্ট্রাকচার প্রক্রিয়াজাতকরণ। আমার অভ্যন্তরের সংক্ষিপ্ত তালিকাটি একটি নির্দিষ্ট ইন্টারফেসের এবং তারপরে প্রতিটি নির্দিষ্ট ক্ষেত্রে কার্যকর করার জন্য সংজ্ঞা দেয়।

একদিন আমি নিজেকে ভেবে দেখলাম কেন নয়? আমাদের কাছে মেথড পয়েন্টার রয়েছে - মেথড অবজেক্ট। জেআইটি সংকলকদের অনুকূলকরণের সাথে সাথে, প্রতিফলিত প্রার্থনা সত্যই আর বিশাল পারফরম্যান্স পেনাল্টি বহন করে না। এবং এর পরেও বলুন, এক ফাইল থেকে অন্য জায়গায় একটি ফাইল অনুলিপি করা, প্রতিবিম্বিত পদ্ধতির প্রার্থনার ব্যয় তুচ্ছ হয়ে যায়।

আমি এটি সম্পর্কে আরও চিন্তাভাবনা করার পরে, আমি বুঝতে পেরেছি যে ওওপি দৃষ্টান্তের কলব্যাকের জন্য একটি অবজেক্ট এবং একটি পদ্ধতি একসাথে আবদ্ধ করা দরকার - কলব্যাক অবজেক্টটি প্রবেশ করান।

জাভাতে কলব্যাক্সের জন্য আমার প্রতিবিম্ব ভিত্তিক সমাধানটি দেখুন । যে কোনও ব্যবহারের জন্য বিনামূল্যে।


4

ওকে, এই থ্রেডটি ইতিমধ্যে যথেষ্ট পুরানো, সম্ভবত খুব সম্ভবত আমার উত্তর প্রশ্নের পক্ষে সহায়ক নয়। তবে যেহেতু এই থ্রেডটি আমাকে আমার সমাধান খুঁজে পেতে সহায়তা করেছে, তাই আমি এটিকে যাইহোক এখানেই রেখে দেব।

আমার পরিচিত ইনপুট এবং জ্ঞাত আউটপুট (উভয় ডাবল ) সহ একটি পরিবর্তনশীল স্থির পদ্ধতি ব্যবহার করা দরকার । সুতরাং, পদ্ধতি প্যাকেজ এবং নাম জেনে আমি নিম্নলিখিত হিসাবে কাজ করতে পারি:

java.lang.reflect.Method Function = Class.forName(String classPath).getMethod(String method, Class[] params);

একটি ফাংশন যা প্যারামিটার হিসাবে এক ডাবল গ্রহণ করে।

সুতরাং, আমার দৃ concrete় পরিস্থিতিতে আমি এটি দিয়ে সূচনা করেছি

java.lang.reflect.Method Function = Class.forName("be.qan.NN.ActivationFunctions").getMethod("sigmoid", double.class);

এবং এটি আরও জটিল পরিস্থিতিতে পরে ডেকে আনে

return (java.lang.Double)this.Function.invoke(null, args);

java.lang.Object[] args = new java.lang.Object[] {activity};
someOtherFunction() + 234 + (java.lang.Double)Function.invoke(null, args);

যেখানে ক্রিয়াকলাপ একটি স্বেচ্ছাসেবী দ্বৈত মান। সফটওয়্যার মোনকি যেমনটি করেছেন তেমন আমি এটি আরও কিছুটা বিমূর্ত এবং সাধারণীকরণের কথা ভাবছি তবে বর্তমানে আমি এটির মতো উপায় নিয়ে যথেষ্ট খুশি। তিন লাইনের কোড, কোনও ক্লাস এবং ইন্টারফেসের প্রয়োজন নেই, এটি খুব খারাপ নয়।



4

ক্রিয়াকলাপগুলির একটি অ্যারের জন্য ইন্টারফেস ছাড়াই একই জিনিসটি করতে:

class NameFuncPair
{
    public String name;                // name each func
    void   f(String x) {}              // stub gets overridden
    public NameFuncPair(String myName) { this.name = myName; }
}

public class ArrayOfFunctions
{
    public static void main(String[] args)
    {
        final A a = new A();
        final B b = new B();

        NameFuncPair[] fArray = new NameFuncPair[]
        {
            new NameFuncPair("A") { @Override void f(String x) { a.g(x); } },
            new NameFuncPair("B") { @Override void f(String x) { b.h(x); } },
        };

        // Go through the whole func list and run the func named "B"
        for (NameFuncPair fInstance : fArray)
        {
            if (fInstance.name.equals("B"))
            {
                fInstance.f(fInstance.name + "(some args)");
            }
        }
    }
}

class A { void g(String args) { System.out.println(args); } }
class B { void h(String args) { System.out.println(args); } }

1
কেন? এটি পূর্ব প্রস্তাবিত সমাধানগুলির চেয়ে জটিল, যার বিকল্প হিসাবে কেবল একটি বেনাম ফাংশন সংজ্ঞা প্রয়োজন। প্রতি বিকল্প হিসাবে, আপনি একটি বর্গ এবং একটি বেনাম ফাংশন সংজ্ঞা তৈরি করুন। সবচেয়ে খারাপ, কোডে দুটি পৃথক স্থানে এটি করা হয়। আপনি এই পদ্ধতির ব্যবহারের জন্য কিছু ন্যায়সঙ্গততা সরবরাহ করতে চাইতে পারেন।
নির্মাতা স্টিভ

3

ল্যাম্বডাজ দেখুন

http://code.google.com/p/lambdaj/

এবং বিশেষত এটির নতুন ক্লোজার বৈশিষ্ট্য

http://code.google.com/p/lambdaj/wiki/Closures

এবং আপনি অর্থহীন ইন্টারফেস তৈরি না করে বা কুৎসিত অভ্যন্তর শ্রেণি ব্যবহার না করে ক্লোজার বা ফাংশন পয়েন্টার সংজ্ঞায়নের জন্য খুব পঠনযোগ্য উপায় পাবেন


3

বাহ, কেন কেবল একটি ডেলিগেট ক্লাস তৈরি করবেন না যা জাভা জন্য আমি ইতিমধ্যে করেছি এবং টি ফিরে আসার টাইপ যেখানে প্যারামিটারে পাস করার জন্য এটি ব্যবহার করে তা এতটা শক্ত নয়। আমি দুঃখিত, তবে সি ++ / সি # প্রোগ্রামার হিসাবে সাধারণভাবে জাভা শিখছি, আমার ফাংশন পয়েন্টার প্রয়োজন কারণ তারা খুব কার্যকরী। আপনি যদি এমন কোনও ক্লাসের সাথে পরিচিত হন যা পদ্ধতি সম্পর্কিত তথ্য নিয়ে কাজ করে তবে আপনি এটি করতে পারেন। জাভা লাইব্রেরিতে যা জাভা.লাং.রেফলেট.মোথড হবে।

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


আপনি কোডের বিশদটি না দেখলে কোনও দরকারী উত্তর নয়। একজন প্রতিনিধি শ্রেণি তৈরি করা কীভাবে সহায়তা করে? বিকল্প হিসাবে কি কোড প্রয়োজন?
টুলমেকারস্টেভ

2

জাভা 8 টির উত্তরগুলির মধ্যে একটিও একটি সম্পূর্ণ, সম্মিলিত উদাহরণ দেয় নি, তাই এটি এখানে আসে।

নিম্নলিখিত পদ্ধতি "ফাংশন পয়েন্টার" গ্রহণ করে যে পদ্ধতিটি ঘোষণা করুন:

void doCalculation(Function<Integer, String> calculation, int parameter) {
    final String result = calculation.apply(parameter);
}

ল্যাম্বডা এক্সপ্রেশন সহ ফাংশন সরবরাহ করে এটি কল করুন:

doCalculation((i) -> i.toString(), 2);

1

যদি কেউ এমন কোনও ক্রিয়াকলাপটি পাস করতে লড়াই করে যা যা তার আচরণটি নির্ধারণ করতে প্যারামিটারগুলির একটি সেট নেয় তবে স্ক্রিমটির মতো প্যারামিটারগুলির একটি সেট নির্বাহ করতে হয়:

(define (function scalar1 scalar2)
  (lambda (x) (* x scalar1 scalar2)))

জাভাতে প্যারামিটার-সংজ্ঞায়িত আচরণ সহ পাস ফাংশন দেখুন


1

জাভা 8-এর পর থেকে, আপনি ল্যাম্বডাস ব্যবহার করতে পারেন, যার অফিসিয়াল এসই 8 এপিআইতে লাইব্রেরি রয়েছে।

ব্যবহার: আপনাকে কেবল একটি বিমূর্ত পদ্ধতি সহ একটি ইন্টারফেস ব্যবহার করতে হবে। এর একটি উদাহরণ তৈরি করুন (আপনি ইতিমধ্যে সরবরাহ করা একটি জাভা এসই 8 ব্যবহার করতে চাইতে পারেন) এর মতো:

Function<InputType, OutputType> functionname = (inputvariablename) {
... 
return outputinstance;
}

আরও তথ্যের জন্য ডকুমেন্টেশন চেকআউট করুন: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html


1

জাভা 8 এর আগে, ফাংশন-পয়েন্টার-জাতীয় কার্যকারিতার নিকটতম বিকল্পটি ছিল একটি বেনাম শ্রেণি। উদাহরণ স্বরূপ:

Collections.sort(list, new Comparator<CustomClass>(){
    public int compare(CustomClass a, CustomClass b)
    {
        // Logic to compare objects of class CustomClass which returns int as per contract.
    }
});

তবে এখন জাভা 8-এ আমাদের খুব ঝরঝরে বিকল্প রয়েছে যা ল্যাম্বডা এক্সপ্রেশন হিসাবে পরিচিত , যা ব্যবহার করা যেতে পারে:

list.sort((a, b) ->  { a.isBiggerThan(b) } );

যেখানে বিগারথান হল একটি পদ্ধতি CustomClass। আমরা এখানে পদ্ধতি উল্লেখগুলিও ব্যবহার করতে পারি:

list.sort(MyClass::isBiggerThan);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.