কলযোগ্য <টি> এবং জাভা 8 এর সরবরাহকারী <টি> এর মধ্যে পার্থক্য কী?


13

কোডআরভিউতে কিছু ওজনের কিছু প্রস্তাবনার পরে আমি সি # থেকে জাভাতে স্যুইচ করছি। সুতরাং, আমি যখন এলডাব্লুজেজিএল-এর দিকে তাকাচ্ছিলাম, তখন একটি জিনিস আমার মনে পড়েছিল যে পদ্ধতিটি Displayচালিত হয়েছিল সেই একই থ্রেডে অবশ্যই প্রতিটি কল সম্পাদন করা উচিত Display.create()। এটি মনে রাখার পরে, আমি এমন একটি ক্লাস বেতার দিয়েছি যা দেখতে কিছুটা এইরকম দেখাচ্ছে।

public class LwjglDisplayWindow implements DisplayWindow {
    private final static int TargetFramesPerSecond = 60;
    private final Scheduler _scheduler;

    public LwjglDisplayWindow(Scheduler displayScheduler, DisplayMode displayMode) throws LWJGLException {
        _scheduler = displayScheduler;
        Display.setDisplayMode(displayMode);
        Display.create();
    }

    public void dispose() {
        Display.destroy();
    }

    @Override
    public int getTargetFramesPerSecond() { return TargetFramesPerSecond; }

    @Override
    public Future<Boolean> isClosed() {
        return _scheduler.schedule(() -> Display.isCloseRequested());
    }
}

এই শ্রেণিটি লেখার সময় আপনি খেয়াল করবেন যে আমি একটি পদ্ধতি তৈরি করেছি isClosed()যা একটি রিটার্ন বলে Future<Boolean>। এটি আমার Schedulerইন্টারফেসে একটি ফাংশন প্রেরণ করে (যা কোনও চারপাশে মোড়কের চেয়ে বেশি কিছু নয় ScheduledExecutorServicethe scheduleপদ্ধতিতে লেখার সময় Schedulerআমি লক্ষ্য করেছি যে আমি যে ফাংশনটি পাশ করেছে তা উপস্থাপনের জন্য একটি Supplier<T>যুক্তি বা একটি Callable<T>যুক্তি ব্যবহার করতে পারি ScheduledExecutorServicean এতে কোনটি ছিল না জন্য ওভাররাইড Supplier<T>কিন্তু আমি লক্ষ্য করেছি যে, ল্যামডা অভিব্যক্তি () -> Display.isCloseRequested()আসলে উভয় সঙ্গে সামঞ্জস্যপূর্ণ ধরনের Callable<bool> এবং Supplier<bool>

আমার প্রশ্নটি হল, শব্দার্থগতভাবে বা অন্যথায় এই দুটিয়ের মধ্যে কোনও পার্থক্য রয়েছে - এবং যদি তা হয় তবে এটি কী, তাই আমি এটি মেনে চলতে পারি?


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

.. কোন কিছুর শব্দার্থ সম্পর্কে জিজ্ঞাসা করা কোন ধারণামূলক প্রশ্ন নয়?
ড্যান প্যান্ট্রি

আমি মনে করি এটি একটি ধারণাগত প্রশ্ন, এই সাইটের অন্যান্য ভাল প্রশ্নের মতো ধারণাগত নয় তবে এটি বাস্তবায়নের বিষয়ে নয়। কোড কাজ করে, প্রশ্ন কোড সম্পর্কে নয়। প্রশ্নটি জিজ্ঞাসা করছে "এই দুটি ইন্টারফেসের মধ্যে পার্থক্য কী?"

আপনি কেন সি # থেকে জাভাতে স্যুইচ করতে চান!
দিদিয়ার এ

2
এর মধ্যে একটি পার্থক্য রয়েছে, যথা Callable.call () ব্যতিক্রম ছুঁড়ে ফেলে এবং Provider.get () দেয় না। যা ল্যাম্বদা এক্সপ্রেশনগুলিকে পরবর্তীকালে অনেক বেশি আকর্ষণীয় করে তোলে।
থরবজর্ন রাভন অ্যান্ডারসন

উত্তর:


6

সংক্ষিপ্ত উত্তরটি হ'ল উভয় ফাংশনাল ইন্টারফেস ব্যবহার করছে তবে এটি বিবেচনার জন্যও উপযুক্ত যে সমস্ত কার্যকরী ইন্টারফেসের @FunctionalInterfaceটীকাটি হওয়া উচিত নয় । জাভাডকের সমালোচনা অংশটি পড়ে:

তবে সংকলকটি কোনও ইন্টারফেসের সংজ্ঞা পূরণের কোনও কার্যকারিতা ইন্টারফেস হিসাবে কার্যকারিতা ইন্টারফেস হিসাবে বিবেচনা করবে, কার্যকারিতা ইন্টারফেস ঘোষণায় ফাংশনাল ইনটারফেস টিকা আছে কিনা তা নির্বিশেষে।

এবং একটি কার্যকরী ইন্টারফেসের সহজ সংজ্ঞাটি হ'ল (কেবলমাত্র অন্যান্য ব্যতিক্রম ছাড়াই) কেবলমাত্র:

ধারণামূলকভাবে, একটি ক্রিয়ামূলক ইন্টারফেসের ঠিক একটি বিমূর্ত পদ্ধতি রয়েছে।

সুতরাং, @ ম্যাসিজে চালাপুকের উত্তরে, টীকাটি ফেলে দেওয়া এবং পছন্দসই ল্যাম্বদা নির্দিষ্ট করাও সম্ভব:

// interface
public interface MyInterface {
    boolean myCall(int arg);
}

// method call
public boolean invokeMyCall(MyInterface arg) {
    return arg.myCall(0);
}

// usage
instance.invokeMyCall(a -> a != 0); // returns true if the argument supplied is not 0

এখন, যা উভয় Callableএবং Supplierকার্যকরী ইন্টারফেসগুলি তোলে তা হ'ল কারণ এগুলিতে ঠিক একটি বিমূর্ত পদ্ধতি রয়েছে:

  • Callable.call()
  • Supplier.get()

যেহেতু উভয় পদ্ধতিই একটি যুক্তিতে গ্রহণ করে না ( MyInterface.myCall(int)উদাহরণটির বিপরীতে ), আনুষ্ঠানিক পরামিতিগুলি খালি ( ())।

আমি লক্ষ করেছি যে ল্যাম্বডা এক্সপ্রেশনটি () -> Display.isCloseRequested()আসলে Callable<Boolean> এবং উভয়ের সাথেই সুসংগত Supplier<Boolean>

আপনার এখনই অনুমান করতে সক্ষম হওয়া উচিত, এটি কেবল কারণ দুটি বিমূর্ত পদ্ধতিই আপনি যেভাবে ব্যবহার করেন তা প্রকাশ করবে। আপনার অবশ্যই একটি Callableদেওয়া আপনার ব্যবহারের উচিত ScheduledExecutorService

আরও অনুসন্ধান (প্রশ্নের ক্ষেত্রের বাইরে)

উভয় ইন্টারফেস সম্পূর্ণ ভিন্ন প্যাকেজ থেকে আসে , তাই এগুলিও আলাদাভাবে ব্যবহৃত হয়। আপনার ক্ষেত্রে, আমি দেখতে পাই Supplier<T>না যে এটির সরবরাহ না করা হলে এর বাস্তবায়ন কীভাবে ব্যবহৃত হবে Callable:

public static <T> Supplier<Callable<T>> getCallable(T value) {
    return () -> () -> {
        return value;
    };
}

প্রথমটি () ->আলগাভাবে "একটি Supplierদেয় ..." এবং দ্বিতীয়টি "একটি দেয় ..." হিসাবে ব্যাখ্যা করা যেতে পারে Callable। ল্যাম্বদা return value;এর দেহ Callable, যা নিজেই Supplierল্যাম্বার দেহ ।

যাইহোক, এই দ্বন্দ্বযুক্ত উদাহরণে ব্যবহার কিছুটা জটিল get()হয়ে ওঠে , কারণ এখন থেকে আপনার ফলাফলটি তৈরির Supplierআগে প্রথম get()থেকেই আপনার দরকার Future, যা call()আপনার Callableঅ্যাসিঙ্ক্রোনাসিতে পরিণত হবে ।

public static <T> T doWork(Supplier<Callable<T>> callableSupplier) {
    // service being an instance of ExecutorService
    return service.submit(callableSupplier.get()).get();
}

1
আমি এই উত্তরের স্বীকৃত উত্তরটি পরিবর্তন করছি কারণ এটি কেবল আরও বেশি বিস্তৃত
ড্যান প্যান্ট্রি

দীর্ঘতর আরও দরকারী হিসাবে সমান হয় না, দেখুন @ srrm_lwn এর উত্তর।
সেন্সরস্মিত

@ সেন্সরস্মিথ srrms উত্তরটি আসলটি ছিল যা আমি স্বীকৃত উত্তর হিসাবে চিহ্নিত করেছি। আমি এখনও মনে করি এটি আরও কার্যকর।
ড্যান প্যান্ট্রি

21

২ টি ইন্টারফেসের মধ্যে একটি প্রাথমিক পার্থক্য হ'ল কলযোগ্য চেক করা ব্যতিক্রমগুলি এর বাস্তবায়নের মধ্যে থেকে ফেলে দেওয়া মঞ্জুরি দেয়, অন্যদিকে সরবরাহকারী তা করেন না।

জেডিকে থেকে কোড স্নিপেটগুলি এখানে হাইলাইট করছে -

@FunctionalInterface
public interface Callable<V> {
/**
 * Computes a result, or throws an exception if unable to do so.
 *
 * @return computed result
 * @throws Exception if unable to compute a result
 */
V call() throws Exception;
}

@FunctionalInterface
public interface Supplier<T> {

/**
 * Gets a result.
 *
 * @return a result
 */
T get();
}

এটি কর্মক্ষম ইন্টারফেসে আর্গুমেন্ট হিসাবে কলযোগ্যকে অযোগ্য করে তোলে।
বেসিলিভ

3
@ বাসিলভ এটি করেন না - Supplierস্ট্রিম এপিআইয়ের মতো এমন জায়গাগুলিতে এটি কেবল ব্যবহারযোগ্য নয় । আপনি একেবারে ল্যাম্বডাস এবং পদ্ধতি রেফারেন্সগুলিতে পাস করতে পারেন যা গ্রহণ করে Callable
dimo414

12

আপনারা যেমন লক্ষ্য করেছেন, বাস্তবে তারা একই কাজ করে থাকে (কিছু প্রকারের মূল্য সরবরাহ করে) তবে নীতিগতভাবে তারা বিভিন্ন জিনিস করার উদ্দেশ্যে থাকে :

Callableহ'ল " একটি টাস্ক যা ফলাফল দেয় , যখন একটি Supplier" ফলাফল সরবরাহকারী "। অন্য কথায় একটি Callableহ'ল কাজের অ-অ-ইউনিটকে রেফারেন্স করার একটি উপায়, যখন Supplierএকটি এখনও একটি অজানা মানকে উল্লেখ করার উপায়।

এটি সম্ভব যে কোনও Callableখুব কম কাজ করতে পারে এবং কেবল একটি মান ফিরিয়ে দেয়। এটিও Supplierবেশ কিছু কাজ করা সম্ভব (উদাহরণস্বরূপ একটি বড় ডেটা কাঠামো তৈরি করা)। তবে সাধারণত আপনি যেগুলির সাথেই যত্নশীল তা বলা তাদের নীতিগত উদ্দেশ্য। উদাহরণস্বরূপ একটি গুলি এর ExecutorServiceসাথে কাজ করে Callableকারণ এটির প্রাথমিক উদ্দেশ্য হ'ল কাজের ইউনিটগুলি চালানো । একটি অলস-বোঝা ডেটা স্টোর একটি ব্যবহার করবে Supplier, কারণ এটি কতটা কাজ নিতে পারে তা নিয়ে খুব বেশি উদ্বেগ ছাড়াই কোনও মূল্য সরবরাহ করার বিষয়ে চিন্তা করে ।

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


2

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

আপনি ল্যাম্বডাসের সাথে সামঞ্জস্যপূর্ণ আপনার নিজের ইন্টারফেসগুলি সংজ্ঞায়িত করতে পারেন এবং এগুলি @FunctionalInterfaceটীকা সহ ডকুমেন্ট করতে পারেন । ডকুমেন্টিং যদিও alচ্ছিক।

@FunctionalInterface
public interface MyInterface {
    boolean myCall(int arg);
}

...

MyInterface var = (int a) -> a != 0;

যদিও এই নির্দিষ্ট ইন্টারফেসটি IntPredicateজাভাতে ডাকা হয়।
কনরাড বোরোস্কি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.