এই নিবন্ধটি কার জন্য?
আপনি যদি এই বিভাগগুলির মধ্যে একটির সাথে মানানসই না হন, তাহলে আপনি এই নিবন্ধটি বিরক্তিকর, ত্রুটিপূর্ণ বা সাধারণত আপনার চায়ের কাপ না বলে মনে করতে পারেন। এই ক্ষেত্রে, নির্দ্বিধায় অন্য জিনিসগুলিতে এগিয়ে যান বা, আপনি যদি এই বিষয়ে ভালভাবে পারদর্শী হন তবে অনুগ্রহ করে মন্তব্যে পরামর্শ দিন যে আমি কীভাবে নিবন্ধটি উন্নত করতে পারি বা পরিপূরক করতে পারি। উপাদানটির কোনো একাডেমিক মান আছে বলে দাবি করে না, নতুনত্ব ছেড়ে দিন। একেবারে বিপরীত: আমি যতটা সম্ভব জটিল (কিছু লোকের জন্য) জিনিসগুলি বর্ণনা করার চেষ্টা করব। স্ট্রিম API ব্যাখ্যা করার জন্য একটি অনুরোধ আমাকে এটি লিখতে অনুপ্রাণিত করেছে। আমি এটি সম্পর্কে চিন্তা করেছি এবং সিদ্ধান্ত নিয়েছি যে আমার কিছু প্রবাহের উদাহরণ ল্যাম্বডা অভিব্যক্তির বোঝা ছাড়াই বোধগম্য হবে। তাই আমরা ল্যাম্বডা এক্সপ্রেশন দিয়ে শুরু করব। এই নিবন্ধটি বুঝতে আপনার কী জানা দরকার?
আপনি এই ওরাকল টিউটোরিয়াল এবং অন্য কোথাও আরও পড়তে পারেন । একে " টার্গেট টাইপিং " বলা হয়। আপনি যা চান ভেরিয়েবলের নাম দিতে পারেন — আপনাকে ইন্টারফেসে উল্লেখ করা একই নাম ব্যবহার করতে হবে না। যদি কোন পরামিতি না থাকে, তাহলে শুধু খালি বন্ধনী নির্দেশ করুন। যদি শুধুমাত্র একটি প্যারামিটার থাকে, তাহলে কোনো বন্ধনী ছাড়াই পরিবর্তনশীল নামটি নির্দেশ করুন। এখন যেহেতু আমরা প্যারামিটারগুলি বুঝতে পেরেছি, এটি ল্যাম্বডা এক্সপ্রেশনের মূল অংশ নিয়ে আলোচনা করার সময়। কোঁকড়া ধনুর্বন্ধনীর ভিতরে, আপনি একটি সাধারণ পদ্ধতির মতোই কোড লিখবেন। যদি আপনার কোডে একটি লাইন থাকে, তাহলে আপনি কোঁকড়া ধনুর্বন্ধনী সম্পূর্ণভাবে বাদ দিতে পারেন (if-statements এবং for-loops-এর মতো)। যদি আপনার একক-লাইন ল্যাম্বডা কিছু ফেরত দেয়, তাহলে আপনাকে একটি অন্তর্ভুক্ত করতে হবে না
- এটি এমন লোকদের জন্য যারা মনে করেন তারা ইতিমধ্যেই জাভা কোর ভাল জানেন, কিন্তু জাভাতে ল্যাম্বডা এক্সপ্রেশন সম্পর্কে তাদের কোন ধারণা নেই। অথবা হয়তো তারা ল্যাম্বডা এক্সপ্রেশন সম্পর্কে কিছু শুনেছে, কিন্তু বিশদ বিবরণের অভাব রয়েছে
- এটি এমন লোকেদের জন্য যাদের ল্যাম্বডা অভিব্যক্তি সম্পর্কে একটি নির্দিষ্ট ধারণা রয়েছে, কিন্তু এখনও তাদের দ্বারা হতাশ এবং সেগুলি ব্যবহার করতে অভ্যস্ত নয়।

-
আপনার অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং (OOP) বোঝা উচিত, যথা:
- শ্রেণী, বস্তু এবং তাদের মধ্যে পার্থক্য;
- ইন্টারফেস, কিভাবে তারা ক্লাস থেকে আলাদা, এবং ইন্টারফেস এবং ক্লাসের মধ্যে সম্পর্ক;
- পদ্ধতি, কিভাবে তাদের কল করতে হয়, বিমূর্ত পদ্ধতি (যেমন একটি বাস্তবায়ন ছাড়া পদ্ধতি), পদ্ধতি পরামিতি, পদ্ধতি আর্গুমেন্ট এবং কিভাবে পাস করতে হয়;
- অ্যাক্সেস মডিফায়ার, স্ট্যাটিক পদ্ধতি/ভেরিয়েবল, চূড়ান্ত পদ্ধতি/ভেরিয়েবল;
- ক্লাস এবং ইন্টারফেসের উত্তরাধিকার, ইন্টারফেসের একাধিক উত্তরাধিকার।
- জাভা কোরের জ্ঞান: জেনেরিক প্রকার (জেনেরিক), সংগ্রহ (তালিকা), থ্রেড।
একটু ইতিহাস
ল্যাম্বডা এক্সপ্রেশনগুলি কার্যকরী প্রোগ্রামিং থেকে জাভাতে এসেছে এবং সেখানে গণিত থেকে এসেছে। মার্কিন যুক্তরাষ্ট্রে 20 শতকের মাঝামাঝি সময়ে, অ্যালোঞ্জো চার্চ, যিনি গণিত এবং সমস্ত ধরণের বিমূর্ততার খুব পছন্দ করতেন, প্রিন্সটন বিশ্ববিদ্যালয়ে কাজ করতেন। এটি ছিল অ্যালোঞ্জো চার্চ যিনি ল্যাম্বডা ক্যালকুলাস আবিষ্কার করেছিলেন, যা প্রাথমিকভাবে প্রোগ্রামিংয়ের সাথে সম্পূর্ণভাবে সম্পর্কহীন বিমূর্ত ধারণাগুলির একটি সেট ছিল। অ্যালান টুরিং এবং জন ভন নিউম্যানের মতো গণিতবিদ একই সময়ে প্রিন্সটন বিশ্ববিদ্যালয়ে কাজ করেছিলেন। সবকিছু একসাথে এসেছিল: চার্চ ল্যাম্বডা ক্যালকুলাস নিয়ে এসেছিল। টুরিং তার বিমূর্ত কম্পিউটিং মেশিন তৈরি করেছিলেন, যা এখন "টুরিং মেশিন" নামে পরিচিত। এবং ভন নিউম্যান একটি কম্পিউটার স্থাপত্যের প্রস্তাব করেছিলেন যা আধুনিক কম্পিউটারের ভিত্তি তৈরি করেছে (এখন এটিকে "ভন নিউম্যান আর্কিটেকচার" বলা হয়)। সেই সময়, আলোঞ্জো চার্চ এর ধারণাগুলি তার সহকর্মীদের কাজ হিসাবে এতটা পরিচিত হয়ে ওঠেনি (বিশুদ্ধ গণিতের ক্ষেত্রের ব্যতিক্রম)। যাইহোক, একটু পরে জন ম্যাকার্থি (এছাড়াও একজন প্রিন্সটন বিশ্ববিদ্যালয়ের স্নাতক এবং, আমাদের গল্পের সময়, ম্যাসাচুসেটস ইনস্টিটিউট অফ টেকনোলজির একজন কর্মচারী) চার্চের ধারণাগুলিতে আগ্রহী হয়ে ওঠেন। 1958 সালে, তিনি সেই ধারণাগুলির উপর ভিত্তি করে প্রথম কার্যকরী প্রোগ্রামিং ভাষা, LISP তৈরি করেন। এবং 58 বছর পরে, কার্যকরী প্রোগ্রামিং এর ধারণাগুলি জাভা 8-এ ফাঁস হয়ে যায়। এমনকি 70 বছরও পেরিয়ে যায়নি... সত্যি বলতে, এটি একটি গাণিতিক ধারণাকে বাস্তবে প্রয়োগ করার জন্য সবচেয়ে বেশি সময় নেয়নি। ম্যাসাচুসেটস ইনস্টিটিউট অফ টেকনোলজির একজন কর্মচারী) চার্চের ধারণাগুলিতে আগ্রহী হন। 1958 সালে, তিনি সেই ধারণাগুলির উপর ভিত্তি করে প্রথম কার্যকরী প্রোগ্রামিং ভাষা, LISP তৈরি করেন। এবং 58 বছর পরে, কার্যকরী প্রোগ্রামিং এর ধারণাগুলি জাভা 8-এ ফাঁস হয়ে যায়। এমনকি 70 বছরও পেরিয়ে যায়নি... সত্যি বলতে, এটি একটি গাণিতিক ধারণাকে বাস্তবে প্রয়োগ করার জন্য সবচেয়ে বেশি সময় নেয়নি। ম্যাসাচুসেটস ইনস্টিটিউট অফ টেকনোলজির একজন কর্মচারী) চার্চের ধারণাগুলিতে আগ্রহী হন। 1958 সালে, তিনি সেই ধারণাগুলির উপর ভিত্তি করে প্রথম কার্যকরী প্রোগ্রামিং ভাষা, LISP তৈরি করেন। এবং 58 বছর পরে, কার্যকরী প্রোগ্রামিং এর ধারণাগুলি জাভা 8-এ ফাঁস হয়ে যায়। এমনকি 70 বছরও পেরিয়ে যায়নি... সত্যি বলতে, এটি একটি গাণিতিক ধারণাকে বাস্তবে প্রয়োগ করার জন্য সবচেয়ে বেশি সময় নেয়নি।হৃদয় বিষয়ক
ল্যাম্বডা এক্সপ্রেশন হল এক ধরনের ফাংশন। আপনি এটিকে একটি সাধারণ জাভা পদ্ধতি হিসাবে বিবেচনা করতে পারেন তবে একটি যুক্তি হিসাবে অন্যান্য পদ্ধতিতে পাস করার স্বতন্ত্র ক্ষমতা সহ। সেটা ঠিক. এটি কেবলমাত্র সংখ্যা, স্ট্রিং এবং বিড়ালগুলিকে পদ্ধতিতে নয়, অন্যান্য পদ্ধতিতেও পাস করা সম্ভব হয়েছে! কখন আমাদের এই প্রয়োজন হতে পারে? এটি সহায়ক হবে, উদাহরণস্বরূপ, যদি আমরা কিছু কলব্যাক পদ্ধতি পাস করতে চাই। অর্থাৎ, আমরা যে পদ্ধতিটিকে কল করি তা প্রয়োজন হলে অন্য কোনো পদ্ধতিকে কল করার ক্ষমতা থাকতে হবে যা আমরা এটিতে পাস করি। অন্য কথায়, তাই আমাদের নির্দিষ্ট পরিস্থিতিতে একটি কলব্যাক এবং অন্যদের মধ্যে একটি ভিন্ন কলব্যাক পাস করার ক্ষমতা রয়েছে। এবং যাতে আমাদের পদ্ধতি যে আমাদের কলব্যাক গ্রহণ করে তাদের কল করে। সাজানো একটি সহজ উদাহরণ। ধরুন আমরা কিছু চতুর সাজানোর অ্যালগরিদম লিখছি যা এইরকম দেখাচ্ছে:
public void mySuperSort() {
// We do something here
if(compare(obj1, obj2) > 0)
// And then we do something here
}
বিবৃতিতে if
, আমরা পদ্ধতি বলি compare()
, তুলনা করার জন্য দুটি বস্তুর মধ্যে পাস করা, এবং আমরা জানতে চাই যে এই বস্তুগুলির মধ্যে কোনটি "বৃহত্তর"। আমরা অনুমান করি "বৃহত্তর" "ছোট" এর আগে আসে। আমি উদ্ধৃতিতে "বৃহত্তর" রেখেছি, কারণ আমরা একটি সর্বজনীন পদ্ধতি লিখছি যা জানবে কীভাবে কেবল আরোহী ক্রমেই নয়, অবরোহ ক্রমেও সাজানো যায় (এই ক্ষেত্রে, "বৃহত্তর" বস্তুটি আসলে "কম" বস্তু হবে , এবং বিপরীতভাবে). আমাদের সাজানোর জন্য নির্দিষ্ট অ্যালগরিদম সেট করতে, এটিকে আমাদের পদ্ধতিতে পাস করার জন্য আমাদের কিছু প্রক্রিয়া দরকার mySuperSort()
। এইভাবে আমরা আমাদের পদ্ধতিকে "নিয়ন্ত্রণ" করতে সক্ষম হব যখন এটি বলা হয়। অবশ্যই, আমরা দুটি পৃথক পদ্ধতি লিখতে পারি - mySuperSortAscend()
এবংmySuperSortDescend()
— আরোহী এবং অবরোহ ক্রমে সাজানোর জন্য। অথবা আমরা পদ্ধতিতে কিছু আর্গুমেন্ট পাস করতে পারি (উদাহরণস্বরূপ, একটি বুলিয়ান ভেরিয়েবল; সত্য হলে, ক্রমবর্ধমান ক্রমে সাজান, এবং মিথ্যা হলে, তারপর অবরোহ ক্রমে)। কিন্তু আমরা কিছু বাছাই করতে চান যদি জটিল যেমন স্ট্রিং অ্যারে তালিকা? কিভাবে আমাদের mySuperSort()
পদ্ধতি জানতে হবে কিভাবে এই স্ট্রিং অ্যারে সাজাতে হয়? আকার দ্বারা? সব শব্দের ক্রমবর্ধমান দৈর্ঘ্য দ্বারা? সম্ভবত বর্ণানুক্রমিকভাবে অ্যারে প্রথম স্ট্রিং উপর ভিত্তি করে? এবং যদি আমরা কিছু ক্ষেত্রে অ্যারের আকার অনুসারে অ্যারের তালিকা সাজাতে চাই, এবং অন্যান্য ক্ষেত্রে প্রতিটি অ্যারের সমস্ত শব্দের ক্রমবর্ধমান দৈর্ঘ্য দ্বারা? আমি আশা করি আপনি তুলনাকারীদের সম্পর্কে ইতিমধ্যেই শুনেছেন এবং এই ক্ষেত্রে আমরা কেবলমাত্র আমাদের সাজানোর পদ্ধতিতে একটি তুলনামূলক বস্তু প্রেরণ করব যা পছন্দসই সাজানোর অ্যালগরিদম বর্ণনা করে। কারণ মানsort()
পদ্ধতিটি একই নীতির উপর ভিত্তি করে প্রয়োগ করা হয় , আমি আমার উদাহরণগুলিতে mySuperSort()
ব্যবহার করব ।sort()
String[] array1 = {"Dota", "GTA5", "Halo"};
String[] array2 = {"I", "really", "love", "Java"};
String[] array3 = {"if", "then", "else"};
List<String[]> arrays = new ArrayList<>();
arrays.add(array1);
arrays.add(array2);
arrays.add(array3);
Comparator<;String[]> sortByLength = new Comparator<String[]>() {
@Override
public int compare(String[] o1, String[] o2) {
return o1.length - o2.length;
}
};
Comparator<String[]> sortByCumulativeWordLength = new Comparator<String[]>() {
@Override
public int compare(String[] o1, String[] o2) {
int length1 = 0;
int length2 = 0;
for (String s : o1) {
length1 += s.length();
}
for (String s : o2) {
length2 += s.length();
}
return length1 - length2;
}
};
arrays.sort(sortByLength);
ফলাফল:
- Dota GTA5 Halo
- if then else
- I really love Java
এখানে প্রতিটি অ্যারের শব্দের সংখ্যা অনুসারে অ্যারেগুলি সাজানো হয়েছে। কম শব্দ সহ একটি বিন্যাস "কম" বলে বিবেচিত হয়। সেজন্যই প্রথম আসে। আরও শব্দ সহ একটি অ্যারেকে "বৃহত্তর" হিসাবে বিবেচনা করা হয় এবং শেষে স্থাপন করা হয়। যদি আমরা পদ্ধতিতে একটি ভিন্ন তুলনাকারী পাস করি sort()
, যেমন sortByCumulativeWordLength
, তাহলে আমরা একটি ভিন্ন ফলাফল পাব:
- if then else
- Dota GTA5 Halo
- I really love Java
এখন are arrayগুলি অ্যারের শব্দের মোট অক্ষরের সংখ্যা অনুসারে সাজানো হয়েছে। প্রথম অ্যারেতে, 10টি অক্ষর রয়েছে, দ্বিতীয়টিতে 12টি এবং তৃতীয়টিতে 15টি অক্ষর রয়েছে। যদি আমাদের শুধুমাত্র একটি তুলনাকারী থাকে, তাহলে আমাদের এটির জন্য একটি পৃথক পরিবর্তনশীল ঘোষণা করতে হবে না। পরিবর্তে, পদ্ধতিতে কল করার সময় আমরা কেবল একটি বেনামী ক্লাস তৈরি করতে পারি sort()
। এটার মতো কিছু:
String[] array1 = {"Dota", "GTA5", "Halo"};
String[] array2 = {"I", "really", "love", "Java"};
String[] array3 = {"if", "then", "else"};
List<String[]> arrays = new ArrayList<>();
arrays.add(array1);
arrays.add(array2);
arrays.add(array3);
arrays.sort(new Comparator<String[]>() {
@Override
public int compare(String[] o1, String[] o2) {
return o1.length - o2.length;
}
});
আমরা প্রথম ক্ষেত্রে হিসাবে একই ফলাফল পাবেন. টাস্ক 1. এই উদাহরণটি পুনরায় লিখুন যাতে এটি অ্যারেগুলিকে প্রতিটি অ্যারের শব্দের সংখ্যার ক্রমবর্ধমান ক্রমে সাজায় না, বরং অবরোহ ক্রমে। আমরা ইতিমধ্যে এই সব জানি. আমরা পদ্ধতিতে অবজেক্ট পাস করতে জানি। এই মুহুর্তে আমাদের যা প্রয়োজন তার উপর নির্ভর করে, আমরা বিভিন্ন বস্তুকে একটি পদ্ধতিতে প্রেরণ করতে পারি, যা তারপরে আমরা যে পদ্ধতিটি প্রয়োগ করেছি তা আহ্বান করবে। এটি প্রশ্ন তোলে: কেন বিশ্বে আমাদের এখানে ল্যাম্বডা অভিব্যক্তির প্রয়োজন? কারণ একটি ল্যাম্বডা এক্সপ্রেশন এমন একটি বস্তু যার ঠিক একটি পদ্ধতি রয়েছে। একটি "পদ্ধতি বস্তুর" মত। একটি বস্তুতে প্যাকেজ করা একটি পদ্ধতি। এটিতে কেবল একটি সামান্য অপরিচিত সিনট্যাক্স রয়েছে (কিন্তু পরে আরও বেশি)। আসুন এই কোডটি আরও একবার দেখে নেওয়া যাক:
arrays.sort(new Comparator<String[]>() {
@Override
public int compare(String[] o1, String[] o2) {
return o1.length - o2.length;
}
});
এখানে আমরা আমাদের অ্যারে তালিকাটি নিয়েছি এবং এটির sort()
পদ্ধতিকে কল করি, যেখানে আমরা একটি একক compare()
পদ্ধতির সাথে একটি তুলনাকারী বস্তু পাস করি (এটির নাম আমাদের কাছে কোন ব্যাপার না — সর্বোপরি, এটি এই অবজেক্টের একমাত্র পদ্ধতি, তাই আমরা ভুল করতে পারি না)। এই পদ্ধতিতে দুটি পরামিতি রয়েছে যা আমরা নিয়ে কাজ করব। আপনি যদি IntelliJ IDEA-তে কাজ করেন, আপনি সম্ভবত দেখেছেন যে এটি নিম্নলিখিত কোডটিকে উল্লেখযোগ্যভাবে ঘনীভূত করার প্রস্তাব দিয়েছে:
arrays.sort((o1, o2) -> o1.length - o2.length);
এটি ছয়টি লাইনকে একক সংক্ষিপ্ত করে দেয়। 6 লাইন একটি সংক্ষিপ্ত এক হিসাবে পুনরায় লেখা হয়. কিছু অদৃশ্য হয়ে গেছে, কিন্তু আমি গ্যারান্টি দিচ্ছি যে এটি গুরুত্বপূর্ণ কিছু ছিল না। এই কোডটি ঠিক একইভাবে কাজ করবে যেভাবে এটি একটি বেনামী ক্লাসের সাথে করবে। টাস্ক 2. একটি ল্যাম্বডা এক্সপ্রেশন ব্যবহার করে টাস্ক 1 এর সমাধানটি পুনর্লিখন করার সময় একটি অনুমান করুন (অন্তত, IntelliJ IDEA কে আপনার বেনামী ক্লাসকে ল্যাম্বডা এক্সপ্রেশনে রূপান্তর করতে বলুন)।
এর ইন্টারফেস সম্পর্কে কথা বলা যাক
নীতিগতভাবে, একটি ইন্টারফেস কেবল বিমূর্ত পদ্ধতির একটি তালিকা। যখন আমরা একটি ক্লাস তৈরি করি যা কিছু ইন্টারফেস প্রয়োগ করে, তখন আমাদের ক্লাসকে অবশ্যই ইন্টারফেসে অন্তর্ভুক্ত পদ্ধতিগুলি প্রয়োগ করতে হবে (বা আমাদের ক্লাসটি বিমূর্ত করতে হবে)। অনেকগুলি বিভিন্ন পদ্ধতির ইন্টারফেস রয়েছে (উদাহরণস্বরূপ,List
), এবং শুধুমাত্র একটি পদ্ধতি সহ ইন্টারফেস রয়েছে (উদাহরণস্বরূপ, Comparator
বা Runnable
)। এমন ইন্টারফেস রয়েছে যেগুলির একটি একক পদ্ধতি নেই (তথাকথিত মার্কার ইন্টারফেস যেমন Serializable
)। যে ইন্টারফেসগুলিতে শুধুমাত্র একটি পদ্ধতি রয়েছে তাকে কার্যকরী ইন্টারফেসও বলা হয় । জাভা 8 এ, তারা এমনকি একটি বিশেষ টীকা দিয়ে চিহ্নিত করা হয়েছে:@FunctionalInterface
. এটি এই একক-পদ্ধতি ইন্টারফেস যা ল্যাম্বডা এক্সপ্রেশনের জন্য লক্ষ্য প্রকার হিসাবে উপযুক্ত। যেমনটি আমি উপরে বলেছি, একটি ল্যাম্বডা এক্সপ্রেশন একটি বস্তুতে মোড়ানো একটি পদ্ধতি। এবং যখন আমরা এই ধরনের একটি বস্তু পাস, আমরা মূলত এই একক পদ্ধতি পাস হয়. দেখা যাচ্ছে যে পদ্ধতিটিকে কী বলা হয় তা আমরা চিন্তা করি না। আমাদের কাছে গুরুত্বপূর্ণ বিষয়গুলি হল পদ্ধতির পরামিতি এবং অবশ্যই, পদ্ধতির মূল অংশ। সংক্ষেপে, একটি ল্যাম্বডা এক্সপ্রেশন হল একটি কার্যকরী ইন্টারফেসের বাস্তবায়ন। যেখানেই আমরা একটি একক পদ্ধতির সাথে একটি ইন্টারফেস দেখি, একটি বেনামী ক্লাস একটি ল্যাম্বডা হিসাবে পুনরায় লেখা যেতে পারে। যদি ইন্টারফেসে একাধিক বা কম একটি পদ্ধতি থাকে, তাহলে একটি ল্যাম্বডা এক্সপ্রেশন কাজ করবে না এবং আমরা পরিবর্তে একটি বেনামী ক্লাস বা এমনকি একটি সাধারণ ক্লাসের উদাহরণ ব্যবহার করব। এখন একটু ল্যাম্বডাস খনন করার পালা। :)
বাক্য গঠন
সাধারণ সিনট্যাক্স এরকম কিছু:
(parameters) -> {method body}
অর্থাৎ, পদ্ধতির পরামিতিগুলির চারপাশে বন্ধনী, একটি "তীর" (একটি হাইফেন এবং বৃহত্তর চিহ্ন দ্বারা গঠিত), এবং তারপরে বন্ধনীতে মেথড বডি, বরাবরের মতো। পরামিতিগুলি ইন্টারফেস পদ্ধতিতে নির্দিষ্ট করাগুলির সাথে মিলে যায়৷ যদি পরিবর্তনশীল প্রকারগুলি কম্পাইলার দ্বারা দ্ব্যর্থহীনভাবে নির্ধারণ করা যায় (আমাদের ক্ষেত্রে, এটি জানে যে আমরা স্ট্রিং অ্যারে নিয়ে কাজ করছি, কারণ আমাদের List
অবজেক্ট ] ব্যবহার করে টাইপ করা হয়েছে String[
), তাহলে আপনাকে তাদের প্রকারগুলি নির্দেশ করতে হবে না।
যদি তারা অস্পষ্ট হয়, তাহলে প্রকারটি নির্দেশ করুন। প্রয়োজন না হলে IDEA এটি ধূসর রঙ করবে। |
return
বিবৃতি কিন্তু আপনি যদি কোঁকড়া ধনুর্বন্ধনী ব্যবহার করেন, তাহলে আপনাকে অবশ্যই একটি return
বিবৃতি স্পষ্টভাবে অন্তর্ভুক্ত করতে হবে, যেমন আপনি একটি সাধারণ পদ্ধতিতে করবেন।
উদাহরণ
উদাহরণ 1.
() -> {}
সহজ উদাহরণ। এবং সবচেয়ে অর্থহীন :), যেহেতু এটি কিছুই করে না। উদাহরণ 2।
() -> ""
আরেকটি আকর্ষণীয় উদাহরণ। এটি কিছুই নেয় না এবং একটি খালি স্ট্রিং ফেরত দেয় ( return
বাদ দেওয়া হয়, কারণ এটি অপ্রয়োজনীয়)। এখানে একই জিনিস, কিন্তু সঙ্গে return
:
() -> {
return "";
}
উদাহরণ 3. "হ্যালো, ওয়ার্ল্ড!" ল্যাম্বডাস ব্যবহার করে
() -> System.out.println("Hello, World!")
return
এটি কিছুই নেয় না এবং কিছুই ফেরত দেয় না (আমরা কল করার আগে রাখতে পারি না System.out.println()
, কারণ println()
পদ্ধতির রিটার্ন টাইপ হল void
)। এটি কেবল অভিবাদন প্রদর্শন করে। এটি ইন্টারফেসের বাস্তবায়নের জন্য আদর্শ Runnable
। নিম্নলিখিত উদাহরণ আরো সম্পূর্ণ:
public class Main {
public static void main(String[] args) {
new Thread(() -> System.out.println("Hello, World!")).start();
}
}
অথবা এই মত:
public class Main {
public static void main(String[] args) {
Thread t = new Thread(() -> System.out.println("Hello, World!"));
t.start();
}
}
অথবা আমরা ল্যাম্বডা এক্সপ্রেশনটিকে একটি Runnable
অবজেক্ট হিসাবে সংরক্ষণ করতে পারি এবং তারপর এটি Thread
কনস্ট্রাক্টরের কাছে প্রেরণ করতে পারি:
public class Main {
public static void main(String[] args) {
Runnable runnable = () -> System.out.println("Hello, World!");
Thread t = new Thread(runnable);
t.start();
}
}
চলুন যখন একটি ল্যাম্বডা এক্সপ্রেশন একটি ভেরিয়েবলে সংরক্ষিত হয় সেই মুহুর্তে একটি ঘনিষ্ঠভাবে নজর দেওয়া যাক। ইন্টারফেস আমাদের বলে যে এর বস্তুর একটি পদ্ধতি Runnable
থাকতে হবে । public void run()
ইন্টারফেস অনুযায়ী, run
পদ্ধতিতে কোন পরামিতি লাগে না। এবং এটি কিছুই ফেরত দেয় না, অর্থাৎ এর রিটার্ন টাইপ হয় void
। তদনুসারে, এই কোডটি এমন একটি পদ্ধতির সাথে একটি বস্তু তৈরি করবে যা কিছু নেয় না বা ফেরত দেয় না। এটি Runnable
ইন্টারফেসের run()
পদ্ধতির সাথে পুরোপুরি মেলে। এই কারণেই আমরা এই ল্যাম্বডা এক্সপ্রেশনটিকে একটি পরিবর্তনশীলে রাখতে সক্ষম হয়েছি Runnable
। উদাহরণ 4.
() -> 42
আবার, এটি কিছুই নেয় না, তবে এটি 42 নম্বর প্রদান করে। এই ধরনের একটি ল্যাম্বডা এক্সপ্রেশন একটি ভেরিয়েবলে রাখা যেতে পারে Callable
, কারণ এই ইন্টারফেসে শুধুমাত্র একটি পদ্ধতি রয়েছে যা দেখতে এরকম কিছু:
V call(),
রিটার্ন টাইপ কোথায় V
(আমাদের ক্ষেত্রে, int
)। তদনুসারে, আমরা নিম্নলিখিত হিসাবে একটি ল্যাম্বডা অভিব্যক্তি সংরক্ষণ করতে পারি:
Callable<Integer> c = () -> 42;
উদাহরণ 5. বেশ কয়েকটি লাইন জড়িত একটি ল্যাম্বডা অভিব্যক্তি
() -> {
String[] helloWorld = {"Hello", "World!"};
System.out.println(helloWorld[0]);
System.out.println(helloWorld[1]);
}
আবার, এটি একটি ল্যাম্বডা এক্সপ্রেশন যার কোন প্যারামিটার নেই এবং একটি void
রিটার্ন টাইপ (কারণ কোন বিবৃতি নেই return
)। উদাহরণ 6
x -> x
এখানে আমরা একটি x
ভেরিয়েবল নিই এবং এটি ফেরত দিই। দয়া করে মনে রাখবেন যে যদি শুধুমাত্র একটি প্যারামিটার থাকে, তাহলে আপনি এটির চারপাশে বন্ধনীগুলি বাদ দিতে পারেন। এখানে একই জিনিস, কিন্তু বন্ধনী সহ:
(x) -> x
এবং এখানে একটি সুস্পষ্ট রিটার্ন বিবৃতি সহ একটি উদাহরণ:
x -> {
return x;
}
অথবা বন্ধনী এবং একটি রিটার্ন স্টেটমেন্ট সহ এটি পছন্দ করুন:
(x) -> {
return x;
}
বা প্রকারের একটি সুস্পষ্ট ইঙ্গিত সহ (এবং এইভাবে বন্ধনী সহ):
(int x) -> x
উদাহরণ 7
x -> ++x
আমরা x
এটি গ্রহণ করি এবং ফেরত দিই, কিন্তু শুধুমাত্র 1 যোগ করার পরে। আপনি সেই ল্যাম্বডাকে এভাবে পুনরায় লিখতে পারেন:
x -> x + 1
উভয় ক্ষেত্রে, আমরা বিবৃতি সহ প্যারামিটার এবং মেথড বডির চারপাশে বন্ধনীগুলি বাদ দিই return
, যেহেতু সেগুলি ঐচ্ছিক। বন্ধনী সহ সংস্করণ এবং একটি রিটার্ন স্টেটমেন্ট উদাহরণ 6 এ দেওয়া হয়েছে। উদাহরণ 8
(x, y) -> x % y
আমরা গ্রহণ করি x
এবং দ্বারা y
ভাগের অবশিষ্টাংশ ফেরত দেয় । প্যারামিটারের চারপাশে বন্ধনী এখানে প্রয়োজন। শুধুমাত্র একটি প্যারামিটার থাকলেই এগুলি ঐচ্ছিক৷ এখানে এটি প্রকারগুলির একটি সুস্পষ্ট ইঙ্গিত সহ: x
y
(double x, int y) -> x % y
উদাহরণ 9
(Cat cat, String name, int age) -> {
cat.setName(name);
cat.setAge(age);
}
আমরা একটি Cat
বস্তু, একটি String
নাম, এবং একটি int বয়স নিতে. পদ্ধতিতে, আমরা বিড়ালের উপর ভেরিয়েবল সেট করতে পাস করা নাম এবং বয়স ব্যবহার করি। কারণ আমাদের cat
অবজেক্ট একটি রেফারেন্স টাইপ, এটি ল্যাম্বডা এক্সপ্রেশনের বাইরে পরিবর্তিত হবে (এটি পাস করা নাম এবং বয়স পাবে)। এখানে একটি সামান্য আরো জটিল সংস্করণ যা একটি অনুরূপ ল্যাম্বডা ব্যবহার করে:
public class Main {
public static void main(String[] args) {
// Create a cat and display it to confirm that it is "empty"
Cat myCat = new Cat();
System.out.println(myCat);
// Create a lambda
Settable<Cat> s = (obj, name, age) -> {
obj.setName(name);
obj.setAge(age);
};
// Call a method to which we pass the cat and lambda
changeEntity(myCat, s);
// Display the cat on the screen and see that its state has changed (it has a name and age)
System.out.println(myCat);
}
private static <T extends HasNameAndAge> void changeEntity(T entity, Settable<T> s) {
s.set(entity, "Smokey", 3);
}
}
interface HasNameAndAge {
void setName(String name);
void setAge(int age);
}
interface Settable<C extends HasNameAndAge> {
void set(C entity, String name, int age);
}
class Cat implements HasNameAndAge {
private String name;
private int age;
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
ফলাফল:
Cat{name='null', age=0}
Cat{name='Smokey', age=3}
আপনি দেখতে পাচ্ছেন, Cat
বস্তুটির একটি অবস্থা ছিল, এবং তারপরে আমরা ল্যাম্বডা এক্সপ্রেশন ব্যবহার করার পরে রাষ্ট্রটি পরিবর্তিত হয়েছে। ল্যাম্বডা এক্সপ্রেশনগুলি জেনেরিকের সাথে পুরোপুরি একত্রিত হয়। এবং যদি আমাদের একটি ক্লাস তৈরি করতে হয় Dog
যা প্রয়োগ করে , তাহলে আমরা ল্যাম্বডা এক্সপ্রেশন পরিবর্তন না করে পদ্ধতিতে একই HasNameAndAge
ক্রিয়াকলাপ সম্পাদন করতে পারি । টাস্ক 3. একটি পদ্ধতির সাথে একটি কার্যকরী ইন্টারফেস লিখুন যা একটি সংখ্যা নেয় এবং একটি বুলিয়ান মান প্রদান করে। ল্যাম্বডা এক্সপ্রেশনের মতো একটি ইন্টারফেসের বাস্তবায়ন লিখুন যা পাস করা সংখ্যাটি 13 দ্বারা বিভাজ্য হলে সত্য দেখায়। টাস্ক 4।Dog
main()
একটি পদ্ধতির সাথে একটি কার্যকরী ইন্টারফেস লিখুন যা দুটি স্ট্রিং নেয় এবং একটি স্ট্রিং ফেরত দেয়। ল্যাম্বডা এক্সপ্রেশনের মতো একটি ইন্টারফেসের বাস্তবায়ন লিখুন যা দীর্ঘ স্ট্রিং প্রদান করে। টাস্ক 5. একটি পদ্ধতির সাথে একটি কার্যকরী ইন্টারফেস লিখুন যা তিনটি ফ্লোটিং-পয়েন্ট সংখ্যা নেয়: a, b, এবং c এবং একটি ফ্লোটিং-পয়েন্ট নম্বর প্রদান করে। ল্যাম্বডা এক্সপ্রেশনের মতো একটি ইন্টারফেসের বাস্তবায়ন লিখুন যা বৈষম্যকারীকে ফেরত দেয়। যদি আপনি ভুলে গিয়ে থাকেন, তা হল D = b^2 — 4ac
। টাস্ক 6. টাস্ক 5 থেকে কার্যকরী ইন্টারফেস ব্যবহার করে, একটি ল্যাম্বডা এক্সপ্রেশন লিখুন যা এর ফলাফল প্রদান করে a * b^c
। জাভাতে ল্যাম্বডা এক্সপ্রেশনের একটি ব্যাখ্যা। উদাহরণ এবং কর্ম সহ. অংশ ২
GO TO FULL VERSION