Collectors হল Java 8-এর java.util.stream প্যাকেজের একটি ক্লাস যা স্ট্রিমের উপাদানগুলিকে সংগ্রহ (collect) করতে ব্যবহৃত হয়। এটি Stream API-র একটি শক্তিশালী অংশ এবং স্ট্রিম ডেটার ওপর বিভিন্ন ধরণের অপারেশন পরিচালনা করতে সাহায্য করে। Collectors মূলত একটি Terminal Operation হিসাবে কাজ করে, যা স্ট্রিমের ডেটাকে একটি সমষ্টিগত ফলাফল (যেমন একটি List, Set, Map বা অন্যান্য কাস্টম সংগ্রহ) এ রূপান্তর করে।
Collectors এর সুবিধা
- Data Aggregation:
Collectorsবিভিন্ন ধরনের ডেটা একত্রিত করতে ব্যবহৃত হয়। যেমন, একটি স্ট্রিমের মানগুলো একটি লিস্টে বা সেটে রূপান্তর করা।
- Functional Programming Support:
- এটি ফাংশনাল প্রোগ্রামিং ধারণা সমর্থন করে, যেখানে আপনি স্ট্রিমের উপাদানগুলির উপর বিভিন্ন কার্যক্রম বা অগ্রগতি পরিচালনা করতে পারেন।
- Performance:
Collectorsঅপারেশনগুলি কার্যকরভাবে স্ট্রিমের মানগুলিকে একত্রিত করে, কোডের কার্যকারিতা এবং পারফরম্যান্স বৃদ্ধি করে।
- Declarative Approach:
Collectors-এর সাহায্যে আপনি সহজ এবং declarative (ঘোষণামূলক) কোড লিখতে পারেন, যা সহজে পড়া এবং রক্ষণাবেক্ষণ করা যায়।
Collectors ক্লাসের মূল মেথড
toList()
- এটি একটি স্ট্রিমের উপাদানগুলিকে একটি
Listএ সংগ্রহ করে।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); List<String> filteredNames = names.stream() .filter(name -> name.startsWith("A")) .collect(Collectors.toList()); // List তৈরি হচ্ছে System.out.println(filteredNames); // Output: [Alice] } }- এটি একটি স্ট্রিমের উপাদানগুলিকে একটি
toSet()
- এটি একটি স্ট্রিমের উপাদানগুলোকে একটি
Setএ সংগ্রহ করে, যা ডুপ্লিকেট মান বাদ দেয়।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Alice", "David"); Set<String> uniqueNames = names.stream() .collect(Collectors.toSet()); // Set তৈরি হচ্ছে System.out.println(uniqueNames); // Output: [Alice, Bob, David] } }- এটি একটি স্ট্রিমের উপাদানগুলোকে একটি
toMap()
- এটি একটি স্ট্রিমের উপাদানগুলোকে একটি
Mapএ রূপান্তরিত করে, যেখানে কীগুলি নির্ধারণ করতে একটি ফাংশন এবং মানগুলির জন্য একটি ফাংশন প্রদান করা হয়।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); Map<Integer, String> nameMap = names.stream() .collect(Collectors.toMap(String::length, name -> name)); System.out.println(nameMap); // Output: {5=Alice, 3=Bob, 7=Charlie} } }- এটি একটি স্ট্রিমের উপাদানগুলোকে একটি
joining()
- এটি স্ট্রিমের উপাদানগুলোকে একত্রিত (concatenate) করে একটি স্ট্রিংয়ে রূপান্তর করে।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); String result = names.stream() .collect(Collectors.joining(", ", "Names: ", ".")); System.out.println(result); // Output: Names: Alice, Bob, Charlie. } }groupingBy()
- এটি স্ট্রিমের উপাদানগুলোকে একটি গ্রুপে বিভক্ত করে, যেখানে একটি কী (key) ব্যবহার করা হয়।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); Map<Integer, List<String>> groupedByLength = names.stream() .collect(Collectors.groupingBy(String::length)); System.out.println(groupedByLength); // Output: {3=[Bob], 5=[Alice], 7=[Charlie, David]} } }partitioningBy()
- এটি স্ট্রিমের উপাদানগুলিকে দুটি ভাগে বিভক্ত করে, যেখানে একটি শর্তের ভিত্তিতে দুটি গ্রুপে ভাগ করা হয়।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); Map<Boolean, List<String>> partitioned = names.stream() .collect(Collectors.partitioningBy(name -> name.length() > 4)); System.out.println(partitioned); // Output: {false=[Bob], true=[Alice, Charlie, David]} } }counting()
- এটি একটি স্ট্রিমের উপাদানগুলির সংখ্যা গণনা করে।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); long count = names.stream() .collect(Collectors.counting()); System.out.println(count); // Output: 4 } }summarizingInt(), summarizingDouble(), summarizingLong()
- এই পদ্ধতিগুলি স্ট্রিমের উপাদানগুলির উপর বিভিন্ন ধরনের সারাংশ বা সংক্ষিপ্ত প্রতিবেদন তৈরি করে (যেমন, গড়, সর্বনিম্ন, সর্বোচ্চ মান, মোট যোগফল ইত্যাদি)।
উদাহরণ:
import java.util.*; import java.util.stream.*; public class CollectorsExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); IntSummaryStatistics stats = numbers.stream() .collect(Collectors.summarizingInt(Integer::intValue)); System.out.println(stats); // Output: IntSummaryStatistics{count=5, sum=15, min=1, average=3.000000, max=5} } }
Collectors-এর উপকারিতা
- কমপ্যাক্ট কোড:
Collectorsব্যবহার করলে স্ট্রিমের উপাদানগুলির উপর কম্প্লেক্স অপারেশন খুব সহজেই এবং সংক্ষিপ্তভাবে করা যায়।
- উন্নত পারফরম্যান্স:
Collectorsস্ট্রিম অপারেশনগুলিকে উচ্চ কার্যকারিতা দিয়ে সম্পন্ন করতে সাহায্য করে, যা কোডের পারফরম্যান্স বাড়ায়।
- ফাংশনাল স্টাইল:
Collectorsফাংশনাল প্রোগ্রামিং স্টাইল সমর্থন করে, যা কোডকে আরো পরিষ্কার এবং প্রোগ্রামারদের জন্য আরও সহজে পড়া যায়।
সারসংক্ষেপ
Collectors Java 8-এ Stream API-র একটি অত্যন্ত গুরুত্বপূর্ণ অংশ যা স্ট্রিমের ডেটা সংগ্রহ, গ্রুপিং, ফিল্টারিং এবং বিভিন্ন রকমের সমষ্টিগত ফলাফল তৈরি করতে সহায়ক। এটি স্ট্রিম অপারেশনগুলি সহজ, পরিষ্কার এবং কার্যকরীভাবে সম্পাদন করতে সাহায্য করে, এবং কোডের উন্নত পারফরম্যান্স নিশ্চিত করে।
Collectors হল একটি গুরুত্বপূর্ণ ক্লাস যা Java 8 Streams API-তে ব্যবহৃত হয়। এটি স্ট্রিমের উপাদানগুলোকে একটি সংগৃহীত আকারে (যেমন List, Set, Map) রূপান্তর করতে সহায়তা করে। Collectors ক্লাসটি বিভিন্ন reduction অপারেশন সম্পন্ন করতে ব্যবহৃত হয়, যা মূলত একটি স্ট্রিমের উপাদানগুলোকে সংগ্রহ (collect) করার কাজ করে।
Collectors এর প্রাথমিক ধারণা
Collectors ক্লাসের মাধ্যমে আপনি স্ট্রিমের উপাদানগুলোকে একটি বিশেষ ডেটা স্ট্রাকচার (যেমন List, Set, Map) বা একটি একক মানে (যেমন সমষ্টি, গড়, সর্বোচ্চ মান ইত্যাদি) রূপান্তর করতে পারেন। Collectors এর বেশ কয়েকটি জনপ্রিয় মেথড রয়েছে যা স্ট্রিমের উপাদানগুলোকে প্রক্রিয়া করতে ব্যবহৃত হয়।
Collectors ক্লাস মূলত Collector ইন্টারফেসের একটি বাস্তবায়ন। এটি স্ট্রিমের উপাদানগুলো সংগ্রহ (collect) করার জন্য বিভিন্ন প্রকারের কার্যক্রম সাপোর্ট করে। এটি স্ট্রিমে কিছু aggregation বা reduction অপারেশন যেমন grouping, partitioning, mapping, joining ইত্যাদি করে।
Collectors এর প্রধান মেথডসমূহ
Java 8-এ Collectors ক্লাসটি বিভিন্ন কমন অপারেশন করতে ব্যবহৃত হয়। এর মধ্যে সবচেয়ে প্রচলিত মেথডগুলোর মধ্যে রয়েছে:
toList(): স্ট্রিমের উপাদানগুলোকে একটি List-এ সংগ্রহ করতে ব্যবহৃত হয়।toSet(): স্ট্রিমের উপাদানগুলোকে একটি Set-এ সংগ্রহ করতে ব্যবহৃত হয়।toMap(): স্ট্রিমের উপাদানগুলোকে একটি Map-এ সংগ্রহ করতে ব্যবহৃত হয়।joining(): স্ট্রিং উপাদানগুলিকে একত্রিত (concatenate) করতে ব্যবহৃত হয়।groupingBy(): স্ট্রিমের উপাদানগুলোকে একটি কীগুচ্ছ দিয়ে গ্রুপিং করতে ব্যবহৃত হয়।partitioningBy(): স্ট্রিমের উপাদানগুলোকে দুটি ভাগে ভাগ করতে ব্যবহৃত হয় (true/false ভ্যালুতে)।summarizingInt(),summarizingDouble(),summarizingLong(): সংখ্যাগত মানের সারাংশ (যেমন গড়, মোট, সর্বনিম্ন, সর্বোচ্চ) বের করতে ব্যবহৃত হয়।reducing(): স্ট্রিমের উপাদানগুলোকে একটি একক মানে (যেমন গড়, সর্বোচ্চ, সমষ্টি) রূপান্তর করতে ব্যবহৃত হয়।
Collectors এর ব্যবহার
১. toList() ব্যবহার
toList() মেথড স্ট্রিমের উপাদানগুলোকে একটি List-এ রূপান্তর করতে ব্যবহৃত হয়।
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectorsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // Output: [2, 4]
}
}এখানে, toList() মেথড ব্যবহার করে স্ট্রিমের ফিল্টার করা উপাদানগুলোকে একটি List এ সংগ্রহ করা হয়েছে।
২. toSet() ব্যবহার
toSet() মেথড স্ট্রিমের উপাদানগুলোকে একটি Set-এ রূপান্তর করতে ব্যবহৃত হয়। এটি ডুপ্লিকেট উপাদানগুলোকে ফিল্টার করে।
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class CollectorsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
Set<Integer> uniqueNumbers = numbers.stream()
.collect(Collectors.toSet());
System.out.println(uniqueNumbers); // Output: [1, 2, 3, 4, 5]
}
}এখানে, toSet() মেথড স্ট্রিমের উপাদানগুলোকে একটি Set এ রূপান্তর করেছে, যা ডুপ্লিকেট মানগুলো বাদ দিয়ে শুধুমাত্র ইউনিক মান রেখেছে।
৩. groupingBy() ব্যবহার
groupingBy() মেথড স্ট্রিমের উপাদানগুলোকে একটি কীগুচ্ছ দিয়ে গ্রুপ করতে ব্যবহৃত হয়। এটি একটি Map তৈরি করে যেখানে কীগুলি নির্দিষ্ট শর্তের ভিত্তিতে উপাদানগুলোকে গ্রুপ করে।
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CollectorsExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry", "avocado", "blueberry");
Map<Character, List<String>> groupedByFirstLetter = words.stream()
.collect(Collectors.groupingBy(word -> word.charAt(0)));
System.out.println(groupedByFirstLetter); // Output: {a=[apple, avocado], b=[banana, blueberry], c=[cherry]}
}
}এখানে, groupingBy() মেথড ব্যবহার করে, আমরা স্ট্রিংগুলিকে তাদের প্রথম অক্ষরের ভিত্তিতে গ্রুপ করেছি এবং একটি Map তৈরি করেছি যেখানে প্রতিটি কীগুচ্ছ একটি চরিত্র (অক্ষর) এবং মান হলো সেই অক্ষর দিয়ে শুরু হওয়া স্ট্রিংগুলোর তালিকা।
৪. joining() ব্যবহার
joining() মেথড ব্যবহার করে স্ট্রিংয়ের উপাদানগুলিকে একত্রিত (concatenate) করা যায়।
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectorsExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry");
String result = words.stream()
.collect(Collectors.joining(", "));
System.out.println(result); // Output: apple, banana, cherry
}
}এখানে, joining() মেথড ব্যবহার করে আমরা স্ট্রিংগুলিকে কমা (,) দিয়ে যুক্ত করেছি।
৫. summarizingInt() ব্যবহার
summarizingInt() মেথড ব্যবহার করে একটি স্ট্রিমের উপাদানগুলোর উপর গাণিতিক সারাংশ (যেমন গড়, সর্বোচ্চ, সর্বনিম্ন) বের করা হয়।
import java.util.Arrays;
import java.util.List;
import java.util.IntSummaryStatistics;
public class CollectorsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
IntSummaryStatistics stats = numbers.stream()
.collect(Collectors.summarizingInt(Integer::intValue));
System.out.println("Sum: " + stats.getSum()); // Output: Sum: 15
System.out.println("Average: " + stats.getAverage()); // Output: Average: 3.0
System.out.println("Max: " + stats.getMax()); // Output: Max: 5
}
}এখানে, summarizingInt() মেথড ব্যবহার করে আমরা সংখ্যাগুলোর গাণিতিক সারাংশ বের করেছি যেমন, গড়, সর্বোচ্চ, সর্বনিম্ন, ইত্যাদি।
সারসংক্ষেপ
Collectors ক্লাস স্ট্রিমের উপাদানগুলোকে বিভিন্ন ধরণের ডেটা স্ট্রাকচারে রূপান্তর করতে এবং সেগুলোর উপর aggregation বা reduction অপারেশন করতে সহায়তা করে। Java 8 এর Stream API এর মাধ্যমে আপনি toList(), toSet(), groupingBy(), joining(), summarizingInt() এবং আরও অনেক কার্যকরী অপারেশন খুব সহজে ব্যবহার করতে পারেন।
এইসব Collectors মেথড স্ট্রিমের উপাদানগুলোকে আরও সহজে প্রক্রিয়া করতে এবং বিভিন্ন কন্টেইনারে (যেমন List, Set, Map) একত্রিত করতে সাহায্য করে, যা কোডের কার্যকারিতা এবং পঠনযোগ্যতা বৃদ্ধি করে।
Java 8-এ Streams API এর মাধ্যমে ডেটা সংগ্রহ করা অত্যন্ত সহজ এবং কার্যকরী হয়েছে। Collectors ক্লাসের বিভিন্ন static method যেমন toList(), toSet(), এবং toMap() ব্যবহার করে আপনি স্ট্রিমের উপাদানগুলিকে বিভিন্ন সংগ্রহ (Collection) ফর্ম্যাটে রূপান্তর করতে পারেন। এটি Java-তে ডেটা সংগ্রহের একটি অত্যন্ত শক্তিশালী এবং সোজা উপায়।
এখানে এই তিনটি পদ্ধতি (method) কীভাবে কাজ করে তা বিস্তারিতভাবে আলোচনা করা হয়েছে।
১. Collectors.toList()
toList() একটি কোলেকশন হিসেবে List রিটার্ন করে যা স্ট্রিমের উপাদানগুলিকে একটি তালিকায় (List) রূপান্তরিত করে। এটি স্ট্রিমের উপাদানগুলোকে ইনসার্ট করার জন্য একটি ArrayList ব্যবহার করে।
Syntax:
List<T> toList()ব্যবহার উদাহরণ:
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Mike", "Mia");
// Collecting data into a List using toList()
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("J"))
.collect(Collectors.toList());
System.out.println(filteredNames); // Output: [John, Jane]
}
}এখানে, toList() মেথডটি স্ট্রিমের উপাদানগুলোকে একটি List এ রূপান্তরিত করেছে।
২. Collectors.toSet()
toSet() মেথডটি স্ট্রিমের উপাদানগুলোকে একটি Set কোলেকশনে রূপান্তর করে, যা ডুপ্লিকেট মানগুলোকে সরিয়ে দেয়। এটি স্ট্রিমের উপাদানগুলোকে HashSet বা LinkedHashSet (ভিন্ন ভিন্ন সংস্করণে) এর মধ্যে স্থানান্তরিত করে।
Syntax:
Set<T> toSet()ব্যবহার উদাহরণ:
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Mike", "Mike", "Mia");
// Collecting data into a Set using toSet()
Set<String> nameSet = names.stream()
.collect(Collectors.toSet());
System.out.println(nameSet); // Output: [Mike, Jane, John, Mia]
}
}এখানে, toSet() মেথডটি একটি Set কোলেকশনে রূপান্তরিত করেছে, যেখানে ডুপ্লিকেট Mike নামটি সরিয়ে ফেলা হয়েছে।
৩. Collectors.toMap()
toMap() মেথডটি স্ট্রিমের উপাদানগুলোকে একটি Map (Key-Value পেয়ার) তে রূপান্তরিত করে। এর জন্য আপনাকে দুটি ফাংশন পাস করতে হবে: একটি Key তৈরি করার জন্য এবং একটি Value তৈরি করার জন্য।
Syntax:
<Map<K, V>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper)keyMapper: এটি স্ট্রিমের উপাদান থেকে কী (Key) তৈরি করবে।valueMapper: এটি স্ট্রিমের উপাদান থেকে মান (Value) তৈরি করবে।
ব্যবহার উদাহরণ:
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Mike", "Mia");
// Collecting data into a Map using toMap()
Map<String, Integer> nameLengthMap = names.stream()
.collect(Collectors.toMap(name -> name, String::length));
System.out.println(nameLengthMap); // Output: {John=4, Jane=4, Mike=4, Mia=3}
}
}এখানে, toMap() মেথডটি স্ট্রিমের প্রতিটি উপাদানকে একটি Map এ রূপান্তরিত করেছে, যেখানে কী হলো নাম এবং মান হলো সেই নামের দৈর্ঘ্য।
৪. toMap() with Duplicate Keys Handling
যখন আপনি toMap() ব্যবহার করেন এবং স্ট্রিমের মধ্যে একাধিক উপাদান একই কী তৈরি করে, তখন একটি কনফ্লিক্ট তৈরি হয়। এই কনফ্লিক্ট সমাধান করার জন্য third parameter হিসেবে একটি merge function ব্যবহার করা যেতে পারে, যা কী-মিল হওয়া ভ্যালুগুলির মধ্যে কীভাবে একত্রিত হবে তা নির্ধারণ করে।
Syntax with merge function:
<Map<K, V>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper,
BinaryOperator<V> mergeFunction)ব্যবহার উদাহরণ:
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Mike", "Mia", "Mia");
// Collecting data into a Map with merge function to handle duplicates
Map<String, String> nameMap = names.stream()
.collect(Collectors.toMap(
name -> name, // keyMapper
name -> name, // valueMapper
(existingValue, newValue) -> existingValue + "," + newValue)); // merge function
System.out.println(nameMap); // Output: {John=John, Jane=Jane, Mike=Mike, Mia=Mia,Mia}
}
}এখানে, toMap() মেথডটি একই কী (Mia) পেলে তাদের মানগুলি একত্রিত করে।
সারসংক্ষেপ
Java 8-এর Collectors ক্লাসের মাধ্যমে স্ট্রিমের উপাদানগুলোকে বিভিন্ন কোলেকশনে রূপান্তর করা খুবই সহজ। toList(), toSet(), এবং toMap() তিনটি সাধারণ এবং গুরুত্বপূর্ণ কোলেকশন রূপান্তর পদ্ধতি:
toList(): স্ট্রিমের উপাদানগুলোকে একটিListতে রূপান্তরিত করে।toSet(): স্ট্রিমের উপাদানগুলোকে একটিSetতে রূপান্তরিত করে, ডুপ্লিকেট মানগুলি সরিয়ে দেয়।toMap(): স্ট্রিমের উপাদানগুলোকে একটিMapতে রূপান্তরিত করে, যেখানে আপনি কী এবং মান নির্ধারণ করতে পারেন।
এগুলি স্ট্রিমের ডেটাকে বিভিন্ন ফরম্যাটে সংগ্রহ করার জন্য শক্তিশালী এবং সহজ পদ্ধতি প্রদান করে।
Java 8-এ Collectors একটি শক্তিশালী উপাদান হিসেবে উপস্থিত হয়েছে, যা Stream API-র সাথে কাজ করার জন্য সহজে ডেটা সংগ্রহ করতে সাহায্য করে। Java 8-এ কিছু বিল্ট-ইন Collectors যেমন Collectors.toList(), Collectors.toSet(), এবং Collectors.joining() রয়েছে, তবে আপনি নিজের Custom Collectors তৈরি করে আরও নির্দিষ্টভাবে ডেটা সংগ্রহের কাজ করতে পারেন।
Custom Collector তৈরি করা হয় Collector ইন্টারফেসের মাধ্যমে, যা মূলত তিনটি কম্পোনেন্ট দ্বারা কাজ করে:
- Supplier: একটি নতুন সংগ্রহ তৈরি করে।
- Accumulator: স্ট্রিমের প্রতিটি উপাদান সংগ্রহে যুক্ত করে।
- Combiner: মাল্টিপল উপাদানগুলিকে একত্রে যোগ করে।
এছাড়া finisher এবং characteristics ফাংশনগুলোও থাকতে পারে।
১. Custom Collector তৈরি
একটি Custom Collector তৈরি করতে আমরা Collector ইন্টারফেসের তিনটি মেথড ইমপ্লিমেন্ট করি:
- supplier() – নতুন একটি সংগ্রহ তৈরি করবে।
- accumulator() – প্রতিটি উপাদান সংগ্রহে যুক্ত করবে।
- combiner() – মাল্টিপল সংগ্রহকে একত্রিত করবে।
এছাড়া, finisher() (যদি দরকার হয়) এবং characteristics() মেথডও ইমপ্লিমেন্ট করা যেতে পারে।
উদাহরণ: Custom Collector - List of Strings Concatenation
আমরা একটি Custom Collector তৈরি করব যা স্ট্রিংগুলির একটি তালিকাকে একত্রিত করবে।
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class CustomCollectorExample {
public static void main(String[] args) {
List<String> strings = Arrays.asList("Java", "is", "awesome");
// Custom Collector তৈরি
Collector<String, StringBuilder, String> customCollector = Collector.of(
StringBuilder::new, // Supplier: নতুন StringBuilder তৈরি করা
StringBuilder::append, // Accumulator: StringBuilder এ স্ট্রিং অ্যাড করা
StringBuilder::append, // Combiner: দুটি StringBuilder একত্র করা
StringBuilder::toString // Finisher: StringBuilder কে স্ট্রিং-এ রূপান্তর করা
);
// Custom Collector ব্যবহার
String result = strings.stream().collect(customCollector);
System.out.println(result); // Output: Java is awesome
}
}ব্যাখ্যা:
- Supplier:
StringBuilder::new- এটি একটি নতুনStringBuilderতৈরি করবে। - Accumulator:
StringBuilder::append- এটি স্ট্রিং গুলোStringBuilderএ যুক্ত করবে। - Combiner:
StringBuilder::append- এটি দুটিStringBuilderকে একত্রিত করবে। - Finisher:
StringBuilder::toString- এটি স্ট্রিং হিসেবে রিটার্ন করবে।
২. Custom Collector - Counting Occurrences of Elements
এখন একটি কাস্টম কলেক্টর তৈরি করা হবে যা একটি তালিকাতে প্রতিটি উপাদানের উপস্থিতির সংখ্যা গননা করবে।
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class CustomCollectorExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("Apple", "Banana", "Apple", "Orange", "Banana", "Apple");
// Custom Collector তৈরি
Collector<String, Map<String, Integer>, Map<String, Integer>> countCollector = Collector.of(
HashMap::new, // Supplier: একটি নতুন HashMap তৈরি করবে
(map, fruit) -> map.merge(fruit, 1, Integer::sum), // Accumulator: ফ্রুটের কাউন্ট বাড়ানো
(map1, map2) -> { // Combiner: দুটি মাপ একত্রিত করা
map1.forEach((key, value) -> map2.merge(key, value, Integer::sum));
return map2;
},
Function.identity() // Finisher: Map ফিরিয়ে দেবে
);
// Custom Collector ব্যবহার
Map<String, Integer> fruitCount = fruits.stream().collect(countCollector);
System.out.println(fruitCount); // Output: {Apple=3, Banana=2, Orange=1}
}
}ব্যাখ্যা:
- Supplier:
HashMap::new- এটি একটি নতুনHashMapতৈরি করবে যেখানে কীগুলো হবে স্ট্রিং এবং মান হবে ইন্টিজার। - Accumulator:
map.merge(fruit, 1, Integer::sum)- এটি প্রতিটি ফ্রুটের জন্য তার উপস্থিতি গননা করবে। - Combiner:
map1.forEach(...)- দুটিHashMapএকত্রিত করবে। - Finisher:
Function.identity()- এখানে কোনো পরিবর্তন নেই, শুধুMapকে ফিরিয়ে দেওয়া হচ্ছে।
৩. Custom Collector - Grouping Data
আমরা একটি কাস্টম কলেক্টর তৈরি করতে পারি যা কিছু ডেটাকে গ্রুপিং করবে। উদাহরণস্বরূপ, যদি আমরা ফ্রুটগুলিকে তাদের প্রকার (যেমন "Citrus" এবং "Non-Citrus") অনুযায়ী গ্রুপ করতে চাই, তাহলে কাস্টম গ্রুপিং কলেক্টর ব্যবহার করা যায়।
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class CustomCollectorExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("Apple", "Orange", "Lemon", "Banana", "Grapefruit");
// Custom Collector তৈরি
Collector<String, Map<String, List<String>>, Map<String, List<String>>> groupCollector = Collector.of(
HashMap::new, // Supplier: একটি নতুন HashMap তৈরি করবে
(map, fruit) -> { // Accumulator: গ্রুপিং যুক্ত করা
String key = fruit.equals("Orange") || fruit.equals("Lemon") || fruit.equals("Grapefruit") ? "Citrus" : "Non-Citrus";
map.computeIfAbsent(key, k -> new ArrayList<>()).add(fruit);
},
(map1, map2) -> { // Combiner: দুটি মাপ একত্রিত করা
map1.forEach((key, value) -> map2.merge(key, value, (v1, v2) -> { v1.addAll(v2); return v1; }));
return map2;
},
Function.identity() // Finisher: ফাইনাল গ্রুপিং ফিরে দেওয়া
);
// Custom Collector ব্যবহার
Map<String, List<String>> groupedFruits = fruits.stream().collect(groupCollector);
System.out.println(groupedFruits); // Output: {Non-Citrus=[Apple, Banana], Citrus=[Orange, Lemon, Grapefruit]}
}
}ব্যাখ্যা:
- Supplier:
HashMap::new- একটি নতুনHashMapতৈরি করবে। - Accumulator:
map.computeIfAbsent()- ফ্রুটগুলি তাদের প্রকার অনুযায়ী গ্রুপ করবে। - Combiner:
map1.forEach(...)- দুটিMapএকত্রিত করবে। - Finisher:
Function.identity()- কোনো পরিবর্তন ছাড়া ফাইনাল গ্রুপিং ম্যাপ ফেরত দেবে।
৪. Collectors Supporting Characteristics
একটি কাস্টম কলেক্টর তৈরি করার সময় আপনি characteristics() মেথডও ব্যবহার করতে পারেন, যা সংগ্রহের প্রকৃতি সম্পর্কে কিছু তথ্য দেয়। সাধারণত এটি CONCURRENT, UNORDERED, এবং IDEMPOTENT থাকতে পারে।
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class CustomCollectorExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("Apple", "Orange", "Banana", "Grapefruit");
// Custom Collector তৈরি
Collector<String, List<String>, List<String>> customCollector = Collector.of(
ArrayList::new,
List::add,
(list1, list2) -> { list1.addAll(list2); return list1; },
Function.identity(),
Collector.Characteristics.IDENTITY_FINISH
);
List<String> fruitList = fruits.stream().collect(customCollector);
System.out.println(fruitList); // Output: [Apple, Orange, Banana, Grapefruit]
}
}সারসংক্ষেপ
- Custom Collectors তৈরি করার জন্য
Collectorইন্টারফেস ইমপ্লিমেন্ট করতে হয়, যেখানে আপনাকে supplier(), accumulator(), এবং combiner() মেথডগুলো প্রদান করতে হয়। - আপনি finisher(), characteristics() মেথডও কাস্টমাইজ করতে পারেন।
- Custom Collectors ব্যবহার করে আপনি জটিল ডেটা সংগ্রহ এবং ম্যানিপুলেশন করতে পারেন যেমন গুণাগুণ গণনা, গ্রুপিং, কাস্টম ফরম্যাটে ডেটা একত্রিত করা ইত্যাদি।
Java 8 এর Stream API-তে Aggregation এবং Reduction হল দুটি গুরুত্বপূর্ণ কাজ যা Collectors এর মাধ্যমে সম্পন্ন করা হয়। এই দুটি প্রক্রিয়া স্ট্রিমের উপাদানগুলিকে একত্রিত (aggregate) বা সংকুচিত (reduce) করার জন্য ব্যবহৃত হয়।
Aggregation:
Aggregation এর মাধ্যমে, স্ট্রিমের উপাদানগুলোকে একত্রিত করা হয়। এটি সাধারণত collect মেথডের মাধ্যমে করা হয়, যা স্ট্রিমের উপাদানগুলোকে একটি নতুন সংগ্রহ (collection) যেমন List, Set, Map ইত্যাদিতে জমা করে।
Reduction:
Reduction এর মাধ্যমে, স্ট্রিমের উপাদানগুলোকে একটি একক মানে (যেমন যোগফল, গুনফল ইত্যাদি) সংকুচিত করা হয়। এটি সাধারণত reduce মেথড ব্যবহার করে করা হয়, যা স্ট্রিমের উপাদানগুলির উপর একটি বাইনারি অপারেশন প্রয়োগ করে।
১. Aggregation উদাহরণ
Aggregation হল উপাদানগুলোকে একত্রিত করার প্রক্রিয়া, যেমন List, Set বা String তৈরি করা।
উদাহরণ: toList() - List তৈরি করা
import java.util.List;
import java.util.stream.Collectors;
public class AggregationExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
// স্ট্রিমের উপাদানগুলোকে একটি List-এ একত্রিত করা
List<Integer> collectedList = numbers.stream()
.collect(Collectors.toList());
System.out.println(collectedList); // Output: [1, 2, 3, 4, 5]
}
}এখানে, Collectors.toList() ব্যবহার করে স্ট্রিমের উপাদানগুলোকে একটি নতুন List-এ একত্রিত করা হয়েছে।
উদাহরণ: joining() - String তৈরি করা
import java.util.List;
import java.util.stream.Collectors;
public class AggregationExample {
public static void main(String[] args) {
List<String> words = List.of("Java", "is", "fun");
// সব শব্দকে একটি স্ট্রিং-এ যোগ করা
String result = words.stream()
.collect(Collectors.joining(" "));
System.out.println(result); // Output: Java is fun
}
}এখানে, Collectors.joining() ব্যবহার করে স্ট্রিমের সব উপাদানকে একটি একক String-এ একত্রিত করা হয়েছে, যেখানে প্রতিটি উপাদানের মধ্যে একটি স্পেস যুক্ত করা হয়েছে।
উদাহরণ: groupingBy() - গ্রুপিং করা
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class AggregationExample {
public static void main(String[] args) {
List<String> words = List.of("apple", "banana", "cherry", "apricot");
// প্রথম অক্ষরের উপর ভিত্তি করে গ্রুপিং করা
Map<Character, List<String>> groupedByFirstLetter = words.stream()
.collect(Collectors.groupingBy(word -> word.charAt(0)));
System.out.println(groupedByFirstLetter);
// Output: {a=[apple, apricot], b=[banana], c=[cherry]}
}
}এখানে, Collectors.groupingBy() ব্যবহার করে প্রথম অক্ষরের ভিত্তিতে গ্রুপিং করা হয়েছে।
২. Reduction উদাহরণ
Reduction হল স্ট্রিমের উপাদানগুলোর উপর একটি বাইনারি অপারেশন প্রয়োগ করে একটি একক মানে রূপান্তর করা। reduce() মেথডটি ব্যবহার করে সাধারণত এই কাজটি করা হয়।
উদাহরণ: reduce() - যোগফল বের করা
import java.util.List;
import java.util.Optional;
public class ReductionExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
// স্ট্রিমের উপাদানগুলোর যোগফল বের করা (Reduction)
Optional<Integer> sum = numbers.stream()
.reduce((a, b) -> a + b);
sum.ifPresent(System.out::println); // Output: 15
}
}এখানে, reduce() মেথড ব্যবহার করে আমরা স্ট্রিমের সকল সংখ্যার যোগফল বের করেছি। reduce() একটি বাইনারি অপারেশন (এখানে a + b) প্রয়োগ করে একটি একক ফলাফল (যোগফল) বের করে।
উদাহরণ: summarizingInt() - পরিসংখ্যান তৈরি
import java.util.List;
import java.util.IntSummaryStatistics;
import java.util.stream.Collectors;
public class ReductionExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
// সংখ্যাগুলির উপর সঙ্গতিপূর্ণ পরিসংখ্যান তৈরি
IntSummaryStatistics stats = numbers.stream()
.collect(Collectors.summarizingInt(Integer::intValue));
System.out.println("Sum: " + stats.getSum()); // Output: Sum: 15
System.out.println("Average: " + stats.getAverage()); // Output: Average: 3.0
System.out.println("Max: " + stats.getMax()); // Output: Max: 5
}
}এখানে, Collectors.summarizingInt() ব্যবহার করা হয়েছে যা স্ট্রিমের উপাদানগুলোর উপর পরিসংখ্যান তৈরি করে, যেমন যোগফল, গড়, সর্বোচ্চ মান ইত্যাদি।
উদাহরণ: count() - উপাদানের সংখ্যা
import java.util.List;
public class ReductionExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
// স্ট্রিমের উপাদানগুলির সংখ্যা বের করা
long count = numbers.stream().count();
System.out.println("Count: " + count); // Output: 5
}
}এখানে, count() মেথড ব্যবহার করে স্ট্রিমের উপাদানগুলির সংখ্যা বের করা হয়েছে।
৩. Aggregation এবং Reduction এর পার্থক্য
| বৈশিষ্ট্য | Aggregation | Reduction |
|---|---|---|
| ধরন | একাধিক উপাদানকে একত্রিত করা (যেমন List, Set তৈরি করা) | একাধিক উপাদানকে একটি একক মানে সংকুচিত করা (যেমন যোগফল) |
| উদাহরণ | toList(), joining(), groupingBy() | reduce(), summarizingInt(), count() |
| ফলাফল | একটি সংগ্রহ তৈরি করা (List, Set, Map ইত্যাদি) | একটি একক মান (যেমন যোগফল, গড়, সর্বোচ্চ ইত্যাদি) |
| পদ্ধতি | collect() মেথড ব্যবহার করা হয় | reduce() মেথড এবং অন্যান্য পরিসংখ্যান পদ্ধতি |
সারসংক্ষেপ
- Aggregation হলো স্ট্রিমের উপাদানগুলোকে একটি সংগ্রহে একত্রিত করার প্রক্রিয়া (যেমন List, Set বা String তৈরি করা)।
- Reduction হলো স্ট্রিমের উপাদানগুলোকে একটি একক মানে সংকুচিত করার প্রক্রিয়া (যেমন যোগফল, গুনফল, পরিসংখ্যান তৈরি করা)।
- Java 8 এর Collectors API-তে অনেক বিল্ট-ইন অপারেশন রয়েছে যা এই দুটি প্রক্রিয়া সহজে করতে সাহায্য করে।
Collectors ব্যবহার করে আপনি সহজেই স্ট্রিমের উপাদানগুলোকে একত্রিত বা সংকুচিত করে বিভিন্ন কার্যকরী ফলাফল অর্জন করতে পারবেন।
Read more