Generics এবং Functional Programming (Java 8+)

Java Technologies - জাভা জেনেরিক্স (Java Generics)
114
114

Java 8 থেকে ফাংশনাল প্রোগ্রামিং কনসেপ্ট, যেমন Lambda Expressions, Method References, এবং Streams API, প্রবর্তিত হয়েছে। Generics এবং ফাংশনাল প্রোগ্রামিং একত্রে ব্যবহার করলে প্রোগ্রামিং আরও শক্তিশালী এবং টাইপ-সেফ হয়।


Lambda Expressions এবং Generics

Lambda Expressions ফাংশনাল প্রোগ্রামিংয়ের একটি মূল অংশ। এটি একটি ফাংশনকে কোডের অংশ হিসেবে পাস করার সুবিধা দেয়। Generics এর মাধ্যমে Lambda Expressions টাইপ সেফটি নিশ্চিত করে।

উদাহরণ: Generics এর সাথে Lambda Expressions

import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        Function<String, Integer> stringToLength = (String s) -> s.length();
        System.out.println(stringToLength.apply("Generics and Functional Programming"));
    }
}

Explanation:

  • Function<String, Integer> একটি জেনেরিক ইন্টারফেস যা একটি String ইনপুট নেয় এবং একটি Integer রিটার্ন করে।
  • Lambda Expression (String s) -> s.length() টাইপ সেফভাবে কাজ করে।

Generics এবং Functional Interfaces

Java 8-এ অনেকগুলো Functional Interface প্রবর্তিত হয়েছে, যেমন Function, Consumer, Supplier, এবং Predicate। এগুলো জেনেরিক্স ব্যবহার করে টাইপ সেফ প্রোগ্রামিং নিশ্চিত করে।

কিছু গুরুত্বপূর্ণ Functional Interfaces:

Functional InterfaceGeneric DeclarationPurpose
Function<T, R>T (input), R (output)একটি ইনপুট নিয়ে একটি আউটপুট প্রদান করে।
Consumer<T>T (input)একটি ইনপুট গ্রহণ করে, কিছু কাজ করে, কিন্তু কিছু রিটার্ন করে না।
Supplier<T>T (output)কোনো ইনপুট নেয় না, একটি আউটপুট প্রদান করে।
Predicate<T>T (input)একটি ইনপুট গ্রহণ করে, একটি Boolean রিটার্ন করে।

Generics সহ Functional Interfaces এর ব্যবহার

১. Function<T, R> এর ব্যবহার
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        Function<Integer, String> intToString = (Integer i) -> "Number: " + i;
        System.out.println(intToString.apply(10));
    }
}
২. Consumer এর ব্যবহার
import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        Consumer<String> printConsumer = (String s) -> System.out.println(s);
        printConsumer.accept("Hello, Generics and Functional Programming!");
    }
}
৩. Supplier এর ব্যবহার
import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) {
        Supplier<Double> randomSupplier = () -> Math.random();
        System.out.println("Random number: " + randomSupplier.get());
    }
}
৪. Predicate এর ব্যবহার
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        Predicate<Integer> isEven = (Integer i) -> i % 2 == 0;
        System.out.println("Is 10 even? " + isEven.test(10));
    }
}

Streams API এবং Generics

Streams API জাভার ডেটা প্রসেসিংয়ের জন্য একটি শক্তিশালী টুল, এবং এটি Generics এর উপর ভিত্তি করে তৈরি। এটি টাইপ সেফ এবং Declarative Programming কে সমর্থন করে।

Generics সহ Streams API এর ব্যবহার

১. Collection থেকে Stream তৈরি এবং প্রসেসিং
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("John", "Alice", "Bob", "Catherine");

        names.stream()
             .filter(name -> name.startsWith("C"))
             .map(String::toUpperCase)
             .forEach(System.out::println);
    }
}

Explanation:

  • filter একটি Predicate নেয়।
  • map একটি Function নেয়।
  • forEach একটি Consumer নেয়।
২. Custom Generic ক্লাস ব্যবহার
import java.util.Arrays;
import java.util.List;

class Box<T> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

public class Main {
    public static void main(String[] args) {
        List<Box<String>> boxes = Arrays.asList(
            new Box<>("Apple"),
            new Box<>("Banana"),
            new Box<>("Cherry")
        );

        boxes.stream()
             .map(Box::getValue)
             .map(String::toUpperCase)
             .forEach(System.out::println);
    }
}

আউটপুট:

APPLE
BANANA
CHERRY

Method References এবং Generics

Method References Lambda Expressions এর একটি সংক্ষিপ্ত রূপ। এটি Generics এর সাথে টাইপ সেফভাবে কাজ করে।

উদাহরণ:

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("John", "Alice", "Bob");

        // Method Reference: String::toUpperCase
        names.stream()
             .map(String::toUpperCase)
             .forEach(System.out::println);
    }
}

Functional Programming এর সুবিধা Generics এর মাধ্যমে

  1. টাইপ সেফ কোড: Generics এর মাধ্যমে Lambda Expressions এবং Streams টাইপ সেফ থাকে।
  2. পুনঃব্যবহারযোগ্যতা: Generics এবং Functional Interfaces কোডকে আরো পুনঃব্যবহারযোগ্য করে তোলে।
  3. ডিক্লারেটিভ স্টাইল: Streams API Declarative Programming স্টাইলকে সহজ করে।
  4. কোড সংক্ষিপ্তকরণ: Lambda এবং Method References কোডকে সংক্ষিপ্ত এবং পরিষ্কার রাখে।

সীমাবদ্ধতা

  1. Complexity: Generics এবং Functional Programming একত্রে ব্যবহার করলে কোড কিছুটা জটিল হতে পারে।
  2. Debugging: Lambda এবং Streams-এর কারণে ডিবাগিং চ্যালেঞ্জিং হতে পারে।
  3. Runtime Type Information: Generics এর Type Erasure এর কারণে Runtime-এ টাইপ সংক্রান্ত কিছু তথ্য অনুপলব্ধ থাকে।

Java 8+ এর ফাংশনাল প্রোগ্রামিং এবং Generics একত্রে ব্যবহার টাইপ সেফ, সংক্ষিপ্ত, এবং কার্যকর প্রোগ্রাম তৈরি করতে সাহায্য করে। Lambda Expressions, Method References, এবং Streams API জেনেরিক্সের ক্ষমতা বৃদ্ধি করেছে। তবে, এই সুবিধাগুলো ব্যবহারের সময় কোডের জটিলতা এবং Type Erasure সম্পর্কিত সীমাবদ্ধতার ব্যাপারে সচেতন থাকতে হবে।

Content added By

Java 8 এবং তারপরে Functional Programming এর ভূমিকা

72
72

Java 8 এ Functional Programming এর সংযোজন জাভার প্রোগ্রামিং স্টাইলকে একটি নতুন মাত্রা দিয়েছে। Lambda Expressions, Streams API, এবং Functional Interfaces এর মাধ্যমে কোড আরও সংক্ষিপ্ত, রিডেবল এবং কার্যকর হয়েছে। জেনেরিক্স এই নতুন ফিচারগুলির সাথে সামঞ্জস্য রেখে টাইপ সেফটি এবং ফ্লেক্সিবিলিটি প্রদান করে। এখানে Java 8 এবং তারপরে Functional Programming এর বিভিন্ন দিক এবং জেনেরিক্সের ভূমিকা আলোচনা করা হলো।


Lambda Expressions এবং Generics

Lambda Expressions মূলত একটি Functional Interface (যার মধ্যে একটি মাত্র অ্যাবস্ট্রাক্ট মেথড থাকে) ব্যবহার করে কাজ করে। Lambda Expressions জেনেরিক্সের সাথে মিলিয়ে ব্যবহার করলে টাইপ সেফ কোড লেখা যায়।

উদাহরণ: Lambda এবং Generics একত্রে ব্যবহার

import java.util.function.Function;

public class GenericLambdaExample {
    public static void main(String[] args) {
        // Generic Lambda
        Function<String, Integer> stringToLength = str -> str.length();
        System.out.println("Length of 'Java': " + stringToLength.apply("Java"));

        Function<Integer, String> intToString = num -> "Number: " + num;
        System.out.println(intToString.apply(42));
    }
}

আউটপুট:

Length of 'Java': 4
Number: 42

Functional Interfaces এবং Generics

Java 8 এ অনেক বিল্ট-ইন Functional Interfaces এসেছে, যেমন:

  • Predicate: একটি শর্ত চেক করার জন্য।
  • Function<T, R>: একটি মান পরিবর্তন করে অন্য মানে রূপান্তর করার জন্য।
  • Supplier: কোনো মান সরবরাহ করার জন্য।
  • Consumer: কোনো মান গ্রহণ করে প্রক্রিয়াজাত করার জন্য।

উদাহরণ: Generics এর সাথে Functional Interfaces

import java.util.function.Predicate;

public class GenericPredicateExample {
    public static void main(String[] args) {
        Predicate<String> isNotEmpty = str -> str != null && !str.isEmpty();

        System.out.println(isNotEmpty.test("Hello")); // true
        System.out.println(isNotEmpty.test(""));      // false
    }
}

Streams API এবং Generics

Java 8 এর Streams API জেনেরিক টাইপ ব্যবহার করে Collections এর উপর অপারেশন পরিচালনা করে। এটি টাইপ সেফ এবং সহজে ব্যবহারযোগ্য।

উদাহরণ: Streams এবং Generics

import java.util.Arrays;
import java.util.List;

public class StreamGenericExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Dave");

        // Filter and Map using Generics
        names.stream()
             .filter(name -> name.startsWith("A")) // Predicate<String>
             .map(String::toUpperCase)            // Function<String, String>
             .forEach(System.out::println);       // Consumer<String>
    }
}

আউটপুট:

ALICE

Optional এবং Generics

Java 8 এ Optional<T> এসেছে NullPointerException এড়ানোর জন্য। এটি একটি জেনেরিক ক্লাস এবং ফাংশনাল প্রোগ্রামিং স্টাইলে ডেটা ম্যানিপুলেশন করতে ব্যবহৃত হয়।

উদাহরণ: Optional এর সাথে Generics

import java.util.Optional;

public class OptionalGenericExample {
    public static void main(String[] args) {
        Optional<String> optionalName = Optional.of("Java Generics");

        optionalName.ifPresent(System.out::println); // Prints the value if present
    }
}

Custom Functional Interfaces এবং Generics

Java 8 এর আগে যদি জেনেরিক ফাংশনাল ইন্টারফেস তৈরি করতে হতো, তবে এটি ম্যানুয়ালি করতে হতো। তবে, Functional Interfaces এর সংযোজনের পরে এটি আরও সহজ হয়েছে।

উদাহরণ: Custom Functional Interface

@FunctionalInterface
interface GenericFunction<T, R> {
    R apply(T t);
}

public class CustomGenericFunction {
    public static void main(String[] args) {
        GenericFunction<String, Integer> stringToLength = str -> str.length();
        System.out.println("Length: " + stringToLength.apply("Functional Generics"));
    }
}

Parallelism এবং Generics

Java 8 এর parallel streams কোডে সহজে কনকারেন্ট প্রসেসিং চালানোর সুযোগ দেয়, এবং এটি Generics এর সাহায্যে টাইপ সেফ এবং সহজ করে।

উদাহরণ: Parallel Streams

import java.util.Arrays;
import java.util.List;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        numbers.parallelStream()
               .map(num -> num * num) // Function<Integer, Integer>
               .forEach(System.out::println);
    }
}

Collectors এবং Generics

Java 8 এর Collectors API ডেটা সংগ্রহ করতে ব্যবহৃত হয় এবং এটি Generics এর সাহায্যে টাইপ সেফ ভাবে কাজ করে।

উদাহরণ: Collectors ব্যবহার

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Dave");

        // Collect names starting with 'C'
        List<String> result = names.stream()
                                   .filter(name -> name.startsWith("C")) // Predicate<String>
                                   .collect(Collectors.toList());

        System.out.println(result);
    }
}

আউটপুট:

[Charlie]

Java 8 এবং তারপরে Functional Programming এবং Generics এর সংমিশ্রণ জাভার প্রোগ্রামিং শৈলীকে আরও শক্তিশালী করেছে। নিচে এর সুবিধাগুলো উল্লেখ করা হলো:

  1. Lambda Expressions এবং Functional Interfaces:
    • জেনেরিক টাইপ ব্যবহার করে টাইপ সেফ এবং সংক্ষিপ্ত কোড লেখা সম্ভব।
  2. Streams API:
    • Generics এর মাধ্যমে টাইপ সেফ ডেটা প্রসেসিং করা যায়।
  3. Optional:
    • NullPointerException হ্রাস করতে Generics এর সাহায্যে কাজ করে।
  4. Custom Functional Interfaces:
    • জেনেরিক টাইপ ব্যবহার করে রিইউজেবল ফাংশনাল ইন্টারফেস তৈরি করা সহজ।

সঠিকভাবে Generics এবং Functional Programming ব্যবহার করলে টাইপ সেফটি নিশ্চিত হয় এবং কোড আরও রিডেবল, সংক্ষিপ্ত এবং কার্যকর হয়।

Content added By

Lambda Expressions এবং Generics এর Integration

94
94

জাভা ৮ থেকে Lambda Expressions এবং Generics একসঙ্গে ব্যবহার করে আরও কার্যকর এবং সংক্ষিপ্ত কোড লেখা সম্ভব হয়েছে। Lambda Expressions মূলত ফাংশনাল প্রোগ্রামিং ধারণা নিয়ে এসেছে, যা Functional Interfaces এর মাধ্যমে কাজ করে। জেনেরিক্সের সাথে Lambda ব্যবহার করার ফলে টাইপ সেফ এবং পুনঃব্যবহারযোগ্য কোড তৈরি করা যায়।


Lambda Expressions এবং Functional Interface সংক্ষেপে

  • Lambda Expression: এটি একটি কমপ্যাক্ট পদ্ধতি যেখানে একটি ফাংশনকে ইনলাইন পদ্ধতিতে প্রকাশ করা হয়।
    • Syntax:

      (parameters) -> expression
      
  • Functional Interface: একটি ইন্টারফেস যাতে একটি মাত্র অ্যাবস্ট্রাক্ট মেথড থাকে। Lambda Expressions এর মাধ্যমে এই ইন্টারফেসগুলোর বাস্তবায়ন করা হয়।

Lambda এবং Generics এর Integration এর উদাহরণ

১. Comparator Interface এর সাথে Lambda এবং Generics

Lambda এবং জেনেরিক্স ব্যবহার করে তালিকা (List) সাজানো সহজ হয়।

import java.util.*;

public class LambdaWithGenerics {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // Using Lambda Expression for Comparator
        names.sort((s1, s2) -> s1.compareTo(s2));

        System.out.println(names); // [Alice, Bob, Charlie]
    }
}

২. Custom Generic Method এবং Lambda

Lambda ব্যবহার করে জেনেরিক মেথডকে আরও কার্যকর করা যায়।

import java.util.function.Function;

public class GenericLambdaExample {
    public static <T, R> R applyFunction(T input, Function<T, R> function) {
        return function.apply(input);
    }

    public static void main(String[] args) {
        String result = applyFunction(5, x -> "Number: " + (x * 2));
        System.out.println(result); // Number: 10
    }
}

৩. Predicate Interface এর সাথে Lambda এবং Generics

Predicate একটি ফাংশনাল ইন্টারফেস যা একটি ইনপুট নিয়ে বুলিয়ান আউটপুট দেয়। এটি ফিল্টার করার জন্য সাধারণত ব্যবহৃত হয়।

import java.util.*;
import java.util.function.Predicate;

public class GenericPredicateExample {
    public static <T> List<T> filterList(List<T> list, Predicate<T> predicate) {
        List<T> result = new ArrayList<>();
        for (T item : list) {
            if (predicate.test(item)) {
                result.add(item);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // Filter even numbers
        List<Integer> evens = filterList(numbers, x -> x % 2 == 0);

        System.out.println(evens); // [2, 4]
    }
}

৪. Consumer Interface এর সাথে Lambda এবং Generics

Consumer ফাংশনাল ইন্টারফেস একটি ইনপুট গ্রহণ করে এবং কোনো রিটার্ন না দিয়ে কাজ সম্পন্ন করে।

import java.util.*;
import java.util.function.Consumer;

public class GenericConsumerExample {
    public static <T> void processItems(List<T> list, Consumer<T> consumer) {
        for (T item : list) {
            consumer.accept(item);
        }
    }

    public static void main(String[] args) {
        List<String> items = Arrays.asList("Java", "Generics", "Lambda");

        processItems(items, item -> System.out.println(item.toUpperCase()));
    }
}

আউটপুট:

JAVA
GENERICS
LAMBDA

৫. Supplier Interface এর সাথে Lambda এবং Generics

Supplier ফাংশনাল ইন্টারফেস কোনো ইনপুট নেয় না এবং একটি আউটপুট প্রদান করে।

import java.util.function.Supplier;

public class GenericSupplierExample {
    public static <T> T provideItem(Supplier<T> supplier) {
        return supplier.get();
    }

    public static void main(String[] args) {
        String message = provideItem(() -> "Hello, Lambda and Generics!");
        System.out.println(message);
    }
}

Lambda এবং Generics এর Integration এর সুবিধা

  1. কোড সংক্ষিপ্ত: Lambda ব্যবহার করে বয়লারপ্লেট কোড কমানো যায়।
  2. টাইপ সেফটি: Generics টাইপ সেফ কোড নিশ্চিত করে।
  3. পুনঃব্যবহারযোগ্যতা: Generics এবং Lambda একত্রে ব্যবহার করলে মেথড এবং ক্লাস আরও পুনঃব্যবহারযোগ্য হয়।
  4. সহজ পঠনযোগ্যতা: কম কোডে সহজবোধ্য কার্যকারিতা প্রকাশ করা যায়।

Lambda এবং Generics এর সাথে সতর্কতা

  1. Type Erasure: জেনেরিক্সে টাইপ ইনফরমেশন কম্পাইল টাইমে মুছে যায়, যা রানটাইম টাইপ চেকিং কিছুটা জটিল করতে পারে।
  2. উপযুক্ত Functional Interface: Lambda ব্যবহার করার জন্য প্রয়োজনীয় Functional Interface নিশ্চিত করতে হবে।
  3. Wildcard ব্যবহার: জেনেরিক্সের সাথে Wildcards (?) ব্যবহার Lambda এর কার্যকারিতা সীমাবদ্ধ করতে পারে।

Lambda Expressions এবং Generics একত্রে ব্যবহারে জাভা প্রোগ্রামিং আরও সংক্ষিপ্ত, ফ্লেক্সিবল এবং কার্যকর হয়েছে। এটি বড় স্কেল প্রজেক্টে টাইপ সেফটি নিশ্চিত করার পাশাপাশি কার্যকারিতা বাড়িয়ে দেয়। সঠিকভাবে Lambda এবং Generics ব্যবহার করে কোড সহজবোধ্য এবং রিডেবল রাখা সম্ভব।

Content added By

Streams API এবং Generics

84
84

জাভার Streams API এবং Generics একসাথে ব্যবহার করে ডেটা প্রসেসিং আরও শক্তিশালী, ফ্লেক্সিবল এবং টাইপ-সেইফ করা যায়। Generics Streams API-তে টাইপের নিরাপত্তা নিশ্চিত করে এবং ডেটা প্রসেসিংয়ে কম্পাইল-টাইম চেকিং নিশ্চিত করে।


Generics এবং Streams API এর সম্পর্ক

  1. Generics Collections: Streams API সাধারণত জেনেরিক কালেকশন (যেমন List<T>, Set<T>) থেকে স্ট্রিম তৈরি করতে ব্যবহৃত হয়।
  2. Type-Safe Operations: Generics Streams API-তে টাইপ-সেইফ অপারেশন নিশ্চিত করে, ফলে টাইপ-কাস্টিং এর প্রয়োজন হয় না।
  3. Reusable Pipelines: জেনেরিক্সের সাহায্যে Streams API-তে ডেটা প্রসেসিং পাইপলাইন রিইউজেবল করা যায়।

Streams API এবং Generics এর ব্যবহার: উদাহরণ

1. স্ট্রিম তৈরি এবং জেনেরিক প্রসেসিং

import java.util.Arrays;
import java.util.List;

public class GenericStreamExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

        // Stream তৈরি এবং প্রসেসিং
        names.stream()
            .filter(name -> name.startsWith("A"))
            .forEach(System.out::println); // Output: Alice
    }
}

2. জেনেরিক মেথড ব্যবহার করে স্ট্রিম প্রসেসিং

import java.util.List;
import java.util.stream.Collectors;

public class GenericStreamMethod {
    // জেনেরিক মেথড
    public static <T> List<T> filterItems(List<T> items, java.util.function.Predicate<T> predicate) {
        return items.stream()
                .filter(predicate)
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

        // Even সংখ্যা ফিল্টার করা
        List<Integer> evenNumbers = filterItems(numbers, num -> num % 2 == 0);
        System.out.println("Even Numbers: " + evenNumbers); // Output: [2, 4, 6]

        List<String> words = List.of("apple", "banana", "cherry", "date");
        List<String> shortWords = filterItems(words, word -> word.length() <= 5);
        System.out.println("Short Words: " + shortWords); // Output: [apple, banana, cherry, date]
    }
}

3. Map এবং Reduce অপারেশন (Generics সহ)

import java.util.Arrays;
import java.util.List;

public class GenericStreamMapReduce {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // Map এবং Reduce অপারেশন
        int sumOfSquares = numbers.stream()
                                  .map(num -> num * num) // প্রতিটি সংখ্যার স্কোয়ার
                                  .reduce(0, Integer::sum); // সবগুলোর যোগফল

        System.out.println("Sum of Squares: " + sumOfSquares); // Output: 55
    }
}

4. Custom Class এবং Streams API

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return name + ": $" + price;
    }
}

public class GenericStreamWithCustomClass {
    public static void main(String[] args) {
        List<Product> products = Arrays.asList(
            new Product("Laptop", 800.00),
            new Product("Phone", 500.00),
            new Product("Tablet", 300.00),
            new Product("Headphones", 50.00)
        );

        // ফিল্টার করে প্রোডাক্টের নামের তালিকা তৈরি
        List<String> expensiveProductNames = products.stream()
                .filter(product -> product.getPrice() > 300.00)
                .map(Product::getName)
                .collect(Collectors.toList());

        System.out.println("Expensive Products: " + expensiveProductNames);
        // Output: [Laptop, Phone]
    }
}

5. Generics এবং Parallel Streams

import java.util.Arrays;
import java.util.List;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Parallel Stream ব্যবহার
        int sum = numbers.parallelStream()
                         .filter(num -> num % 2 == 0) // Even সংখ্যা ফিল্টার করা
                         .mapToInt(num -> num * 2)   // প্রতিটি সংখ্যা দ্বিগুণ করা
                         .sum();

        System.out.println("Sum of doubled even numbers: " + sum); // Output: 60
    }
}

Generics এবং Streams API এর সুবিধা

  1. Reusable Methods: একবার জেনেরিক মেথড বা ক্লাস লিখে তা বিভিন্ন টাইপের জন্য পুনর্ব্যবহার করা যায়।
  2. Type Safety: টাইপ সম্পর্কিত ভুল এড়ানো যায় কারণ কম্পাইল-টাইম চেকিং নিশ্চিত হয়।
  3. Concise Code: Generics এবং Streams API ব্যবহার করলে কোড আরও সংক্ষিপ্ত ও সহজপাঠ্য হয়।
  4. Parallel Processing: Generics ব্যবহার করেও সহজে প্যারালাল প্রসেসিং সম্ভব।

Generics এবং Streams API একত্রে ব্যবহার করলে জাভার ডেটা প্রসেসিং আরও কার্যকর ও টাইপ-সেইফ হয়। Collections Framework থেকে সহজে স্ট্রিম তৈরি, জেনেরিক মেথডের মাধ্যমে ফ্লেক্সিবল পাইপলাইন তৈরি, এবং জটিল ডেটা প্রক্রিয়া সহজতর করার জন্য Generics অত্যন্ত কার্যকর। সঠিকভাবে Generics এবং Streams API ব্যবহার করলে প্রোগ্রামিং আরও কার্যকর ও রিইউজেবল হয়ে ওঠে।

Content added By

Functional Interfaces এবং Type Parameters

102
102

Functional Interfaces এবং Generics একত্রে ব্যবহার করে কোডের ফ্লেক্সিবিলিটি এবং পুনঃব্যবহারযোগ্যতা বাড়ানো যায়। Functional Interfaces হল এক ধরনের ইন্টারফেস, যেখানে শুধুমাত্র একটি অ্যাবস্ট্রাক্ট মেথড থাকে। Generics এর মাধ্যমে Functional Interfaces টাইপ-অ্যাগনস্টিক করা যায়, যা কোডে টাইপ সেফটি এবং রিডেবিলিটি নিশ্চিত করে।


Functional Interfaces এবং Generics এর সংযোগ

  1. Functional Interfaces:
    • একটি অ্যাবস্ট্রাক্ট মেথড নিয়ে তৈরি ইন্টারফেস।
    • Lambda Expressions বা Method References এর মাধ্যমে সহজে ব্যবহার করা যায়।
  2. Generics:
    • Functional Interfaces কে জেনেরিক টাইপের মাধ্যমে ডাইনামিক ও পুনঃব্যবহারযোগ্য করা যায়।

Common Functional Interfaces (java.util.function):

  • Function<T, R>: একটি ইনপুট নিয়ে একটি আউটপুট প্রদান করে।
  • Predicate<T>: একটি শর্ত যাচাই করে boolean আউটপুট প্রদান করে।
  • Consumer<T>: ইনপুট গ্রহণ করে কিন্তু কিছু রিটার্ন করে না।
  • Supplier<T>: কোনো ইনপুট ছাড়া একটি আউটপুট প্রদান করে।
  • BiFunction<T, U, R>: দুটি ইনপুট নিয়ে একটি আউটপুট প্রদান করে।

Functional Interfaces এবং Generics এর উদাহরণ

1. Custom Generic Functional Interface

@FunctionalInterface
interface Transformer<T, R> {
    R transform(T input);
}

public class Main {
    public static void main(String[] args) {
        // String to Integer Transformer
        Transformer<String, Integer> stringToInteger = Integer::parseInt;
        System.out.println("String to Integer: " + stringToInteger.transform("123"));

        // Integer to Double Transformer
        Transformer<Integer, Double> intToDouble = input -> input * 2.5;
        System.out.println("Integer to Double: " + intToDouble.transform(10));
    }
}

আউটপুট:

String to Integer: 123
Integer to Double: 25.0

উপকারিতা:

  • Generics ব্যবহার করে একাধিক টাইপের জন্য একই Functional Interface ব্যবহার করা যায়।
  • টাইপ সেফটি নিশ্চিত হয়।

2. Using Built-in Functional Interfaces with Generics

import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        // Function to calculate square
        Function<Integer, Integer> square = x -> x * x;
        System.out.println("Square of 5: " + square.apply(5));

        // Function to convert String to Uppercase
        Function<String, String> toUpperCase = String::toUpperCase;
        System.out.println("Uppercase: " + toUpperCase.apply("hello"));
    }
}

আউটপুট:

Square of 5: 25
Uppercase: HELLO

উপকারিতা:

  • Function<T, R> এর মাধ্যমে সহজেই ইনপুট-আউটপুট সম্পর্ক তৈরি করা যায়।
  • Generics ব্যবহার করে ইনপুট এবং আউটপুটের টাইপ ডাইনামিক করা যায়।

3. Predicate Example

import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        // Predicate to check if a number is even
        Predicate<Integer> isEven = x -> x % 2 == 0;
        System.out.println("Is 4 even? " + isEven.test(4));
        System.out.println("Is 7 even? " + isEven.test(7));
    }
}

আউটপুট:

Is 4 even? true
Is 7 even? false

উপকারিতা:

  • শর্ত যাচাইয়ের জন্য Predicates সহজ এবং কার্যকর।
  • Generics ব্যবহার করে যেকোনো টাইপের জন্য Predicate তৈরি করা যায়।

4. Consumer Example

import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        // Consumer to print a value
        Consumer<String> printer = System.out::println;
        printer.accept("Hello, World!");
    }
}

আউটপুট:

Hello, World!

উপকারিতা:

  • Generics ব্যবহার করে যেকোনো টাইপের জন্য Consumer তৈরি করা যায়।
  • কোড রিডেবিলিটি এবং ক্লিন কোড মেইনটেইন করা যায়।

5. Supplier Example

import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) {
        // Supplier to provide a default value
        Supplier<String> defaultMessage = () -> "Default Message";
        System.out.println(defaultMessage.get());
    }
}

আউটপুট:

Default Message

উপকারিতা:

  • Generics ব্যবহার করে যেকোনো টাইপের জন্য ডিফল্ট ভ্যালু সরবরাহ করা যায়।
  • এটি লেট লোডিং প্যাটার্নের জন্য কার্যকর।

Complex Example: Combining Functional Interfaces

import java.util.function.Function;
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        // Predicate to check if a number is positive
        Predicate<Integer> isPositive = x -> x > 0;

        // Function to calculate factorial
        Function<Integer, Integer> factorial = x -> {
            int result = 1;
            for (int i = 1; i <= x; i++) {
                result *= i;
            }
            return result;
        };

        int number = 5;
        if (isPositive.test(number)) {
            System.out.println("Factorial of " + number + ": " + factorial.apply(number));
        } else {
            System.out.println("Number must be positive!");
        }
    }
}

আউটপুট:

Factorial of 5: 120

উপকারিতা:

  • একাধিক Functional Interfaces একত্রিত করে ডাইনামিক লজিক তৈরি করা যায়।
  • কোড সহজে পরিবর্তন এবং পুনঃব্যবহারযোগ্য করা যায়।

Generics এবং Functional Interfaces এর সুবিধা

  1. টাইপ সেফটি: টাইপ সংক্রান্ত ত্রুটি কম্পাইল টাইমে ধরা পড়ে।
  2. কোড রিডেবিলিটি: Lambda Expressions এবং Method References এর মাধ্যমে কোড সংক্ষিপ্ত হয়।
  3. পুনঃব্যবহারযোগ্যতা: একবার তৈরি করা Functional Interface বিভিন্ন টাইপের জন্য ব্যবহার করা যায়।
  4. ডাইনামিক কোডিং: Generics ব্যবহার করে Functional Interfaces আরও ফ্লেক্সিবল হয়।
  5. মেইনটেইনেবিলিটি: Generics এবং Functional Interfaces একত্রে ব্যবহার করে কোড সহজে পরিবর্তনযোগ্য এবং পরিচালনযোগ্য হয়।

Generics এবং Functional Interfaces এর সমন্বয় বড় স্কেলের জাভা প্রজেক্টে টাইপ-সেইফ, পুনঃব্যবহারযোগ্য, এবং মেইনটেইনেবল কোড তৈরি করতে সহায়ক। এটি প্রোগ্রামের মডুলারিটি বাড়ায় এবং জাভার Functional Programming ক্ষমতাকে আরও কার্যকর করে।

Content added By
টপ রেটেড অ্যাপ

স্যাট অ্যাকাডেমী অ্যাপ

আমাদের অল-ইন-ওয়ান মোবাইল অ্যাপের মাধ্যমে সীমাহীন শেখার সুযোগ উপভোগ করুন।

ভিডিও
লাইভ ক্লাস
এক্সাম
ডাউনলোড করুন
Promotion