জাভার মধ্যে অনেক উন্নত বিষয় রয়েছে যা একটি শক্তিশালী, স্কেলেবল এবং দক্ষ অ্যাপ্লিকেশন তৈরি করতে সাহায্য করে। নিচে কিছু জাভা অ্যাডভান্সড টপিকস এবং সেগুলোর উদাহরণ দেওয়া হল, যা আপনাকে জাভার ক্ষমতাগুলির সাথে আরও গভীরে যেতে সাহায্য করবে।
জাভায় মাল্টিথ্রেডেড অ্যাপ্লিকেশন তৈরি করতে কনকারেন্ট ইউটিলিটিগুলি খুবই উপকারী।
ExecutorService
ব্যবহার করে একাধিক কাজ সমানভাবে সম্পাদনimport java.util.concurrent.*;
public class ConcurrencyExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
// কাজ পাঠানো
executorService.submit(() -> {
System.out.println("কাজ ১ - এক্সিকিউট করছেন: " + Thread.currentThread().getName());
});
executorService.submit(() -> {
System.out.println("কাজ ২ - এক্সিকিউট করছেন: " + Thread.currentThread().getName());
});
executorService.shutdown(); // এক্সিকিউটর বন্ধ করা
}
}
ExecutorService
থ্রেড পুল ম্যানেজ করার জন্য ব্যবহৃত হয়।submit()
মেথডে কাজ পাঠানো হয়, এবং থ্রেড পুলের থ্রেডগুলো কাজগুলো একসাথে সম্পাদন করে।Streams API একটি শক্তিশালী অ্যাবস্ট্রাকশন যা একটি সিকোয়েন্স (যেমন, কোলেকশন) প্রক্রিয়া করার জন্য ব্যবহার করা হয়।
import java.util.*;
import java.util.stream.*;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// বিপরীত সংখ্যা ফিল্টার এবং ডাবল করা
List<Integer> doubledEvens = numbers.stream()
.filter(n -> n % 2 == 0) // বিপরীত সংখ্যা ফিল্টার
.map(n -> n * 2) // প্রতিটি বিপরীত সংখ্যাকে ডাবল করা
.collect(Collectors.toList()); // ফলাফলকে একটি তালিকায় রূপান্তর করা
System.out.println(doubledEvens); // আউটপুট: [4, 8, 12, 16, 20]
}
}
filter()
পদ্ধতি একটি শর্ত অনুযায়ী উপাদান ফিল্টার করে।map()
পদ্ধতি উপাদানগুলিকে রূপান্তর করে।collect()
পদ্ধতি ফলাফলগুলো সংগ্রহ করে একটি তালিকায় পরিণত করে।Reflection একটি শক্তিশালী ফিচার যা আপনাকে জাভা ক্লাসের রানটাইমে অবজেক্ট ইনস্পেক্ট এবং মডিফাই করার সুযোগ দেয়।
import java.lang.reflect.*;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// ক্লাস অবজেক্ট তৈরি
MyClass obj = new MyClass();
// ক্লাস অবজেক্ট পাওয়া
Class<?> clazz = obj.getClass();
// মেথড ইনভোকেশন
Method method = clazz.getDeclaredMethod("sayHello");
method.setAccessible(true); // প্রাইভেট মেথড অ্যাক্সেসযোগ্য করা
method.invoke(obj); // মেথড কল করা
}
}
class MyClass {
private void sayHello() {
System.out.println("প্রাইভেট মেথড থেকে শুভেচ্ছা!");
}
}
sayHello()
প্রাইভেট মেথডটি Reflection
দিয়ে কল করা হয়েছে।ডিজাইন প্যাটার্নগুলি সফটওয়্যার ডিজাইনের পুনরাবৃত্ত সমস্যাগুলির সাধারণ সমাধান। একটি জনপ্রিয় ডিজাইন প্যাটার্ন হল Singleton Pattern।
public class Singleton {
private static Singleton instance;
// কনস্ট্রাক্টর প্রাইভেট করা
private Singleton() {}
// একক ইনস্ট্যান্স প্রাপ্তি
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class SingletonExample {
public static void main(String[] args) {
// Singleton ইনস্ট্যান্স অ্যাক্সেস করা
Singleton singleton = Singleton.getInstance();
System.out.println(singleton);
}
}
Singleton
ডিজাইন প্যাটার্ন একটি ক্লাসের একক ইনস্ট্যান্স নিশ্চিত করে এবং সেই ইনস্ট্যান্সের জন্য একটি গ্লোবাল পয়েন্ট প্রদান করে।getInstance()
মেথড একমাত্র ইনস্ট্যান্স তৈরি এবং রিটার্ন করে।জাভার মেমরি ম্যানেজমেন্ট প্রধানত গার্বেজ কালেকশনের মাধ্যমে পরিচালিত হয়, যা অপ্রয়োজনীয় অবজেক্টগুলোকে মুছে ফেলে।
public class GarbageCollectionExample {
public static void main(String[] args) {
// অবজেক্ট তৈরি
GarbageCollectionExample obj1 = new GarbageCollectionExample();
GarbageCollectionExample obj2 = new GarbageCollectionExample();
// রেফারেন্স নাল করা
obj1 = null;
obj2 = null;
// গার্বেজ কালেকশন অনুরোধ করা
System.gc(); // গার্বেজ কালেক্টরকে স্পষ্টভাবে ডাকা (প্রোডাকশনে এটি করা উচিত নয়)
System.out.println("গার্বেজ কালেকশন অনুরোধ পাঠানো হয়েছে।");
}
@Override
protected void finalize() throws Throwable {
// অবজেক্ট গার্বেজ কালেক্টরের দ্বারা সংগ্রহের আগে এই মেথডটি কল হয়
System.out.println("অবজেক্ট গার্বেজ কালেক্ট করা হচ্ছে।");
super.finalize();
}
}
System.gc()
গার্বেজ কালেকশন অনুরোধ করে, যদিও এটি তত্ক্ষণাত্ কার্যকর হবে না।finalize()
মেথডটি গার্বেজ কালেকশন দ্বারা অবজেক্ট সংগ্রহের আগে কল হয়।জাভা নেটওয়ার্কিং লাইব্রেরি ব্যবহার করে আপনি ক্লায়েন্ট-সার্ভার সিস্টেম তৈরি করতে পারেন।
সার্ভার (Server.java)
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(5000);
System.out.println("ক্লায়েন্টের জন্য সার্ভার অপেক্ষা করছে...");
Socket socket = serverSocket.accept(); // ক্লায়েন্ট কানেকশন গ্রহণ করা
System.out.println("ক্লায়েন্ট কানেক্টেড।");
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = reader.readLine();
System.out.println("ক্লায়েন্টের মেসেজ: " + message);
socket.close();
serverSocket.close();
}
}
ক্লায়েন্ট (Client.java)
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 5000); // সার্ভারে কানেক্ট করা
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
writer.println("ক্লায়েন্ট থেকে শুভেচ্ছা!");
socket.close();
}
}
Java 8 এ ফাংশনাল ইন্টারফেস এবং ল্যাম্বডা এক্সপ্রেশন অন্তর্ভুক্ত করা হয়েছে, যা ফাংশনাল প্রোগ্রামিং ধারণাকে সমর্থন করে।
Function
ইন্টারফেসের সাথে ল্যাম্বডা এক্সপ্রেশন ব্যবহারimport java.util.function.Function;
public class FunctionInterfaceExample {
public static void main(String[] args) {
Function<Integer, Integer> square = (n) -> n * n;
System.out.println("৫ এর বর্গ: " + square.apply(5)); // আউটপুট: ২৫
}
}
Function<Integer, Integer>
একটি ফাংশনাল ইন্টারফেস যা একটি ইনপুট আর্গুমেন্ট নেয় এবং একটি ফলাফল রিটার্ন করে।(n) -> n * n
apply()
মেথডের বাস্তবায়ন।Serialization হল একটি অবজেক্টকে বাইট স্ট্রিমে রূপান্তর করা এবং Deserialization হল এটি পুনরায় অবজেক্টে রূপান্তর করা।
import java.io.*;
class Person implements Serializable {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class SerializationExample {
public static void main(String[] args) {
Person person = new Person("John", 30);
try {
// অবজেক্ট সিরিয়ালাইজ করা
FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(person);
out.close();
fileOut.close();
System.out.println("অবজেক্ট সিরিয়ালাইজড।");
// অবজেক্ট ডেসিরিয়ালাইজ করা
FileInputStream fileIn = new FileInputStream("person.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Person deserializedPerson = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("ডেসিরিয়ালাইজড ব্যক্তি: " + deserializedPerson.name + ", " + deserializedPerson.age);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Serializable
ইন্টারফেস ব্যবহার করে ক্লাসকে সিরিয়ালাইজযোগ্য করা হয়।এই অ্যাডভান্সড জাভা টপিকগুলি জাভার বিভিন্ন শক্তিশালী বৈশিষ্ট্য এবং ক্ষমতাগুলিকে বিস্তারিতভাবে তুলে ধরে, যেমন কনকারেন্সি, ফাংশনাল প্রোগ্রামিং, ডিজাইন প্যাটার্ন, নেটওয়ার্কিং, সিরিয়ালাইজেশন, এবং আরও অনেক কিছু। এই সব টপিক শিখে আপনি আরও দক্ষ এবং উন্নত জাভা অ্যাপ্লিকেশন তৈরি করতে পারবেন।
Java 8 এ ল্যাম্বডা এক্সপ্রেশন (Lambda Expressions) পরিচিতি পেয়েছে, যা কোডকে আরও সংক্ষিপ্ত এবং পাঠযোগ্য করে তোলে, বিশেষ করে ফাংশনাল ইন্টারফেসের সাথে কাজ করার সময়। ল্যাম্বডা এক্সপ্রেশন হল একটি স্পষ্ট এবং সংক্ষিপ্ত উপায়, যেটি একটি পদ্ধতি (Method) কে অভিব্যক্তি (Expression) হিসেবে প্রকাশ করে।
ল্যাম্বডা এক্সপ্রেশন মূলত ব্যবহৃত হয় যখন আপনি এমন একটি পদ্ধতি বা ফাংশন তৈরি করতে চান, যেটি অন্য একটি পদ্ধতি বা ফাংশনের আর্গুমেন্ট হিসেবে পাস করা যাবে বা এটি অন্য পদ্ধতির মাধ্যমে কার্যকর হবে।
ল্যাম্বডা এক্সপ্রেশনের সিনট্যাক্স হলো:
(parameter) -> expression
এখানে:
parameter
: পদ্ধতির ইনপুট প্যারামিটার।->
: ল্যাম্বডা অপারেটর, যা প্যারামিটার এবং পদ্ধতির শরীরকে আলাদা করে।expression
: পদ্ধতির কার্যকারিতা বা বাস্তবায়ন।এটি একটি সহজ উদাহরণ যেখানে আমরা Runnable
ইন্টারফেসের মাধ্যমে একটি থ্রেড তৈরি করছি ল্যাম্বডা এক্সপ্রেশন ব্যবহার করে।
public class LambdaExample {
public static void main(String[] args) {
// ল্যাম্বডা এক্সপ্রেশন দিয়ে থ্রেড তৈরি
Thread thread = new Thread(() -> {
System.out.println("ল্যাম্বডা এক্সপ্রেশন থেকে শুভেচ্ছা!");
});
thread.start(); // থ্রেড শুরু করা
}
}
Thread
অবজেক্ট তৈরি করেছি এবং এর কন্সট্রাক্টরে একটি ল্যাম্বডা এক্সপ্রেশন পাস করেছি।() -> { System.out.println("ল্যাম্বডা এক্সপ্রেশন থেকে শুভেচ্ছা!"); }
run()
পদ্ধতিকে বাস্তবায়ন করছে, যা থ্রেড চালু হলে একটি বার্তা কনসোলে প্রিন্ট করে।এবার আমরা দেখবো কিভাবে ল্যাম্বডা এক্সপ্রেশন প্যারামিটার ব্যবহার করতে পারে। এখানে, আমরা Comparator
ইন্টারফেস ব্যবহার করে একটি স্ট্রিংয়ের তালিকা সজ্জিত (sort) করছি।
import java.util.*;
public class LambdaExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Alice", "Bob", "David");
// ল্যাম্বডা এক্সপ্রেশন দিয়ে সজ্জিত করা
Collections.sort(names, (name1, name2) -> name1.compareTo(name2));
// সজ্জিত তালিকা প্রিন্ট করা
names.forEach(name -> System.out.println(name));
}
}
Collections.sort()
মেথড একটি Comparator
ইন্টারফেস নেয়, যার মাধ্যমে আমরা সজ্জিত করার লজিক প্রদান করি।(name1, name2) -> name1.compareTo(name2)
পাস করেছি, যা দুটি স্ট্রিংকে তুলনা করে তাদের সাজিয়ে দেয়।forEach
মেথডের মাধ্যমে ল্যাম্বডা এক্সপ্রেশন name -> System.out.println(name)
ব্যবহার করে তালিকার প্রতিটি নাম প্রিন্ট করা হয়।ল্যাম্বডা এক্সপ্রেশন রিটার্ন ভ্যালুও প্রদান করতে পারে। এখানে, আমরা একটি Function
ইন্টারফেস ব্যবহার করে একটি সংখ্যার বর্গ (square) বের করছি।
import java.util.function.Function;
public class LambdaExample {
public static void main(String[] args) {
// ল্যাম্বডা এক্সপ্রেশন দিয়ে সংখ্যার বর্গ বের করা
Function<Integer, Integer> square = (x) -> x * x;
// ল্যাম্বডা এক্সপ্রেশন প্রয়োগ
System.out.println("৫ এর বর্গ: " + square.apply(5)); // আউটপুট: ২৫
System.out.println("১০ এর বর্গ: " + square.apply(10)); // আউটপুট: ১০০
}
}
Function<Integer, Integer>
ডিফাইন করেছি, যা একটি সংখ্যার বর্গ বের করে।(x) -> x * x
একটি পূর্ণসংখ্যা x
গ্রহণ করে এবং তার বর্গ x * x
রিটার্ন করে।apply()
মেথডের মাধ্যমে এই ল্যাম্বডা এক্সপ্রেশন প্রয়োগ করা হয়।ল্যাম্বডা এক্সপ্রেশন একাধিক স্টেটমেন্টও ধারণ করতে পারে। এখানে, আমরা একটি তালিকা থেকে শুধু বিপরীত সংখ্যা (even numbers) ফিল্টার করছি এবং তাদের প্রিন্ট করছি।
import java.util.*;
public class LambdaExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// ল্যাম্বডা এক্সপ্রেশন দিয়ে শুধুমাত্র বিপরীত সংখ্যা বের করা
numbers.stream()
.filter(n -> {
if (n % 2 == 0) {
return true;
}
return false;
})
.forEach(n -> System.out.println(n)); // আউটপুট: ২, ৪, ৬, ৮, ১০
}
}
stream()
ব্যবহার করে একটি স্ট্রীম তৈরি করেছি।filter()
মেথডের মধ্যে একটি ল্যাম্বডা এক্সপ্রেশন দেওয়া হয়েছে যা শুধুমাত্র বিপরীত (even) সংখ্যাগুলোকে রাখে।forEach()
মেথডের মাধ্যমে ল্যাম্বডা এক্সপ্রেশন n -> System.out.println(n)
ব্যবহার করে প্রতিটি বিপরীত সংখ্যা প্রিন্ট করা হয়।আমরা কাস্টম ফাংশনাল ইন্টারফেস তৈরি করতে পারি এবং সেটি ব্যবহার করে ল্যাম্বডা এক্সপ্রেশন প্রয়োগ করতে পারি।
// কাস্টম ফাংশনাল ইন্টারফেস
@FunctionalInterface
interface MyFunction {
int operation(int a, int b);
}
public class LambdaExample {
public static void main(String[] args) {
// ল্যাম্বডা এক্সপ্রেশন দিয়ে 'operation' পদ্ধতি বাস্তবায়ন
MyFunction add = (a, b) -> a + b;
MyFunction multiply = (a, b) -> a * b;
// অপারেশন প্রয়োগ
System.out.println("যোগফল: " + add.operation(5, 3)); // আউটপুট: ৮
System.out.println("গুণফল: " + multiply.operation(5, 3)); // আউটপুট: ১৫
}
}
MyFunction
ডিফাইন করেছি, যার একটি operation()
মেথড আছে।a, b -> a + b
এবং a, b -> a * b
দিয়ে দুটি অপারেশন (যোগ এবং গুণ) বাস্তবায়ন করেছি।Stream API
এবং ল্যাম্বডা এক্সপ্রেশন ব্যবহার করে সংগ্রহ (collections) প্যারালালভাবে প্রসেস করা সহজ হয়।Java 8 এর ল্যাম্বডা এক্সপ্রেশন একটি শক্তিশালী টুল যা Java কোডকে আরও সংক্ষিপ্ত, পরিষ্কার এবং কার্যকরী করে তোলে। এটি ফাংশনাল প্রোগ্রামিং ধারণা বাস্তবায়ন করার মাধ্যমে Java-তে আরও নতুন কৌশল এবং ফিচার ব্যবহার করার সুযোগ দেয়।
Java 8 Streams API একটি শক্তিশালী ফিচার যা কোডিংকে সহজ এবং আরও কার্যকরী করে তোলে, বিশেষত Collections থেকে ডেটা ফিল্টারিং, ম্যানিপুলেশন, এবং প্রক্রিয়াকরণে। এটি ডেটাকে পারালাল ও সিরিয়াল প্রক্রিয়াকরণ করতে সহায়ক এবং ফাংশনাল প্রোগ্রামিং কনসেপ্ট ব্যবহার করে।
নিচে একটি উদাহরণ দেওয়া হল যেখানে Java 8 এর Streams API ব্যবহার করে Collections থেকে ডেটা ফিল্টার করা হয়েছে।
import java.util.*;
import java.util.stream.*;
public class StreamsApiExample {
public static void main(String[] args) {
// একটি List of Integer তৈরি করা
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 1. Filter করা: যেসব সংখ্যার মান 5 এর বেশি তাদের ফিল্টার করা
System.out.println("Numbers greater than 5:");
numbers.stream()
.filter(n -> n > 5) // ফিল্টার কন্ডিশন
.forEach(System.out::println); // প্রিন্ট করা
// 2. Map করা: প্রত্যেক সংখ্যার উপর 2 গুণ বৃদ্ধি করা
System.out.println("\nNumbers multiplied by 2:");
numbers.stream()
.map(n -> n * 2) // প্রতিটি সংখ্যার 2 গুণ বৃদ্ধি
.forEach(System.out::println);
// 3. Collect করা: ফিল্টার করা সংখ্যাগুলিকে একটি নতুন List এ সংগ্রহ করা
List<Integer> filteredList = numbers.stream()
.filter(n -> n % 2 == 0) // শুধু even সংখ্যা
.collect(Collectors.toList()); // নতুন List এ সংগ্রহ
System.out.println("\nFiltered even numbers: " + filteredList);
// 4. FindFirst: প্রথম মান পাওয়া
Integer firstEvenNumber = numbers.stream()
.filter(n -> n % 2 == 0)
.findFirst() // প্রথম even সংখ্যা পাওয়া
.orElse(null); // যদি কিছু না থাকে
System.out.println("\nFirst even number: " + firstEvenNumber);
// 5. Reduce: সব সংখ্যা যোগ করা
int sum = numbers.stream()
.reduce(0, Integer::sum); // সব সংখ্যার যোগফল
System.out.println("\nSum of all numbers: " + sum);
}
}
filter()
: এটি একটি Intermediate Operation যা একটি প্রেডিকেট (condition) গ্রহণ করে এবং সেটি পূর্ণ হলে উপাদানগুলো রিটার্ন করে। উদাহরণস্বরূপ, filter(n -> n > 5)
কন্ডিশনটি এমন সব সংখ্যাকে ফিল্টার করবে যেগুলি ৫ এর বেশি।map()
: এটি একটি Intermediate Operation যা প্রতিটি উপাদানের উপর কোনো অপারেশন প্রয়োগ করে এবং ফলাফল রিটার্ন করে। এখানে map(n -> n * 2)
প্রতিটি সংখ্যাকে ২ গুণ করবে।collect()
: এটি একটি Terminal Operation যা একটি স্ট্রিমের উপাদানগুলোকে একটি সংগ্রহ (Collection) তে রূপান্তরিত করে। উদাহরণস্বরূপ, Collectors.toList()
ব্যবহার করে ফিল্টার করা সংখ্যাগুলো একটি List
এ সংগ্রহ করা হয়েছে।findFirst()
: এটি একটি Terminal Operation যা প্রথম মিল পাওয়া উপাদানটি রিটার্ন করে। এখানে এটি প্রথম even সংখ্যা খুঁজে বের করেছে।reduce()
: এটি একটি Terminal Operation যা স্ট্রিমের উপাদানগুলোকে একত্রিত করে (উদাহরণস্বরূপ, যোগফল)। এখানে এটি সব সংখ্যার যোগফল বের করেছে।Numbers greater than 5:
6
7
8
9
10
Numbers multiplied by 2:
2
4
6
8
10
12
14
16
18
20
Filtered even numbers: [2, 4, 6, 8, 10]
First even number: 2
Sum of all numbers: 55
filter()
, map()
) এবং Terminal Operations (যেমন collect()
, forEach()
, reduce()
) ব্যবহার করে ডেটা প্রক্রিয়াকরণ করতে পারেন।এটি খুবই কার্যকরী যখন Collections থেকে ডেটা ফিল্টার, ম্যানিপুলেট, বা প্রক্রিয়াকরণ করা হয়।
NullPointerException
Optional
ক্লাসটি Java 8 এ পরিচিতি পায় এবং এটি মূলত null চেকিং সমস্যা সমাধানের জন্য ডিজাইন করা হয়েছে। এটি একটি wrapper ক্লাস যা null না থাকা মানের জন্য একটি অবজেক্ট ধারণ করতে পারে এবং null মানের জন্য একটি নিরাপদ বিকল্প প্রদান করে। এর মাধ্যমে NullPointerException
প্রতিরোধ করা সম্ভব হয়।
Optional
একটি container অবজেক্ট যা মূলত null
বা non-null
মান ধারণ করতে পারে।Optional
ব্যবহার করে আমরা null
চেক করা এবং NullPointerException
থেকে বাঁচা সহজ করে ফেলি।এখানে একটি উদাহরণ দেওয়া হলো, যেখানে Optional
ব্যবহার করা হয়েছে null
চেকিং এবং NullPointerException
প্রতিরোধের জন্য।
import java.util.Optional;
public class OptionalExample {
public static void main(String[] args) {
// উদাহরণ 1: null চেক করার জন্য Optional ব্যবহার
String name = "John Doe";
Optional<String> optionalName = Optional.ofNullable(name);
// Optional এর মাধ্যমে null চেক করা
optionalName.ifPresent(n -> System.out.println("নাম: " + n));
// উদাহরণ 2: null চেক না করে মান নেওয়া
String result = optionalName.orElse("নাম পাওয়া যায়নি");
System.out.println("ফলাফল: " + result);
// উদাহরণ 3: Optional এর মাধ্যমে null চেক এবং ডিফল্ট মান নির্ধারণ করা
String nullName = null;
Optional<String> optionalNullName = Optional.ofNullable(nullName);
// Optional থেকে null থাকলে ডিফল্ট মান দেওয়া
String result2 = optionalNullName.orElse("নাম পাওয়া যায়নি");
System.out.println("ফলাফল: " + result2);
// উদাহরণ 4: Optional এর মাধ্যমে Exeption handling করা
String nameFromOptional = optionalNullName.orElseThrow(() -> new IllegalArgumentException("নাম অনুপস্থিত"));
System.out.println("নাম: " + nameFromOptional); // এটি এক্সসেপশন ছুঁড়ে দিবে
}
}
Optional.ofNullable()
: এই মেথডটি একটি Optional
অবজেক্ট তৈরি করে যা একটি null
বা non-null
ভ্যালু ধারণ করতে পারে।ifPresent()
: যদি মানটি non-null হয়, তবে এটি ifPresent
মেথডের ল্যাম্বডা এক্সপ্রেশন (অথবা কোড ব্লক) রান করবে।orElse()
: এটি Optional
অবজেক্টের মধ্যে একটি মান থাকলে তা রিটার্ন করবে, এবং যদি মানটি null হয়, তবে একটি ডিফল্ট মান প্রদান করবে।orElseThrow()
: এটি Optional
অবজেক্টের মধ্যে null
থাকলে একটি কাস্টম এক্সসেপশন ছুঁড়ে দেবে।নাম: John Doe
ফলাফল: John Doe
ফলাফল: নাম পাওয়া যায়নি
Exception in thread "main" java.lang.IllegalArgumentException: নাম অনুপস্থিত
at OptionalExample.main(OptionalExample.java:22)
isPresent()
এবং get()
মেথড ব্যবহার:Optional<String> optional = Optional.of("Java");
if (optional.isPresent()) {
System.out.println("মান পাওয়া গেছে: " + optional.get());
} else {
System.out.println("মান পাওয়া যায়নি");
}
map()
এবং flatMap()
মেথড ব্যবহার:map()
মেথডটি যদি Optional
অবজেক্টে মান থাকে, তবে তা একটি ফাংশন প্রয়োগ করে নতুন Optional
তৈরি করবে।
Optional<String> nameOptional = Optional.of("John");
Optional<String> upperName = nameOptional.map(String::toUpperCase);
System.out.println(upperName.get()); // Output: JOHN
Optional
ব্যবহার করে সহজেই null
চেক করা যায় এবং NullPointerException
কমানো যায়।Optional
ব্যবহার করে কোডে null
চেক করার জন্য অতিরিক্ত if-else স্টেটমেন্ট কমানো যায়।Optional
ব্যবহার করে chainable মেথড (যেমন map()
, flatMap()
) ব্যবহার করে কমপ্লেক্স অপারেশন করা যায়।Optional
কিছুটা অতিরিক্ত ওভারহেড তৈরি করতে পারে, বিশেষত যখন সিঙ্গল ভ্যালুর সাথে কাজ করা হয়।Optional
শুধুমাত্র ঐ ক্ষেত্রে ব্যবহার করা উচিত যেখানে null
এর প্রভাব থাকে, যেমন ফাংশনে null
ফেরত দেওয়া বা মানের অনুপস্থিতি।Optional
ক্লাস Java 8 এ একটি শক্তিশালী টুল হিসেবে পরিচিত, যা NullPointerException
প্রতিরোধ এবং নিরাপদভাবে null
চেক করার সুযোগ দেয়। এটি null
মান নিয়ে কাজ করার সময় কোডের দক্ষতা এবং পঠনযোগ্যতা বৃদ্ধি করে।
Java 8 থেকে Functional Interfaces এবং Lambda Expressions পরিচিত হয়। Functional Interface এমন একটি ইন্টারফেস যা শুধুমাত্র একটি অ্যাবস্ট্রাক্ট মেথড ডিফাইন করে। Java 8 এ, আপনি Lambda Expressions ব্যবহার করে Functional Interface এর মেথড ইমপ্লিমেন্ট করতে পারেন।
এখানে কিছু উদাহরণ দেওয়া হলো যা Functional Interface তৈরি এবং ব্যবহার দেখাবে:
একটি Functional Interface তৈরি করার জন্য, আপনাকে একটি ইন্টারফেস তৈরি করতে হবে এবং সেটিতে শুধুমাত্র একটি অ্যাবস্ট্রাক্ট মেথড থাকবে। Java 8 থেকে, আপনি @FunctionalInterface
অ্যানোটেশন ব্যবহার করে এটি চিহ্নিত করতে পারেন, যদিও এটি ঐচ্ছিক।
@FunctionalInterface
public interface Greeting {
void sayHello(String name); // একমাত্র অ্যাবস্ট্রাক্ট মেথড
}
Functional Interface ব্যবহার করার সবচেয়ে ভালো উপায় হচ্ছে Lambda Expression। Lambda Expression আপনাকে ক্লাসের প্রয়োজন ছাড়াই সরাসরি মেথড ইমপ্লিমেন্ট করার সুযোগ দেয়।
public class FunctionalInterfaceExample {
public static void main(String[] args) {
// Lambda Expression ব্যবহার করে Functional Interface এর মেথড ইমপ্লিমেন্ট
Greeting greeting = (name) -> System.out.println("Hello, " + name + "!");
// মেথড কল করা
greeting.sayHello("John");
}
}
Hello, John!
Java 8 এ অনেক Built-in Functional Interface রয়েছে যা আপনাকে দ্রুত কাজ করতে সাহায্য করবে। এগুলির মধ্যে Predicate
, Function
, Consumer
, Supplier
ইত্যাদি অন্তর্ভুক্ত রয়েছে। এখানে কয়েকটি উদাহরণ দেওয়া হলো:
Predicate<T>
একটি Functional Interface যা একটি শর্ত প্রদান করে এবং boolean
মান প্রদান করে। এটি একটি ইনপুট নিয়ে তার উপর শর্ত প্রয়োগ করে।
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
// Predicate Interface এর মাধ্যমে একটি শর্ত তৈরি
Predicate<Integer> isEven = (n) -> n % 2 == 0;
// শর্ত পরীক্ষা করা
System.out.println(isEven.test(4)); // true
System.out.println(isEven.test(7)); // false
}
}
true
false
Function<T, R>
একটি Functional Interface যা একটি ইনপুট নেয় এবং একটি আউটপুট প্রদান করে। এখানে একটি Function
ব্যবহার করা হয়েছে যা নামের উপর ভিত্তি করে তার লেন্থ প্রদান করে।
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
// Function Interface ব্যবহার করে String এর লেন্থ বের করা
Function<String, Integer> stringLength = (str) -> str.length();
// আউটপুট প্রিন্ট করা
System.out.println(stringLength.apply("Java")); // 4
System.out.println(stringLength.apply("Functional Interface")); // 19
}
}
4
19
Consumer<T>
একটি Functional Interface যা একটি ইনপুট নেয় এবং কিছু করে (কিন্তু কোন আউটপুট প্রদান করে না)। এটি সাধারণত কোন কাজ সম্পাদন করার জন্য ব্যবহৃত হয়, যেমন ডাটা প্রিন্ট করা।
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
// Consumer Interface ব্যবহার করে একটি মেসেজ প্রিন্ট করা
Consumer<String> printMessage = (message) -> System.out.println(message);
// Consumer কল করা
printMessage.accept("Hello from Consumer!");
}
}
Hello from Consumer!
Supplier<T>
একটি Functional Interface যা কোন ইনপুট নেয় না, কিন্তু একটি আউটপুট প্রদান করে। এটি সাধারণত ডাটা তৈরি করার জন্য ব্যবহৃত হয়।
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
// Supplier Interface ব্যবহার করে একটি ভ্যালু প্রদান করা
Supplier<Double> randomValue = () -> Math.random();
// Supplier কল করা
System.out.println(randomValue.get()); // এটি একটি র্যান্ডম ডাবল ভ্যালু প্রদান করবে
}
}
0.4675361892615735 (প্রতিবার আলাদা হবে)
Java 8 এ আপনি বিভিন্ন Functional Interfaces একসাথে ব্যবহার করতে পারেন এবং chaining (সংযোগ) করতে পারেন। এখানে Predicate
, Function
ইত্যাদি একসাথে chaining করে উদাহরণ দেওয়া হয়েছে।
import java.util.function.Function;
import java.util.function.Predicate;
public class ChainingExample {
public static void main(String[] args) {
// Predicate ব্যবহার করে শর্ত তৈরি করা
Predicate<Integer> isEven = (n) -> n % 2 == 0;
Predicate<Integer> isPositive = (n) -> n > 0;
// Function ব্যবহার করে নামের লেন্থ বের করা
Function<String, Integer> stringLength = (str) -> str.length();
// chaining করা
String name = "Java";
boolean result = isEven.test(stringLength.apply(name)); // stringLength -> isEven
System.out.println("Is the length of '" + name + "' even? " + result);
int number = 4;
boolean isValid = isPositive.and(isEven).test(number); // isPositive -> isEven
System.out.println("Is the number " + number + " positive and even? " + isValid);
}
}
Is the length of 'Java' even? true
Is the number 4 positive and even? true
Predicate
, Function
, Consumer
, Supplier
প্রভৃতি আপনাকে অনেক সাধারণ কাজ করতে সাহায্য করে।Java 8 থেকে Date and Time API (যা java.time
প্যাকেজে অন্তর্ভুক্ত) যোগ করা হয়েছে, যা পুরানো java.util.Date
এবং java.util.Calendar
এর চেয়ে অনেক সহজ, সঠিক এবং সুবিধাজনক। এটি LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, এবং Period সহ আরও অনেক ক্লাস প্রদান করে। এই API টির মাধ্যমে আপনি তারিখ এবং সময়ের সাথে কাজ করতে পারবেন অনেক বেশি পরিষ্কারভাবে এবং অনেক কম কোডে।
নিচে কিছু উদাহরণ দেওয়া হলো যেখানে Java 8 এর Date and Time API ব্যবহার করা হয়েছে:
এখানে বর্তমান তারিখ এবং সময় পাওয়ার উদাহরণ:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
public class CurrentDateTimeExample {
public static void main(String[] args) {
// বর্তমান তারিখ
LocalDate currentDate = LocalDate.now();
System.out.println("Current Date: " + currentDate);
// বর্তমান সময়
LocalTime currentTime = LocalTime.now();
System.out.println("Current Time: " + currentTime);
// বর্তমান তারিখ এবং সময়
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("Current Date and Time: " + currentDateTime);
}
}
Output:
Current Date: 2024-12-23
Current Time: 10:30:15.123456
Current Date and Time: 2024-12-23T10:30:15.123456
নির্দিষ্ট তারিখ এবং সময় তৈরি করার উদাহরণ:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
public class SpecificDateTimeExample {
public static void main(String[] args) {
// নির্দিষ্ট তারিখ তৈরি (yyyy-mm-dd)
LocalDate specificDate = LocalDate.of(2024, 12, 25);
System.out.println("Specific Date: " + specificDate);
// নির্দিষ্ট সময় তৈরি (HH:mm:ss)
LocalTime specificTime = LocalTime.of(14, 30, 0);
System.out.println("Specific Time: " + specificTime);
// নির্দিষ্ট তারিখ এবং সময় তৈরি
LocalDateTime specificDateTime = LocalDateTime.of(2024, 12, 25, 14, 30, 0);
System.out.println("Specific Date and Time: " + specificDateTime);
}
}
Output:
Specific Date: 2024-12-25
Specific Time: 14:30:00
Specific Date and Time: 2024-12-25T14:30:00
তারিখ এবং সময় ফরম্যাট করার উদাহরণ:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class FormatDateTimeExample {
public static void main(String[] args) {
// বর্তমান তারিখ
LocalDate currentDate = LocalDate.now();
// একটি নির্দিষ্ট ফরম্যাট তৈরি করা
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
// তারিখ ফরম্যাট করা
String formattedDate = currentDate.format(formatter);
System.out.println("Formatted Date: " + formattedDate);
}
}
Output:
Formatted Date: 23-12-2024
তারিখে দিন, মাস, বা বছর যোগ বা বিয়োগ করার উদাহরণ:
import java.time.LocalDate;
public class AddSubtractDateExample {
public static void main(String[] args) {
LocalDate currentDate = LocalDate.now();
// 5 দিন যোগ করা
LocalDate newDatePlusDays = currentDate.plusDays(5);
System.out.println("Date after 5 days: " + newDatePlusDays);
// 2 মাস বিয়োগ করা
LocalDate newDateMinusMonths = currentDate.minusMonths(2);
System.out.println("Date before 2 months: " + newDateMinusMonths);
// 1 বছর যোগ করা
LocalDate newDatePlusYears = currentDate.plusYears(1);
System.out.println("Date after 1 year: " + newDatePlusYears);
}
}
Output:
Date after 5 days: 2024-12-28
Date before 2 months: 2024-10-23
Date after 1 year: 2025-12-23
দুইটি তারিখের মধ্যে সময়ের পার্থক্য বের করার উদাহরণ:
import java.time.LocalDate;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
public class DurationExample {
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2024, 1, 1);
LocalDate endDate = LocalDate.now();
// তারিখের মধ্যে দিন সংখ্যা বের করা
long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
System.out.println("Days between: " + daysBetween);
// সময়ের মধ্যে Duration বের করা (ঘণ্টায়)
Duration duration = Duration.between(startDate.atStartOfDay(), endDate.atStartOfDay());
System.out.println("Duration in hours: " + duration.toHours());
}
}
Output:
Days between: 358
Duration in hours: 8592
দুইটি তারিখের মধ্যে বছর, মাস, দিন বের করার উদাহরণ:
import java.time.LocalDate;
import java.time.Period;
public class PeriodExample {
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2020, 5, 15);
LocalDate endDate = LocalDate.now();
// তারিখের মধ্যে Period বের করা (বছর, মাস, দিন)
Period period = Period.between(startDate, endDate);
System.out.println("Period: " + period.getYears() + " years, " + period.getMonths() + " months, " + period.getDays() + " days");
}
}
Output:
Period: 4 years, 7 months, 8 days
একটি নির্দিষ্ট টাইমজোনের তারিখ এবং সময় দেখানোর উদাহরণ:
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class ZonedDateTimeExample {
public static void main(String[] args) {
// ZonedDateTime তৈরি (এটা UTC টাইমজোনের সময় দেখাবে)
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
System.out.println("Current UTC Time: " + zonedDateTime);
// একটি নির্দিষ্ট টাইমজোনের ZonedDateTime
ZonedDateTime zonedDateTimeInNY = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("Current Time in New York: " + zonedDateTimeInNY);
}
}
Output:
Current UTC Time: 2024-12-23T15:30:45.123456Z[UTC]
Current Time in New York: 2024-12-23T10:30:45.123456-05:00[America/New_York]
এই উদাহরণগুলির মাধ্যমে আপনি Java 8 এর নতুন Date and Time API ব্যবহার করে বিভিন্ন তারিখ ও সময় সম্পর্কিত কাজ করতে পারবেন।
Read more