জাভা 8-এ ল্যাম্বদা সিনট্যাক্সের পরিবর্তে পদ্ধতিটি রেফারেন্স সিনট্যাক্স ব্যবহার করে কোনও পারফরম্যান্স সুবিধা রয়েছে?


56

পদ্ধতির উল্লেখগুলি কি ল্যাম্বদা মোড়কের ওভারহেড এড়িয়ে যায়? তারা ভবিষ্যতে হতে পারে?

মতে পদ্ধতি রেফারেন্স জাভা টিউটোরিয়াল :

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

আমি বেশ কয়েকটি কারণে পদ্ধতির রেফারেন্স সিনট্যাক্সের চেয়ে ল্যাম্বডা সিনট্যাক্সটিকে পছন্দ করি:

লাম্বদাস পরিষ্কার হয়

ওরাকলের দাবী সত্ত্বেও, লাম্বডা সিনট্যাক্সটি অবজেক্ট মেথড রেফারেন্স শর্ট-হ্যান্ডের চেয়ে সহজ-পঠনযোগ্য বলে মনে করি কারণ পদ্ধতির রেফারেন্স সিনট্যাক্সটি দ্ব্যর্থক:

Bar::foo

আপনি কি এক্স এর ক্লাসে একটি স্ট্যাটিক ওয়ান-আর্গুমেন্ট পদ্ধতি কল করছেন এবং এটি এক্স দিয়ে যাচ্ছেন?

x -> Bar.foo(x)

বা আপনি কি একটি শূন্য-আর্গুমেন্ট উদাহরণ পদ্ধতি কল করছেন?

x -> x.foo()

পদ্ধতি রেফারেন্স সিনট্যাক্স একটির জন্য দাঁড়িয়ে থাকতে পারে। এটি আপনার কোডটি আসলে কী করছে তা লুকিয়ে রাখে।

লাম্বদাস নিরাপদ

আপনি যদি বার :: foo কে ক্লাস পদ্ধতি হিসাবে উল্লেখ করেন এবং বার পরে একই নামের একটি উদাহরণ পদ্ধতি (বা তদ্বিপরীত) যোগ করে, আপনার কোড আর সংকলন করবে না।

আপনি ধারাবাহিকভাবে ল্যাম্বডাস ব্যবহার করতে পারেন

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

উপসংহার

যদি এটি করার জন্য কোনও পারফরম্যান্স জরিমানা না থাকে তবে আমি আমার আইডিইতে সতর্কতাটি বন্ধ করতে এবং লম্বা সিনট্যাক্সটি আমার কোডটিতে মাঝে মধ্যে পদ্ধতি রেফারেন্সটি ছড়িয়ে না দিয়ে ধারাবাহিকভাবে ব্যবহার করতে প্ররোচিত হই।

দ্রষ্টব্য

এখানে বা সেখানেই নয়, তবে আমার স্বপ্নে অবজেক্ট পদ্ধতির উল্লেখগুলি আরও দেখতে দেখতে এবং ল্যাম্বডা মোড়ক ছাড়াই সরাসরি অবজেক্টে পদ্ধতির বিপরীতে ডাকে ডাইনামিক প্রয়োগ করে:

_.foo()

2
এটি আপনার প্রশ্নের উত্তর দেয় না, তবে ক্লোজারগুলি ব্যবহারের অন্যান্য কারণও রয়েছে। আমার মতে, তাদের মধ্যে অনেকগুলি অতিরিক্ত ফাংশন কলের ক্ষুদ্র ওভারহেডকে ছাড়িয়ে যায়।

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

7
.map(_.acceptValue()): যদি আমার ভুল না হয় তবে এটি দেখতে অনেকটা স্কাল সিনট্যাক্সের মতো। হতে পারে আপনি কেবল ভুল ভাষা ব্যবহার করার চেষ্টা করছেন।
জর্জিও

2
"পদ্ধতি রেফারেন্স সিনট্যাক্সগুলি যে পদ্ধতিগুলি শূন্য হয় তার উপর কাজ করবে না" - কীভাবে? আমি পার করছি System.out::printlnকরার forEach()সব সময় ...?
লুকাস এদার

3
"পদ্ধতি রেফারেন্স সিনট্যাক্স সেই পদ্ধতিগুলিতে কাজ করবে না যেগুলি আদিম অ্যারে গ্রহণ করে বা ফিরিয়ে দেয়, পরীক্ষিত ব্যতিক্রম ছুঁড়ে ফেলে ...." এটি সঠিক নয়। যতক্ষণ প্রশ্নে কার্যকরী ইন্টারফেস এটির অনুমতি দেয় আপনি ততক্ষণ ক্ষেত্রে পদ্ধতির উল্লেখগুলি এবং এ জাতীয় ক্ষেত্রে ল্যাম্বদা এক্সপ্রেশন ব্যবহার করতে পারেন।
স্টুয়ার্ট

উত্তর:


12

অনেক পরিস্থিতিতে, আমি ল্যাম্বদা এবং পদ্ধতি-রেফারেন্স সমতুল্য বলে মনে করি। তবে ল্যাম্বদা ঘোষিত ইন্টারফেসের ধরণের মাধ্যমে অনুরোধের লক্ষ্যটি মোড়বে।

উদাহরণ স্বরূপ

public class InvokeTest {

    private static void invoke(final Runnable r) {
        r.run();
    }

    private static void target() {
        new Exception().printStackTrace();
    }

    @Test
    public void lambda() throws Exception {
        invoke(() -> target());
    }

    @Test
    public void methodReference() throws Exception {
        invoke(InvokeTest::target);
    }
}

আপনি স্ট্যাকট্রেস কনসোল আউটপুট দেখতে পাবেন।

ইন lambda(), পদ্ধতি কলিং target()হল lambda$lambda$0(InvokeTest.java:20), যার সন্ধানযোগ্য লাইন তথ্য রয়েছে। স্পষ্টতই, এটি যে ল্যাম্বদা আপনি লিখেন, সংকলকটি আপনার জন্য একটি বেনামি পদ্ধতি উত্পন্ন করে। এবং তারপরে, ল্যাম্বডা পদ্ধতির কলকারীটি InvokeTest$$Lambda$2/1617791695.run(Unknown Source)হ'ল এটি invokedynamicজেভিএমের কল call এটির অর্থ কলটি উত্পন্ন পদ্ধতির সাথে যুক্ত

ইন methodReference(), পদ্ধতি কলটি target()সরাসরি হয় InvokeTest$$Lambda$1/758529971.run(Unknown Source), এর অর্থ কলটি সরাসরি InvokeTest::targetপদ্ধতির সাথে যুক্ত থাকে

উপসংহার

সর্বোপরি, ল্যামডা অভিব্যক্তি ব্যবহার করে শুধুমাত্র কারণ হবে, পদ্ধতি-রেফারেন্স তুলনা এক ল্যামডা থেকে উৎপাদিত পদ্ধতি আরো পদ্ধতি কল।


1
মেটাফ্যাক্টরি সম্পর্কে নীচের উত্তরটি কিছুটা ভাল। আমি কিছু দরকারী মন্তব্য এটি (সাথে প্রাসঙ্গিক যোগ যথা কিভাবে ওরাকল / OpenJDK ব্যবহার এ এস এম মত বাস্তবায়নের রাপার ক্লাস বস্তু দৃষ্টান্ত ল্যামডা / পদ্ধতি হ্যান্ডেল তৈরি করতে প্রয়োজন তৈরি করতে।
আয়াক্স

29

সবই মেটাফ্যাক্টরি নিয়ে about

প্রথমত, বেশিরভাগ পদ্ধতির রেফারেন্সগুলিতে ল্যাম্বদা মেটাফ্যাক্টরি দ্বারা ডিজুয়ারিংয়ের প্রয়োজন হয় না, এগুলি কেবল রেফারেন্স পদ্ধতি হিসাবে ব্যবহৃত হয়। ল্যাম্বদা এক্সপ্রেশনস এর অনুবাদ "" টিএলএই "" নিবন্ধের "ল্যাম্বডা বডি চিনিযুক্ত" বিভাগের অধীনে :

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

এটি টিএলইর "দ্য ল্যাম্বদা মেটাফ্যাক্টরি" তে আরও নিচে তুলে ধরা হয়েছে:

metaFactory(MethodHandles.Lookup caller, // provided by VM
            String invokedName,          // provided by VM
            MethodType invokedType,      // provided by VM
            MethodHandle descriptor,     // lambda descriptor
            MethodHandle impl)           // lambda body

implযুক্তি ল্যামডা পদ্ধতি, হয় একটি desugared ল্যামডা শরীর বা পদ্ধতি একটি পদ্ধতি রেফারেন্স নামে চিহ্নিত করা হয়।

একটি স্ট্যাটিক ( Integer::sum) বা সীমাহীন উদাহরণ পদ্ধতি ( Integer::intValue) উল্লেখগুলি হ'ল ' সিম্পল ' বা সর্বাধিক 'সুবিধাজনক', এই অর্থে যে তারা অনুকূলভাবে ' দ্রুতগতিতে ' মেটাফ্যাক্টরি বৈকল্পিক দ্বারা ডিজাইনিং ছাড়াই পরিচালিত হতে পারে । এই সুবিধাটি টিএলইর "মেটাফ্যাক্টরির রূপগুলিতে" সহায়তার সাথে নির্দেশিত হয়েছে:

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

স্বাভাবিকভাবেই, একটি দৃষ্টান্ত-ক্যাপচারিং পদ্ধতি রেফারেন্স ( obj::myMethod) অনুরোধের জন্য পদ্ধতি হ্যান্ডেলের আর্গুমেন্ট হিসাবে সীমিত উদাহরণ সরবরাহ করা প্রয়োজন, যার অর্থ 'সেতু' পদ্ধতি ব্যবহার করে ডিজুয়ারিংয়ের প্রয়োজন হতে পারে।

উপসংহার

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


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

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

1
সম্ভবত একটি বেসরকারী পদ্ধতিতে ভার্চুয়াল প্রেরণেরও প্রয়োজন হবে না, যেখানে আরও কিছু জনসাধারণের প্রয়োজনের (উদাহরণস্বরূপ) উত্পন্ন স্ট্যাটিক পদ্ধতির মাধ্যমে) বন্ধ করা দরকার যাতে এটি প্রকৃত নজরে লক্ষ্য করা যায় না তা নিশ্চিত করার জন্য এটি উদ্বোধন করতে পারে। টিএল; ডিআর: পদ্ধতি উল্লেখগুলি কম আর্গুমেন্টের কাছাকাছি চলে আসে, তাই এগুলি কম ফাঁস হয় এবং ডায়নামিক কোড উত্পন্নকরণের প্রয়োজন হয়।
আজাক্স

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

@ আজাক্স এই সম্পর্কে কি? blog.soat.fr/2015/12/benchmark-java-lambda-vs-classe-anonyme
ওয়ালফ্র্যাট

0

ল্যাম্বডা এক্সপ্রেশন ব্যবহার করার সময় একটি মারাত্মক পরিণতি ঘটে যা পারফরম্যান্সকে প্রভাবিত করতে পারে।

যখন আপনি একটি ল্যাম্বডা এক্সপ্রেশন ঘোষণা করেন, আপনি স্থানীয় ক্ষেত্রের উপরে একটি বন্ধকরণ তৈরি করছেন ।

এর অর্থ কী এবং এটি কার্য সম্পাদনকে কীভাবে প্রভাবিত করে?

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

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


একই স্থিতিশীল পদ্ধতি রেফারেন্স জন্য যায়।
আজাক্স

12
জাভা ল্যাম্বডাস কঠোরভাবে বন্ধ হয় না। তারা অনামী অন্তর্গত শ্রেণি হয় না। তারা যেখানে ঘোষিত হয়েছে সেখানে সমস্ত ভেরিয়েবলের রেফারেন্স বহন করে না। তারা কেবলমাত্র বাস্তবে উল্লেখ করা যায় এমন ভেরিয়েবলগুলির একটি রেফারেন্স রাখে। এটি রেফারেন্স হতে পারে এমন thisবস্তুর ক্ষেত্রেও প্রযোজ্য । সুতরাং একটি ল্যাম্বডা কেবল তাদের জন্য সুযোগ থাকার কারণে সংস্থানগুলি ফাঁস করে না; এটি কেবল এটির প্রয়োজনীয় জিনিসগুলিকে ধরে রাখে। অন্যদিকে, একটি বেনামি অভ্যন্তর শ্রেণি সংস্থানগুলি ফাঁস করতে পারে তবে সর্বদা তা করে না। উদাহরণস্বরূপ এই কোডটি দেখুন: a.blmq.us/2mmrL6v
squid314

এই উত্তরটি কেবল ভুল
স্টিফান রেইচ

আপনাকে @ স্টেফানরিচ ধন্যবাদ, এটি খুব সহায়ক ছিল!
রোল্যান্ড টেপ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.