জাভা ফাংশনাল প্রোগ্রামিং পর্ব ১

800x400

আমরা যদি ফাংশনাল পদ্ধতিতে প্রোগ্রাম লিখতে চাই তবে আমাদের কোড স্টাইলে কিছু পরিবর্তন আনতে হবে। সাধারনত C++. Java, C#, Python ভাষা গুলোর জন্ম মাল্টি থ্রেড প্রসেসর বের হওয়ার আগের, তাই এসব ভাষা গুলোতে ইম্পারেটিভ ও ওওপি পদ্ধতি সাপোর্ট করত। এখন সব প্রোগ্রামিং ল্যাঙ্গুয়েজে ফাংশনাল পদ্ধতিতে প্রোগ্রাম লেখা যায়। আমরা কিছু কী কনসেপ্ট শিখব যেটি আমাদের ফাংশনাল পদ্ধতিতে প্রোগ্রাম লিখতে সাহায্য করবে।

  1. Be Declarative
  2. Promote immutability
  3. Avoid Side effects
  4. Prefer expressions over statements
  5. Design with higher order functions
  • Be Declarative

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

উদাহরণঃ

boolean found = false;
List<String> cities = new ArrayList<>(Arrays.asList("Cumilla","Sylet","Dhaka"));
for(String city : cities) {
    if(city.equals("Dhaka")) {
        found = true;
        break;
    }
}
System.out.println("Found Dhaka?:" + found);

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

উধাহরনঃ

List<String> cities = new ArrayList<>(Arrays.asList("Cumilla","Sylet","Dhaka"));
System.out.println("Found Dhaka?:" + cities.contains("Dhaka"));
  • Promote immutability

মিউটেবল কোডের অনেক মুভিং পার্ট থাকে। কোডকে অনেক গুলো পার্ট এ বিভক্ত করা যায়, কিন্তু যখন অনেক ভ্যারিয়াবল এর ভ্যালু পরিবর্তন করা হয় তখন কোড বুঝাটা অথবা প্যারালাইজ করা বেশ কঠিন হয়ে পরে। ইমিউটেবিলিটি এই সমস্যা গুলো সমাধান করতে পারে।

জাভা ইমিউটেবিলিটি সাপোর্ট করে তাই প্রোগ্রামারদেরকে যতটা সম্ভব ইমিউটেবল পদ্ধতি তে প্রোগ্রাম লিখতে বলা হয়, কিন্তু কাউকে ইমিউটেবল পদ্ধতিতে প্রোগ্রাম লিখতে বাধ্য করা হয় না । স্যার জসুয়া ব্লচ এর উক্তি “ When declaring variables, fields, and parameters, lean toward declaring them final “

আমরা যখন একটা অবজেক্ট তৈরি করি তখন ইমিউটেবল অবজেক্ট তৈরি করব স্ট্রিং ক্লাসের মত। আমরা যখন collection API নিয়ে কাজ করব তখন immutable, unmodifiable অবজেক্ট তৈরি করব। আমরা মিউটেবল অবজেক্ট এর পরিবর্তে ইমিউটেবল অবজেক্ট তৈরি করাড় মাধ্যমে সাইড ইফেক্ট বিহীন পিওর ফাংশন তৈরি করতে পারি।

  • Avoid Side effects

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

একটি ফাংশন যার কোন সাইড ইফেক্টস নেই এবং যখন ফাংশনটি রান করে তখন কোন ইনপুট ডাটা পরিবর্তন করে না সেই ফাংশনের ভিতরের লজিক বুঝা সহজ, ভুল কম থাকে, লজিক পরিবর্তন করা সহজ। সাইড ইফেক্টস এর অনুপস্থিতি রেস কন্ডিশন থেকে মুক্ত রাখে। ফলাফল খুব সহজে ফাংশনকে প্যারালালাইজ করতে পারি।

উদাহরণঃ

public class SideEffectClass{

    private int state = 0;
    public doSomething(int cm){
        state += cm;
    }
}

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

  • Prefer expressions over statements

স্টেটেমেন্ট কোন একটা ভেরিয়াবল এর ভ্যালু পরিবর্তন করতে বাধ্য করে একে বলে (force mutation)। এক্সপ্রেশন ইমিউটেবিলিটিকে প্রমোট করে। যেমন ইম্পারেটিভ পদ্ধতির যে উধাহরন দিলাম সেখানে লুপ একটা নির্দিষ্ট সময় found ভেরিয়াবল এর ভ্যালু আপডেট করে, এই প্রোগ্রামটি হচ্ছে মিউটেবল স্টেটেমেন্ট এর উদাহরণ। ডিক্লারেটিভ পদ্ধতিতে .contains() মেথড এর মাধ্যমে একটা রেজাল্ট বের করতে পারি, যেটি এক্সপ্রেশন এর উদাহরণ।এভাবে আমরা সহজ ও বোধগম্য ভাষায় প্রোগ্রাম লিখতে পারি।

  • Design with higher order functions

আমরা oop এ মেথড এর ভিতর অবজেক্ট পাঠাতে পারি , আমার মেথড এর ভিতর অবজেক্ট তৈরি করতে পারি এবং মেথড থেকে অবজেক্ট রিটার্ন করি। higher order functions অনেকটা এ ভাবে কাজ করি

১। একটা ফাংশনের ভিতর অন্য একটা ফাংশন পাঠান যায়। ২। ফাংশনের ভিতর অন্য একটা ফাংশন তৈরি করা যায়। ৩। ফাংশন থেকে ফাংশন রিটার্ন করা যায়।

সহজ কথায় কোন একটা function যদি একটা function কে argument হিসেবে নিতে বা return করতে পারে তাকে Higher order function বলে।

উদাহরণঃ

একটা ইন্টারফেস নিলাম IntUnaryFunction যেখানে apply() মেথড আছে।

package com.abdullah.khan;

public interface IntUnaryFunction {
    int apply(int x);
}

TenX ক্লাস IntUnaryFunction ইন্টারফেস কে ইমপ্লিমেন্ট করে।

TenX.java

package com.abdullah.khan;

public class TenX implements IntUnaryFunction{
//it returns 10 times of its argument
    @Override
    public int apply(int x) {
        return 10 * x ;
    }
}

Main.java


package com.abdullah.khan;

public class Main {
    public static int do_twice(IntUnaryFunction f , int x){

        return f.apply(f.apply(x));
    }
    public static void main(String[] args) {
        IntUnaryFunction tenX = new TenX();
        System.out.println(do_twice(tenX, 2));
    }
}

Result 200

Main মেথড থেকে do_twice মেথডে মেথড প্যারামিটার TenX ক্লাসের ইন্সটান্স পাঠাই এবং একটি ভেরিয়াবল পাঠাই। do_twice মেথড এর রিটার্ন স্টেটেমেন্ট লক্ষ করি

return f.apply(f.apply(x));

f.apply(এর ভিতর আবার f.apply(x) কল করা হয়েছে), তার মানে f.apply(x) মেথড দুই বার কল হবে, প্রথম f.apply(x) কল হলে ২০ রিটার্ন করবে তখন স্টেটেমেন্ট অনেকটা return f.apply(20); এই রকম থাকবে, পরবর্তী কলে ফাইনাল ভ্যালু 200 রিটার্ন করবে।

অনেক কিছু লিখে ফেললাম, এখন যাই, পরবর্তী পর্বে দেখব এই কনসেপ্ট গুলো কিভাবে ল্যামডা এক্সপ্রেশনে ব্যবহার করব।

পুর্বে প্রকাশিত