Java তে Exception Handling হাতে কলমে, NullPointerException সহ ৫টি কমন এরর স্ট্যাক ট্রেস পড়ে ঠিক করার সম্পূর্ণ পদ্ধতি

টিউন বিভাগ জাভা
প্রকাশিত

জাভা শেখার শুরুতে সবচেয়ে বেশি হতাশা তৈরি করে কনসোলের লাল রঙের কয়েকটা লাইন। প্রোগ্রাম লিখলেন, রান করলেন, আর ভেসে উঠল Exception in thread main java.lang.NullPointerException। অনেকে এই জায়গায় এসে কোড এলোমেলোভাবে ঘাঁটতে শুরু করেন, কেউ আবার পুরো কোডের চারপাশে try catch বসিয়ে এররটা চোখের আড়াল করে ফেলেন। কিন্তু সমস্যাটা তখনো রয়ে যায়, শুধু আর দেখা যায় না। কিছুদিন পর সেই লুকানো সমস্যাই বড় আকারে ফিরে আসে।

সত্যি বলতে গেলে ওই লাল লেখাগুলোই জাভার সবচেয়ে সাহায্যকারী অংশ। সেখানে হুবহু লেখা থাকে কোন ক্লাসের কোন লাইনে সমস্যা হয়েছে এবং কোন মেথড কাকে ডেকেছিল। এই টিউনে তত্ত্ব মুখস্থ করার বদলে আমরা ইচ্ছা করে পাঁচটি কমন এরর তৈরি করব, প্রতিটির স্ট্যাক ট্রেস লাইন ধরে পড়ব, তারপর কোড ঠিক করব। শেষে জানব try catch finally এবং try with resources এর সঠিক ব্যবহার কোথায়, আর নিজের Custom Exception কীভাবে বানাতে হয়।

যা যা লাগবে

  • কম্পিউটারে JDK 17 বা তার চেয়ে নতুন কোনো ভার্সন ইনস্টল করা থাকতে হবে
  • IntelliJ IDEA Community Edition অথবা VS Code, যেকোনো একটি এডিটর
  • জাভাতে ক্লাস, মেথড ও ভ্যারিয়েবল লেখার প্রাথমিক অভ্যাস
  • প্রতিটি উদাহরণ নিজে হাতে টাইপ করে রান করার ধৈর্য, শুধু পড়ে গেলে শেখা হবে না

Exception আসলে ভেতরে কী ঘটায়

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

Checked ও Unchecked এর পার্থক্য

  • Checked Exception যেমন IOException বা SQLException, কম্পাইলার এগুলো হ্যান্ডেল করতে বাধ্য করে
  • Unchecked Exception যেমন NullPointerException বা ArithmeticException, এগুলো কম্পাইল হয়ে যায় কিন্তু রান করার সময় প্রোগ্রাম ভেঙে দেয়
  • নতুনরা যেসব এররে বেশি আটকান তার প্রায় সবই Unchecked, কারণ কম্পাইলার আগে থেকে কোনো সতর্কবার্তা দেয় না

ধাপ ১: স্ট্যাক ট্রেস পড়ার নিয়ম

নিচের স্ট্যাক ট্রেসটি মন দিয়ে দেখুন। এটি পড়তে হয় উপর থেকে নিচে, আর কাজের তথ্যটুকু থাকে প্রথম দুই লাইনেই।

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null at com.example.ErrorLab.printLength(ErrorLab.java:16) at com.example.ErrorLab.main(ErrorLab.java:6)
  • java.lang.NullPointerException অংশটি বলছে কোন ধরনের সমস্যা হয়েছে
  • কোলনের পরের বাক্যটি জাভা ১৪ এর পর যোগ হওয়া Helpful NullPointerException মেসেজ, এটি সরাসরি জানিয়ে দিচ্ছে name নামের রেফারেন্সটি null
  • ErrorLab.java:16 হলো আসল দুর্ঘটনাস্থল, তাই এডিটরে সবার আগে ১৬ নম্বর লাইনে যেতে হবে
  • এর নিচের লাইনগুলো বলছে কে ওই মেথডকে ডেকেছিল, অর্থাৎ কারণ খুঁজতে এই পথ ধরে উপরে হাঁটতে হবে
  • স্ট্যাক ট্রেসে Caused by লেখা থাকলে সবার নিচের Caused by অংশটিই মূল কারণ, উপরের অংশগুলো তার মোড়ক

ধাপ ২: NullPointerException ধরা ও ঠিক করা

নিচের কোডটি ErrorLab.java নামে সেভ করে রান করুন। এখানে findUser মেথডটি ব্যবহারকারী না পেলে null ফেরত দিচ্ছে, আর সেই null এর উপরেই length মেথড ডাকা হচ্ছে।

public class ErrorLab {public static void main(String[] args) {String name = findUser(101); printLength(name);} static String findUser(int id) {if (id = 100) {return "Nasirul";} return null;} static void printLength(String name) {System.out.println(name.length());}
  • মূল কারণ হলো একটি মেথড null ফেরত দিচ্ছে, অথচ কল করার জায়গায় সেটি যাচাই করা হচ্ছে না
  • সমাধানের সবচেয়ে সহজ উপায় হলো ব্যবহারের আগে যাচাই করে নেওয়া
  • স্ট্রিং তুলনা করার সময় সবসময় জানা মান আগে লিখুন, যেমন "admin".equals(name) লিখলে name null হলেও প্রোগ্রাম ভাঙবে না
  • মেথড থেকে null ফেরত দেওয়ার বদলে Optional ব্যবহার করলে এই সমস্যা গোড়াতেই কমে যায়
 static void printLength(String name) {if (name = null) {System.out.println("ইউজার পাওয়া যায়নি"); return;} System.out.println(name.length());}

ধাপ ৩: ArrayIndexOutOfBoundsException ধরা

অ্যারের ঘর গোনা শুরু হয় শূন্য থেকে, তাই তিন ঘরের অ্যারের সর্বশেষ ইনডেক্স দুই। নিচের লুপে সমান চিহ্ন ব্যবহার করার কারণে প্রোগ্রামটি চার নম্বর ঘরে হাত দিতে চাইছে।

int[] marks = {70, 85, 90};
for (int i = 0; i <= marks.length; i+) {System.out.println(marks[i]);}
  • স্ট্যাক ট্রেসে Index 3 out of bounds for length 3 লেখা থাকবে, সংখ্যা দুটিই আপনাকে ভুলটি দেখিয়ে দিচ্ছে
  • সমাধান হলো শর্তে i < marks.length লেখা, সমান চিহ্ন বাদ দেওয়া
  • ইনডেক্স দরকার না হলে for each লুপ ব্যবহার করুন, তাহলে এই ভুলের সুযোগই থাকে না

ধাপ ৪: NumberFormatException ধরা

ব্যবহারকারীর দেওয়া লেখা সংখ্যায় রূপ দিতে গিয়ে এই এররটি সবচেয়ে বেশি ঘটে। লেখাটির ভেতরে একটি অক্ষর বা ফাঁকা জায়গা থাকলেই parseInt আর কাজ করে না।

String input = "12a";
int value = Integer.parseInt(input);
System.out.println(value);
  • ব্যবহারকারীর ইনপুট সবসময় trim করে নিন, কারণ পেছনের একটি ফাঁকা জায়গাও এররের কারণ হয়
  • রূপান্তরের কাজটি try catch এর ভেতরে রাখুন এবং ভুল হলে ব্যবহারকারীকে বোধগম্য বার্তা দিন
  • ফাইল বা এপিআই থেকে আসা ডেটার ক্ষেত্রে কোন লাইনে সমস্যা হলো তা লগে লিখে রাখুন
try {int value = Integer.parseInt(input.trim()); System.out.println("সংখ্যাটি " + value);} catch (NumberFormatException e) {System.out.println("শুধু সংখ্যা লিখুন, আপনি লিখেছেন " + input);}

ধাপ ৫: ArithmeticException ও ClassCastException

পূর্ণসংখ্যাকে শূন্য দিয়ে ভাগ করলে জাভা ArithmeticException ছোড়ে। মজার বিষয় হলো দশমিক সংখ্যার ক্ষেত্রে এররের বদলে Infinity আসে, তাই গড় হিসাবের কোডে ভুলটি অনেক সময় চোখে পড়ে না।

int total = 250;
int count = 0;
int average = total / count;
  • ভাগ করার আগে ভাজক শূন্য কিনা যাচাই করুন, এটি এক লাইনের কাজ কিন্তু অনেক বড় বিপদ ঠেকায়
  • তালিকা খালি থাকলে গড় শূন্য দেখানো হবে, এই নিয়মটি আগে ঠিক করে নিন

এবার ClassCastException দেখুন। একটি অবজেক্টকে জোর করে ভুল টাইপে রূপ দিতে চাইলে এই এররটি আসে।

Object obj = "Techtunes";
Integer number = (Integer) obj;
  • কাস্ট করার আগে instanceof দিয়ে টাইপ যাচাই করে নিন
  • জাভা ১৬ এর পর থেকে instanceof এর ভেতরেই ভ্যারিয়েবল ঘোষণা করা যায়, ফলে কোড ছোট হয়
if (obj instanceof Integer number) {System.out.println(number + 10);} else {System.out.println("এটি সংখ্যা নয়");}

ধাপ ৬: try catch finally ও try with resources

finally ব্লকের কোড এররে হোক বা না হোক চলবেই, তাই আগে এখানে ফাইল বা ডেটাবেজ বন্ধ করার কাজ লেখা হতো। এখন সেই কাজটি try with resources নিজেই করে দেয়, ফলে বন্ধ করতে ভুলে যাওয়ার ঝুঁকি থাকে না।

try (BufferedReader reader = new BufferedReader(new FileReader("marks.txt"))) {String line = reader.readLine(); System.out.println(line);} catch (IOException e) {System.out.println("ফাইল পড়া যায়নি, কারণ " + e.getMessage());}

যেসব ভুল একদম করবেন না

  • catch ব্লক ফাঁকা রাখা, কারণ এতে সমস্যা লুকিয়ে যায় আর পরে খুঁজে পাওয়া কঠিন হয়
  • catch (Exception e) দিয়ে সব ধরনের সমস্যা একসাথে ধরা, নির্দিষ্ট Exception ধরাই ভালো অভ্যাস
  • e.printStackTrace() লিখে সন্তুষ্ট থাকা, বাস্তব প্রজেক্টে লগার ব্যবহার করুন
  • শুধু লুপ বা শর্ত দিয়ে যাচাই করা সম্ভব এমন জায়গায় try catch ব্যবহার করা

নিজের Custom Exception বানানো

প্রজেক্ট বড় হলে নিজের নিয়ম অনুযায়ী Exception বানালে কোড পড়তে সুবিধা হয়। নিচের উদাহরণে নম্বর যাচাইয়ের জন্য একটি আলাদা Exception তৈরি করা হয়েছে।

class InvalidMarkException extends RuntimeException {public InvalidMarkException(String message) {super(message);}

static void checkMark(int mark) {if (mark < 0 | mark > 100) {throw new InvalidMarkException("নম্বর ০ থেকে ১০০ এর মধ্যে হতে হবে, পাওয়া গেছে " + mark);} System.out.println("নম্বর ঠিক আছে");}

কমন সমস্যা ও সমাধান

স্ট্যাক ট্রেসে আমার ক্লাসের নামই নেই

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

এরর ধরা পড়েছে কিন্তু প্রোগ্রাম আগের মতোই বন্ধ হয়ে যাচ্ছে

catch ব্লকে যে Exception ধরেছেন সেটি হয়তো আসল Exception এর মূল ক্লাস নয়। কনসোলের লেখা নাম হুবহু মিলিয়ে নিন, প্রয়োজনে একই try এর সাথে একাধিক catch ব্লক ব্যবহার করুন।

ডিবাগার দিয়ে কীভাবে জায়গাটি ধরব

এডিটরে ব্রেকপয়েন্ট বসিয়ে ডিবাগ মোডে চালান এবং Variables প্যানেলে দেখুন কোন রেফারেন্সের মান null। IntelliJ IDEA তে Run মেনু থেকে ভিউ প্যানেলে Exception Breakpoint যোগ করলে এরর ঘটার ঠিক মুহূর্তেই প্রোগ্রাম থেমে যায়।

শেষ কথা

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

আপনি জাভা শিখতে গিয়ে কোন এররটিতে সবচেয়ে বেশি সময় নষ্ট করেছেন, টিউমেন্টে জানান। পরের টিউনে আমরা একটি সম্পূর্ণ প্রজেক্ট বানাব যেখানে এই ধরনের সমস্যা হাতে কলমে সমাধান করা হবে।

Level 0

আমি নাছিরুল হক। বিশ্বের সর্ববৃহৎ বিজ্ঞান ও প্রযুক্তির সৌশল নেটওয়ার্ক - টেকটিউনস এ আমি 13 ঘন্টা 33 মিনিট যাবৎ যুক্ত আছি। টেকটিউনস আমি এ পর্যন্ত 6 টি টিউন ও 0 টি টিউমেন্ট করেছি। টেকটিউনসে আমার 0 ফলোয়ার আছে এবং আমি টেকটিউনসে 0 টিউনারকে ফলো করি।


টিউনস


আরও টিউনস


টিউনারের আরও টিউনস


টিউমেন্টস