এই পর্বে যা শিখবেন
- লিখিত উত্তর কোন ক্রমে সাজালে পরীক্ষক সহজে পড়েন — সংজ্ঞা থেকে উপসংহার, আর পার্থক্যের প্রশ্নে টেবিল
- পুরো Java কোর্সের ক্লাসিক তুলনা — JDK/JRE/JVM থেকে PUT/PATCH পর্যন্ত — এক জায়গায়
- খাতায় লেখার মতো ছোট, সম্পূর্ণ প্রোগ্রাম — palindrome থেকে producer–consumer
- ভাইভায় সংজ্ঞা → উদাহরণ → trade-off কাঠামোয় কথা বলা, “জানি না” সৎভাবে সামলানো, আর নিজের প্রজেক্ট গুছিয়ে বলা
- AI-কে ভাইভা পরীক্ষক হিসেবে ব্যবহার করা — আর তার ভুল ধরা
১ · লিখিত পরীক্ষা ও ভাইভা — পরীক্ষক আসলে কী দেখেন
আগের দুই পর্বে আপনি কোড পড়ে আউটপুট বলেছেন আর MCQ অনুশীলন করেছেন। সেখানে উত্তর হয় ঠিক, নয় ভুল। লিখিত পরীক্ষা আর ভাইভা আলাদা। একই তথ্য জানা দুজন প্রার্থীর একজন বেশি নম্বর পান — কারণ তিনি তথ্যটি গুছিয়ে, উদাহরণসহ আর নিজের ভাষায় বলেছেন।
Java-র লিখিত প্রশ্ন সাধারণত চার ধরনের হয়। সংজ্ঞা — “JVM কী?” পার্থক্য — “abstract class আর interface-এর পার্থক্য লিখুন।” ছোট টীকা — “টীকা লিখুন: garbage collection.” আর প্রোগ্রাম — “একটি প্রোগ্রাম লিখুন, যা একটি String palindrome কি না বলে।” Java-তে পার্থক্যের প্রশ্ন অনেক বেশি আসে, কারণ ভাষাটিতে কাছাকাছি দেখতে অনেক জোড়া আছে: == আর equals, throw আর throws, final, finally আর finalize.
যেকোনো লিখিত উত্তর পড়ার সময় একজন পরীক্ষক মনে মনে চারটি জিনিস খোঁজেন:
নির্ভুল সংজ্ঞা
প্রথম এক–দুই বাক্যে মূল কথা। ভুল বা অস্পষ্ট সংজ্ঞা দিয়ে শুরু হলে বাকি উত্তরের ওপর আস্থা কমে যায়।
শুরুবোঝার প্রমাণ
“কীভাবে কাজ করে” আর “কেন এভাবে বানানো” — মুখস্থ সংজ্ঞার বাইরে যা বলবেন, সেটাই বোঝার প্রমাণ।
ব্যাখ্যাছোট সম্পূর্ণ কোড
compile হবে এমন উদাহরণ, নিচে আউটপুট। আধুনিক Java (generics, List.of, record) লিখলে বোঝা যায় আপনি হালনাগাদ।
কখন কোনটি
সীমা, খরচ আর বিকল্প — এই অংশটি সাধারণ উত্তরকে ভালো উত্তরে নেয়।
উপসংহারএই পাতার প্রশ্নগুলো কোর্সের মডিউল অনুযায়ী সাজানো। কোনো অংশে বারবার আটকালে টেবিলের পর্বগুলো আবার পড়ুন:
| কোর্সের মডিউল | পর্ব | লিখিত প্রশ্ন | ভাইভা প্রশ্ন |
|---|---|---|---|
| ১–২ · ভিত্তি ও মূল ভাষা | ০১–১৪ | অংশ ৩ (ক-০১–ক-০৯) | ভ-০১–ভ-১৪ |
| ৩ · অবজেক্ট-ওরিয়েন্টেড Java | ১৫–২২ | অংশ ৪ (খ-০১–খ-০৮) | ভ-১৫–ভ-২৮ |
| ৪ · আধুনিক টাইপ ও ভুল সামলানো | ২৩–২৯ | অংশ ৫ (গ-০১–গ-০৯) | ভ-২৯–ভ-৩৮ |
| ৫ · Collections ও functional Java | ৩০–৩৬ | অংশ ৬ (ঘ-০১–ঘ-০৭) | ভ-৩৯–ভ-৪৮ |
| ৬–৭ · সিস্টেম, JVM ও পেশাদার Java | ৩৭–৫৫ | অংশ ৭ (ঙ-০১–ঙ-১৩) | ভ-৪৯–ভ-৬৮ |
এই পাতার কোনো প্রশ্ন কোনো নির্দিষ্ট পরীক্ষার প্রশ্নপত্র থেকে নেওয়া নয়। এগুলো এমন ধরনের প্রশ্ন, যা বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় প্রায়ই আসে। সিলেবাস, নম্বর বণ্টন আর সময় সবসময় নিজের পরীক্ষার সর্বশেষ বিজ্ঞপ্তি থেকে মিলিয়ে নিন। সব কোড ও আউটপুট ধরে নিয়েছে OpenJDK 21. চালানো যায় এমন প্রোগ্রামে main class-টি public ছাড়া লেখা (অনলাইন runner-এর জন্য); নিজের প্রজেক্টে সাধারণত Main.java ফাইলে public class Main লেখা হয়।
উত্তর সাজানোর কাঠামো তিন কোর্সেই এক — সংজ্ঞা, ব্যাখ্যা, কোড, টেবিল, উপসংহার। পার্থক্য প্রশ্নের বিষয়ে: C++-এ যেখানে destructor আর smart pointer নিয়ে প্রশ্ন, Java-তে সেখানে garbage collection আর try-with-resources; Python-এ যেখানে GIL, Java-তে সেখানে synchronized আর virtual thread. অন্য ভাষার প্রশ্নব্যাংক দেখতে চাইলে C++-এর লিখিত ও ভাইভা বা Python-এর লিখিত ও ভাইভা পর্ব দেখুন।
২ · উত্তরের কাঠামো — সংজ্ঞা, পার্থক্য, টীকা আর প্রোগ্রাম
প্রায় যেকোনো “ব্যাখ্যা করুন” প্রশ্নের জন্য একটি পাঁচ অংশের কাঠামো কাজ করে। একে একটি দালানের মতো ভাবুন — সংজ্ঞা হলো ভিত, ব্যাখ্যা দেয়াল, কোড আর টেবিল জানালা-দরজা, উপসংহার ছাদ।
চার ধরনের প্রশ্নে চার রকম উত্তর
| প্রশ্নের ধরন | যা অবশ্যই থাকবে | সাধারণ ভুল |
|---|---|---|
| সংজ্ঞা (“X কী?”) | এক–দুই বাক্যের সংজ্ঞা, একটি উদাহরণ, কেন দরকার | শুধু পূর্ণ নাম লেখা — “JVM = Java Virtual Machine” |
| পার্থক্য (“X ও Y”) | দুটির এক লাইনের সংজ্ঞা, একই মাপকাঠিতে ৫–৭ সারির টেবিল, দুই পাশের ছোট উদাহরণ, কখন কোনটি | শুধু X নিয়ে লম্বা লেখা, Y প্রায় বাদ; বা মাপকাঠি না মেলানো সারি |
| টীকা (“টীকা লিখুন”) | সংজ্ঞা, ৩–৪টি মূল পয়েন্ট, একটি উদাহরণ বা চিত্র | এক প্যারায় সব কিছু, কোনো পয়েন্ট বা শিরোনাম নেই |
| প্রোগ্রাম (“প্রোগ্রাম লিখুন”) | এক লাইনে পদ্ধতি, সম্পূর্ণ কোড, নমুনা ইনপুট-আউটপুট, edge case | অর্ধেক কোড; কোনো আউটপুট বা ব্যাখ্যা নেই |
সবচেয়ে বেশি আসা ধরন “পার্থক্য লিখুন”। ধরা যাক প্রশ্নটি “ArrayList আর LinkedList-এর পার্থক্য লিখুন” (৫ নম্বর)। নিচের ডায়াগ্রামে “পরে” চাপুন — প্রতিটি ধাপে উত্তরপত্রে একটি নতুন অংশ যোগ হবে।
- দুটি সংজ্ঞাএক লাইন করে
- টেবিলএকই মাপকাঠি
- উদাহরণদুই পাশে
- চিত্রমেমরিতে কেমন
- কখন কোনটিউপসংহার
ArrayList: List interface-এর একটি বাস্তবায়ন, যা ভেতরে
একটি বড়-ছোট হতে পারা array (dynamic array) রাখে।
LinkedList: List ও Deque-এর বাস্তবায়ন, যা ভেতরে
doubly linked list রাখে — প্রতিটি node-এ মান,
আগের node আর পরের node-এর reference.
… (সংজ্ঞা) …
বিষয় ArrayList LinkedList
ভেতরের গঠন dynamic array doubly linked list
get(i) O(1) O(n)
শেষে add amortized O(1) O(1)
শুরুতে/মাঝে add O(n) — সরাতে হয় O(1), যদি node হাতে থাকে
মেমরি কম, পাশাপাশি বেশি (প্রতি node-এ ২টি ref)
অতিরিক্ত ভূমিকা — Deque (addFirst, pollLast)
… (সংজ্ঞা, টেবিল) …
List<String> roll = new ArrayList<>();
roll.add("Ayesha"); roll.add("Karim");
roll.get(1); // O(1): সরাসরি ঘরে যায়
Deque<String> line = new LinkedList<>();
line.addFirst("Rafi"); // O(1): শুধু দুটি link বদলায়
line.pollLast();
… (সংজ্ঞা, টেবিল, উদাহরণ) … ArrayList: [ A | B | C | D | | ] ← পাশাপাশি ঘর LinkedList: null ⇄ A ⇄ B ⇄ C ⇄ D ⇄ null ← ছড়ানো node এক নজরে বোঝা যায় get(i) কেন একটিতে দ্রুত, অন্যটিতে ধীর।
… (সংজ্ঞা, টেবিল, উদাহরণ, চিত্র) …
উপসংহার: সাধারণ তালিকায় ArrayList ডিফল্ট — পাশাপাশি
মেমরি CPU cache-এ ভালো কাজ করে, তাই বাস্তবে মাঝে
যোগেও প্রায়ই দ্রুত। দুই প্রান্তে queue/stack দরকার
হলে ArrayDeque সাধারণত LinkedList-এর চেয়ে ভালো।
সিদ্ধান্ত নিন মেপে, অনুমানে নয়।
- ধাপ ১ — দুটি সংজ্ঞা। পার্থক্যের প্রশ্নেও আগে দুটির সংজ্ঞা দিন, এক লাইন করে। এতে পরীক্ষক দেখেন আপনি দুটিকেই চেনেন। “ভেতরে কী রাখে” কথাটি এখানেই বলুন — পরের সব পার্থক্য এখান থেকেই আসে।
- ধাপ ২ — টেবিল। উত্তরের হৃদয়। প্রতিটি সারি একটি মাপকাঠি, আর দুই কলামে একই মাপকাঠির উত্তর। ৫ নম্বরে ৫–৭ সারিই যথেষ্ট; time complexity-র সারি রাখলে উত্তর অনেক শক্ত হয়।
- ধাপ ৩ — উদাহরণ। দুই পাশেই দুই–তিন লাইনের কোড, মন্তব্যে কেন দ্রুত বা ধীর। লক্ষ করুন, ঘোষণায় বাঁ দিকে interface (
List,Deque) — এটিও ভালো অভ্যাসের প্রমাণ। - ধাপ ৪ — ছোট চিত্র। দুই লাইনের ছবি অনেক বাক্যের কাজ করে। পরীক্ষক এক নজরে দেখেন আপনি মেমরির গঠন বোঝেন।
- ধাপ ৫ — কখন কোনটি। শেষে সিদ্ধান্ত: কোনটি ডিফল্ট, কোথায় অন্যটি, আর একটি বাস্তব সতর্কতা (cache, ArrayDeque). এই অংশটিই বলে আপনি বইয়ের বাইরেও ভেবেছেন। এখন উত্তরটি সম্পূর্ণ।
মোট মিনিটকে মোট নম্বর দিয়ে ভাগ করলে পাবেন প্রতি নম্বরে কত মিনিট। বড় প্রশ্নে সেই সময়ের মোটামুটি এক-পঞ্চমাংশ সংজ্ঞায়, অর্ধেকের মতো টেবিল আর কোডে, বাকিটা উপসংহার ও শেষবার চোখ বোলাতে দিন। নম্বর-ভাগ পরীক্ষকভেদে আলাদা হতে পারে, কিন্তু পাঁচটি অংশ থাকলে কোনো ভাগে বড় ফাঁক থাকে না।
খাতায় Java কোড লেখার ছয় নিয়ম
- সম্পূর্ণ গঠন: দরকারি
import, একটি class আরpublic static void main(String[] args). পুরো প্রোগ্রাম চাইলে কিছু বাদ দেবেন না। - Generics লিখুন:
List<String>, rawListনয়। raw type দেখলে পরীক্ষক বোঝেন আপনি Java 5-এর আগের অভ্যাসে আছেন। - বাঁ দিকে interface:
List<Integer> marks = new ArrayList<>();— নকশার বোঝাপড়া দেখায়। - অর্থবহ নাম ও indentation:
balance,owner—a,bনয়। - আউটপুট লিখুন: কোডের নিচে “আউটপুট: …”. দেখায় আপনি মনে মনে প্রোগ্রামটি চালিয়ে দেখেছেন।
- Edge case এক লাইনে: খালি String,
null, শূন্য বা ঋণাত্মক সংখ্যা — কোডে না রাখলেও নিচে উল্লেখ করুন।
৩ · অংশ ক — ভিত্তি ও মূল ভাষা (মডিউল ১–২)
রিভিশনের জন্য: পর্ব ০১, পর্ব ০৩, পর্ব ০৪, পর্ব ০৫, পর্ব ০৬, পর্ব ০৭, পর্ব ০৮, পর্ব ০৯, পর্ব ১০, পর্ব ১১, পর্ব ১২, পর্ব ১৩, পর্ব ১৪.
প্রতিটি প্রশ্ন পড়ে আগে নিজে খাতায় উত্তর লিখুন, তারপর “→ উত্তর” চেপে মেলান। মডেল উত্তরগুলো সংক্ষিপ্ত কিন্তু সম্পূর্ণ — বড় প্রশ্নে অংশ ২-এর কাঠামো মেনে চিত্র ও কোড যোগ করুন।
ক-০১JDK, JRE আর JVM-এর পার্থক্য লিখুন। (সহজ)
JVM (Java Virtual Machine) হলো সেই প্রোগ্রাম, যা bytecode (.class ফাইল) চালায় — লোড করে, যাচাই করে, interpret বা JIT compile করে, আর মেমরি সামলায়। JRE (Java Runtime Environment) = JVM + standard library — প্রোগ্রাম চালাতে যা লাগে। JDK (Java Development Kit) = JRE-এর সবকিছু + ডেভেলপারের টুল (javac, jar, javadoc, jshell) — প্রোগ্রাম বানাতে যা লাগে।
| বিষয় | JVM | JRE | JDK |
|---|---|---|---|
| কী | bytecode চালানোর ইঞ্জিন | JVM + library | JRE + টুল |
| কার জন্য | সবার (ভেতরে থাকে) | যিনি শুধু চালাবেন | ডেভেলপার |
| compile করা যায়? | না | না | হ্যাঁ — javac |
| platform-নির্ভর? | হ্যাঁ — প্রতি OS-এর আলাদা | হ্যাঁ | হ্যাঁ |
javac Main.java # JDK-এর compiler: Main.java → Main.class (bytecode)
java Main # JVM চালু হয়ে Main.class চালায়উপসংহার: সম্পর্কটি বাক্সের ভেতরে বাক্স: JDK ⊃ JRE ⊃ JVM. Java 11 থেকে Oracle আলাদা JRE ডাউনলোড দেওয়া বন্ধ করেছে; এখন সাধারণত JDK বসানো হয়, আর অ্যাপের সাথে ছোট runtime বানাতে jlink ব্যবহার হয়। ঝামেলার প্রশ্ন “JVM কি platform-independent?” — না; bytecode platform-independent, JVM প্রতিটি OS-এর জন্য আলাদা।
ঝালিয়ে নিন: পর্ব ০৩ · সেটআপ, পর্ব ০৫ · Java কীভাবে চলে
ক-০২Java কেন platform-independent? bytecode, interpreter আর JIT compiler-এর ভূমিকা ব্যাখ্যা করুন। (সহজ)
সংজ্ঞা: Java-র source code সরাসরি কোনো CPU-র machine code-এ নয়, বরং একটি মধ্যবর্তী ভাষা — bytecode — এ compile হয়। যেকোনো OS-এ সেই OS-এর JVM থাকলেই একই .class ফাইল চলে। এটিই “Write Once, Run Anywhere” — Sun Microsystems ১৯৯৫ সালে Java প্রকাশের সময় এই স্লোগান ব্যবহার করে।
- Class loader: দরকার অনুযায়ী
.classফাইল মেমরিতে আনে। - Bytecode verifier: চালানোর আগে যাচাই করে কোডটি নিয়ম ভাঙছে কি না — নিরাপত্তার একটি স্তর।
- Interpreter: শুরুতে bytecode এক এক করে চালায় — দ্রুত শুরু, কিন্তু ধীর গতি।
- JIT compiler: বারবার চলা (“hot”) method-কে চলার সময় native machine code-এ compile করে — তাই দীর্ঘ সময় চলা Java প্রোগ্রাম অনেক দ্রুত হয়।
চিত্র: Main.java → javac → Main.class → (Windows-এর JVM / Linux-এর JVM / macOS-এর JVM) → সেই মেশিনের machine code.
উপসংহার: দাম আছে — JVM-এর শুরু হতে সময় লাগে আর কিছু মেমরি নেয়। এই কারণেই ছোট CLI টুলে বা serverless-এ কখনো কখনো GraalVM native image-এর মতো ahead-of-time compilation ব্যবহার হয়।
ঝালিয়ে নিন: পর্ব ০১ · Java কেন?, পর্ব ০৫ · JVM, bytecode, JIT আর GC
ক-০৩Primitive type আর wrapper class-এর পার্থক্য কী? Autoboxing আর Integer cache ব্যাখ্যা করুন। (মাঝারি)
Java-তে ৮টি primitive type — byte, short, int, long, float, double, char, boolean. এগুলো সরাসরি মান রাখে, object নয়। প্রতিটির একটি wrapper class আছে — Integer, Double, Character ইত্যাদি — যা মানটিকে একটি object-এ মোড়ে।
| বিষয় | Primitive (int) | Wrapper (Integer) |
|---|---|---|
| কী রাখে | সরাসরি মান | object-এর reference |
null হতে পারে? | না (field-এর ডিফল্ট 0) | হ্যাঁ (field-এর ডিফল্ট null) |
| Collection-এ রাখা | যায় না — List<int> অবৈধ | যায় — List<Integer> |
| তুলনা | == মান তুলনা করে | == reference তুলনা করে; মানের জন্য equals |
| খরচ | কম মেমরি, দ্রুত | object header-সহ বেশি মেমরি |
Autoboxing (Java 5 থেকে): compiler নিজে int → Integer রূপান্তর বসায় (Integer.valueOf); উল্টোটা unboxing (intValue())। ফাঁদ: null wrapper unbox করলে NullPointerException.
Integer cache: Integer.valueOf −128 থেকে 127 পর্যন্ত মানের জন্য আগে থেকে বানানো একই object ফেরত দেয়। তাই Integer a = 127, b = 127; হলে a == b হলো true, কিন্তু 128-এ false (ডিফল্ট সেটিংসে; ওপরের সীমা JVM option দিয়ে বাড়ানো যায়)। শিক্ষা: wrapper-এ কখনো == নয়, equals.
ঝালিয়ে নিন: পর্ব ০৬ · primitive, wrapper আর var
ক-০৪String, StringBuilder আর StringBuffer-এর পার্থক্য লিখুন। String immutable কেন? (সহজ)
String একটি immutable class — একবার তৈরি হলে তার অক্ষর আর বদলায় না; concat, toUpperCase সবাই নতুন String ফেরত দেয়। StringBuilder (Java 5) আর StringBuffer (Java 1.0) দুটিই mutable — একই object-এর ভেতরের buffer বদলায়।
| বিষয় | String | StringBuilder | StringBuffer |
|---|---|---|---|
| বদলানো যায়? | না | হ্যাঁ | হ্যাঁ |
| Thread-safe? | হ্যাঁ (immutable বলে) | না | হ্যাঁ — method-গুলো synchronized |
| গতি (বারবার জোড়ায়) | ধীর — প্রতিবার নতুন object | দ্রুত | StringBuilder-এর চেয়ে কিছুটা ধীর |
| String pool | literal pool-এ থাকে | না | না |
| কখন | সাধারণ লেখা, map-এর key | লুপে জোড়া — ডিফল্ট | পুরোনো কোড; এক object বহু thread-এ (বিরল) |
String immutable কেন: (১) String pool — একই literal বহু জায়গায় ভাগ করা নিরাপদ হয়; (২) নিরাপত্তা — ফাইলের পথ বা URL যাচাইয়ের পর কেউ বদলাতে পারে না; (৩) hashCode একবার হিসাব করে রাখা যায়, তাই HashMap-এর key হিসেবে ভালো; (৪) thread-এর মধ্যে ভাগ করতে কোনো lock লাগে না।
উপসংহার: লুপে s += x লিখলে প্রতিবার নতুন String তৈরি হয় — n বার জুড়লে মোট কাজ O(n²)-এর দিকে যায়। লুপে StringBuilder ব্যবহার করুন। এক লাইনের "a" + b + "c" নিয়ে চিন্তার কিছু নেই — compiler নিজেই দক্ষ কোড বানায়।
ঝালিয়ে নিন: পর্ব ০৮ · String, StringBuilder আর immutability
ক-০৫Java কি pass-by-value, নাকি pass-by-reference? উদাহরণসহ ব্যাখ্যা করুন। (মাঝারি)
উত্তর: Java সবসময় pass-by-value. method ডাকার সময় argument-এর মানের কপি যায়। primitive-এর ক্ষেত্রে মানটি সংখ্যা; object-এর ক্ষেত্রে মানটি একটি reference (ঠিকানার মতো কিছু)। তাই reference-এর কপি দিয়ে object-এর ভেতর বদলানো যায়, কিন্তু ডাকার জায়গার ভ্যারিয়েবলকে নতুন object-এ পাঠানো যায় না।
static void addBonus(int salary) { salary += 500; } // কপি বদলাল
static void addItem(List<String> cart) { cart.add("tea"); } // একই object বদলাল
static void replace(List<String> cart) { cart = new ArrayList<>(); } // শুধু কপি নতুন দিকে
int s = 1000; addBonus(s); // s এখনো 1000
List<String> c = new ArrayList<>();
addItem(c); // c = [tea]
replace(c); // c এখনো [tea]চিত্র: c ──► [ArrayList object] আর method-এর cart ──► [একই object]. cart = new … করলে শুধু cart-এর তীর ঘোরে, c-এর নয়।
উপসংহার: C++-এর int&-এর মতো আসল pass-by-reference Java-তে নেই। দুটি মান “swap” করার method তাই Java-তে লেখা যায় না; দরকার হলে array বা object-এর ভেতরের field বদলাতে হয়। ভাইভায় এক বাক্যে: “Java pass-by-value; object-এর ক্ষেত্রে reference-টি value হিসেবে যায়।”
ঝালিয়ে নিন: পর্ব ১২ · method — overloading, varargs আর pass-by-value
ক-০৬একটি প্রোগ্রাম লিখুন, যা বলবে একটি String palindrome কি না (বড়-ছোট হাতের অক্ষর আর বিরামচিহ্ন বাদ দিয়ে)। (সহজ)
পদ্ধতি: palindrome মানে সামনে-পেছনে একই। দুটি সূচক — একটি শুরু থেকে, একটি শেষ থেকে — ভেতরের দিকে আসবে (two-pointer). অক্ষর বা অঙ্ক নয় এমন কিছু এড়িয়ে যাবে, আর তুলনা করবে ছোট হাতের রূপে। নতুন String বানাতে হয় না, তাই মেমরি O(1), সময় O(n).
class Main {
static boolean isPalindrome(String s) {
int i = 0, j = s.length() - 1;
while (i < j) {
char a = s.charAt(i), b = s.charAt(j);
if (!Character.isLetterOrDigit(a)) { i++; continue; }
if (!Character.isLetterOrDigit(b)) { j--; continue; }
if (Character.toLowerCase(a) != Character.toLowerCase(b)) return false;
i++;
j--;
}
return true;
}
public static void main(String[] args) {
String[] tests = {"madam", "Was it a car or a cat I saw?", "Java", "", "12321"};
for (String t : tests) {
System.out.println("\"" + t + "\" -> " + isPalindrome(t));
}
}
}আউটপুট: "madam" -> true, "Was it a car or a cat I saw?" -> true, "Java" -> false, "" -> true, "12321" -> true. দ্বিতীয় বাক্যে ফাঁকা জায়গা আর ? এড়িয়ে যাওয়া হয়েছে, আর W/w একই ধরা হয়েছে। খালি String-এ লুপ একবারও চলে না, তাই true — খাতায় এই edge case এক লাইনে উল্লেখ করুন। সহজ বিকল্প new StringBuilder(t).reverse().toString().equals(t), কিন্তু তাতে বাড়তি String তৈরি হয় আর বিরামচিহ্ন বাদ যায় না।
ঝালিয়ে নিন: পর্ব ০৮ · String, পর্ব ১১ · লুপ
ক-০৭একটি বাক্যের শব্দগুলো উল্টো ক্রমে সাজানোর প্রোগ্রাম লিখুন (“Java is fun” → “fun is Java”). অতিরিক্ত ফাঁকা জায়গা সামলাবেন। (সহজ)
পদ্ধতি: দুই প্রান্তের ফাঁকা trim() দিয়ে বাদ, তারপর split("\\s+") — এক বা একাধিক whitespace দিয়ে ভাগ। এরপর শেষ থেকে শুরুর দিকে শব্দ জুড়ুন। লাইব্রেরি দিয়েও দেখানো হলো — খাতায় দুটি পদ্ধতি দিলে পরীক্ষক দেখেন আপনি দুই স্তরেই ভাবতে পারেন।
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
class Main {
// পদ্ধতি ১: হাতে লুপ, StringBuilder দিয়ে জোড়া
static String reverseWords(String s) {
String[] words = s.trim().split("\\s+");
StringBuilder sb = new StringBuilder();
for (int i = words.length - 1; i >= 0; i--) {
sb.append(words[i]);
if (i > 0) sb.append(' ');
}
return sb.toString();
}
// পদ্ধতি ২: লাইব্রেরি দিয়ে
static String reverseWordsLib(String s) {
List<String> words = new ArrayList<>(Arrays.asList(s.trim().split("\\s+")));
Collections.reverse(words);
return String.join(" ", words);
}
public static void main(String[] args) {
String input = " Java is fun to learn ";
System.out.println("[" + reverseWords(input) + "]");
System.out.println("[" + reverseWordsLib(input) + "]");
System.out.println("[" + reverseWords("") + "]");
}
}আউটপুট: [learn to fun is Java] দুবার, তারপর []. বন্ধনী দিয়ে ছাপানো হয়েছে যাতে দেখা যায় শুরু-শেষে কোনো বাড়তি ফাঁকা নেই। খালি String-এ split একটি খালি উপাদানের array দেয়, তাই ফল খালি। পদ্ধতি ২-এ Arrays.asList-কে new ArrayList<>(…)-এ মোড়ানো হয়েছে, কারণ Arrays.asList-এর তালিকার মাপ বদলানো যায় না — যদিও reverse শুধু জায়গা বদলায়, তাই এখানে মোড়ানো ছাড়াও চলত। দুটি পদ্ধতিই O(n).
ঝালিয়ে নিন: পর্ব ০৮ · String, পর্ব ১৩ · array
ক-০৮Fibonacci সংখ্যা বের করার প্রোগ্রাম লিখুন — iterative আর memoization দুইভাবে। সাধারণ recursion কেন ধীর? (মাঝারি)
পদ্ধতি: F(0) = 0, F(1) = 1, F(n) = F(n−1) + F(n−2). সরাসরি recursion একই মান বারবার হিসাব করে — F(n−2) দুই শাখাতেই আসে — তাই ডাকের সংখ্যা সূচকীয় হারে বাড়ে। Iterative সমাধান শুধু শেষ দুটি মান মনে রাখে: O(n) সময়, O(1) মেমরি। Memoization recursion রেখেই প্রতিটি ফল একবার হিসাব করে map-এ রাখে: O(n) সময়, O(n) মেমরি।
import java.util.HashMap;
import java.util.Map;
class Main {
static long fibIter(int n) { // O(n) সময়, O(1) মেমরি
long a = 0, b = 1;
for (int i = 0; i < n; i++) {
long next = a + b;
a = b;
b = next;
}
return a;
}
static final Map<Integer, Long> memo = new HashMap<>();
static long fibMemo(int n) { // O(n) সময়, O(n) মেমরি
if (n < 2) return n;
Long cached = memo.get(n);
if (cached != null) return cached;
long value = fibMemo(n - 1) + fibMemo(n - 2);
memo.put(n, value);
return value;
}
static int calls = 0;
static long fibNaive(int n) { calls++; return n < 2 ? n : fibNaive(n - 1) + fibNaive(n - 2); }
public static void main(String[] args) {
for (int i = 0; i <= 10; i++) System.out.print(fibIter(i) + " ");
System.out.println();
System.out.println("fib(50): " + fibIter(50) + " = " + fibMemo(50));
System.out.println("naive fib(25) = " + fibNaive(25) + ", calls = " + calls);
}
}আউটপুট: 0 1 1 2 3 5 8 13 21 34 55, fib(50): 12586269025 = 12586269025, naive fib(25) = 75025, calls = 242785. মাত্র ২৫-এর জন্য সাধারণ recursion আড়াই লাখের মতো ডাক দিয়েছে; memo বা লুপে লাগে মাত্র কয়েক ডজন ধাপ। F(50) int-এ ধরে না, তাই long; F(92)-এর পরে, অর্থাৎ F(93)-এ long-ও overflow করে — তখন BigInteger. একটি সূক্ষ্ম কথা: memo-তে computeIfAbsent-এর ভেতর থেকে আবার একই map বদলানো recursion লিখলে Java 9 থেকে HashMap ConcurrentModificationException ছুড়তে পারে — তাই এখানে সরল get/put.
ঝালিয়ে নিন: পর্ব ১২ · method, পর্ব ৫৪ · অ্যালগরিদম ও কনটেস্টে Java
ক-০৯Java-তে String.matches(), Matcher.find() আর lookingAt()-এর পার্থক্য লিখুন। বাংলাদেশি মোবাইল নম্বর যাচাইয়ের একটি regex লিখে ব্যাখ্যা করুন, আর বলুন Java-তে backslash কেন দুবার লিখতে হয়। (মাঝারি)
Regular expression হলো লেখার আকৃতি বর্ণনার একটি ছোট ভাষা। Java-তে এর দুটি মূল class: Pattern — একবার compile করা নকশা (immutable, thread-safe), আর Matcher — একটি লেখার ওপর একটি খোঁজা (thread-safe নয়)।
| Method | কী দেখে | \d+ দিয়ে “abc123” |
|---|---|---|
matches() | পুরো লেখা নকশার সাথে মেলে কি না | false |
lookingAt() | লেখার শুরু থেকে নকশা মেলে কি না | false |
find() | লেখার যেকোনো জায়গায় পরের মিল আছে কি না; বারবার ডাকলে পরের মিল | true (“123”) |
static final Pattern BD_MOBILE = Pattern.compile("(?:\\+?880|0)1[3-9]\\d{8}");
static boolean isMobile(String s) {
return s != null && BD_MOBILE.matcher(s).matches(); // যাচাইয়ে matches(), find() নয়
}
// "01712345678" → true, "+8801712345678" → true, "01212345678" → falseনকশার ব্যাখ্যা: (?:\+?880|0) — শুরুতে +880, 880 অথবা 0 (non-capturing group); তারপর 1; [3-9] — অপারেটরের অঙ্ক ৩ থেকে ৯; শেষে \d{8} — ঠিক আটটি অঙ্ক। matches() পুরো লেখা চায়, তাই আলাদা ^/$ লাগেনি; find() দিলে “আমার নম্বর 01712345678” পুরো বাক্যটিও পাস করত।
backslash দুবার কেন: অনুবাদ হয় দুই স্তরে। Java compiler আগে string literal পড়ে — সেখানে \ নিজেই escape শুরু করে, আর \d নামে কোনো Java escape নেই, তাই "\d" লিখলে compile error “illegal escape character”. "\\d" লিখলে মেমরিতে থাকে দুই অক্ষর \d, যা regex engine পড়ে “একটি অঙ্ক” হিসেবে। text block-এও একই নিয়ম; Java-তে raw string নেই।
উপসংহার: যাচাইয়ে matches(), তথ্য তুলতে while (m.find()) আর group(); নকশা static final Pattern. মনে রাখুন, \d আর \w ডিফল্টে শুধু ASCII — বাংলা অঙ্ক ধরতে UNICODE_CHARACTER_CLASS লাগে।
ঝালিয়ে নিন: পর্ব ১৪ · regular expression, পর্ব ০৮ · String
৪ · অংশ খ — অবজেক্ট-ওরিয়েন্টেড Java (মডিউল ৩)
রিভিশনের জন্য: পর্ব ০২, পর্ব ১৫, পর্ব ১৬, পর্ব ১৭, পর্ব ১৮, পর্ব ১৯, পর্ব ২০, পর্ব ২১, পর্ব ২২.
Java-র লিখিত পরীক্ষায় সবচেয়ে বেশি প্রশ্ন আসে এই অংশ থেকে। “পার্থক্য লিখুন” প্রশ্নে টেবিল ব্যবহার করুন — একই মাপকাঠিতে সারি, নিচে একটি ছোট উদাহরণ।
খ-০১OOP-এর চারটি স্তম্ভ কী? প্রতিটি Java উদাহরণসহ ব্যাখ্যা করুন। (সহজ)
সংজ্ঞা: Object-oriented programming হলো প্রোগ্রামকে object দিয়ে সাজানো — প্রতিটি object নিজের ডেটা (field) আর সেই ডেটার ওপর কাজ (method) একসাথে রাখে। এর চারটি স্তম্ভ:
- Encapsulation: ডেটা
privateরেখে শুধু নিয়ন্ত্রিত method দিয়ে বদলাতে দেওয়া।class Account { private long balance; void deposit(long t) { if (t <= 0) throw …; balance += t; } }— বাইরে থেকে কেউ balance ঋণাত্মক করতে পারে না। - Abstraction: ভেতরের জটিলতা লুকিয়ে সহজ চেহারা দেওয়া।
list.add(x)ডাকলেই হয় — array বড় করা বা node জোড়া নিয়ে ভাবতে হয় না। interface আর abstract class এর প্রধান হাতিয়ার। - Inheritance: একটি class আরেকটির field ও method নিয়ে নতুন class বানানো — “is-a” সম্পর্ক।
class SavingsAccount extends Account { } - Polymorphism: একই ডাক, ভিন্ন কাজ। Compile-time — method overloading; run-time — overriding:
Payment p = new Bkash(); p.fee(500);চালায়Bkash-এর নিয়ম।
উপসংহার: চারটি স্তম্ভ উপায়, লক্ষ্য নয়। লক্ষ্য হলো এমন কোড, যা বদলানো সহজ — নতুন পেমেন্ট পদ্ধতি (Nagad) যোগ করতে পুরোনো কোড না ভেঙে শুধু একটি নতুন class লেখা। “চারটি স্তম্ভ” কথাটি পড়ানোর সুবিধার জন্য প্রচলিত একটি ভাগ; কিছু বইয়ে abstraction-কে আলাদা ধরা হয় না।
ঝালিয়ে নিন: পর্ব ০২ · object দিয়ে ভাবা, পর্ব ১৭, পর্ব ২০
খ-০২Class আর object-এর পার্থক্য কী? Constructor আর সাধারণ method কীভাবে আলাদা? (সহজ)
Class হলো নকশা — কোন কোন field আর method থাকবে তার বর্ণনা। Object হলো সেই নকশা থেকে new দিয়ে heap-এ বানানো একটি আসল নমুনা, যার নিজের field-এর মান আছে। একটি “Student” class থেকে হাজার জন ছাত্রের object.
| বিষয় | Constructor | Method |
|---|---|---|
| নাম | class-এর নামেই | যেকোনো নাম |
| Return type | নেই, void-ও না | থাকতেই হবে (void হতে পারে) |
| কখন চলে | new করার সময়, একবার | যখনই ডাকা হয় |
| Inherit হয়? | না (তবে super(…) দিয়ে ডাকা যায়) | হ্যাঁ |
| না লিখলে | কোনো constructor না থাকলে compiler একটি default constructor দেয় | কিছু দেয় না |
উপসংহার: একটি constructor-ও নিজে লিখলে default constructor আর আপনাআপনি তৈরি হয় না — তখন new Student() compile error. একই class-এর একটি constructor থেকে আরেকটি ডাকতে this(…), আর সেটি অবশ্যই প্রথম লাইনে।
ঝালিয়ে নিন: পর্ব ১৫ · class ও object, পর্ব ১৬ · constructor আর this
খ-০৩Java-র চারটি access level ব্যাখ্যা করুন। কোনটি কোথা থেকে দেখা যায়, টেবিলে দেখান। (সহজ)
Access modifier ঠিক করে একটি class, field বা method কোথা থেকে ব্যবহার করা যাবে। শব্দ তিনটি (private, protected, public), আর কিছু না লিখলে চতুর্থটি — package-private.
| Modifier | একই class | একই package | অন্য package-এর subclass | সবখানে |
|---|---|---|---|---|
private | ✓ | ✗ | ✗ | ✗ |
| (কিছু না) package-private | ✓ | ✓ | ✗ | ✗ |
protected | ✓ | ✓ | ✓ (inheritance-এর মাধ্যমে) | ✗ |
public | ✓ | ✓ | ✓ | ✓ |
উপসংহার: নিয়ম — যতটা সম্ভব কম খোলা (least privilege). field প্রায় সবসময় private; বাইরের দরকারি কাজ public method-এ। top-level class শুধু public বা package-private হতে পারে। ফাঁদের প্রশ্ন: “protected কি শুধু subclass-এর জন্য?” — না, একই package-এর সব class-ও দেখে।
ঝালিয়ে নিন: পর্ব ১৭ · encapsulation আর access modifier
খ-০৪static keyword কী করে? final, finally আর finalize-এর পার্থক্য লিখুন। (মাঝারি)
static মানে “class-এর, কোনো একটি object-এর নয়”। static field-এর পুরো প্রোগ্রামে একটিই কপি (সব object ভাগ করে); static method object ছাড়াই ClassName.method() দিয়ে ডাকা যায়, আর তার ভেতরে this নেই — তাই সরাসরি instance field ছোঁয়া যায় না। main static, কারণ JVM কোনো object বানানোর আগেই তাকে ডাকে।
নাম কাছাকাছি হলেও নিচের তিনটি সম্পূর্ণ আলাদা জিনিস:
| বিষয় | final | finally | finalize() |
|---|---|---|---|
| কী | keyword (modifier) | try-এর সাথে একটি block | Object-এর একটি method |
| কাজ | ভ্যারিয়েবল আর বদলানো যাবে না; method override করা যাবে না; class extend করা যাবে না | exception হোক বা না হোক, প্রায় সবসময় চলে — পরিষ্কারের কাজ | GC object সরানোর আগে হয়তো ডাকত |
| অবস্থা | নিয়মিত ব্যবহৃত | নিয়মিত; তবে রিসোর্সে try-with-resources ভালো | Java 9-এ deprecated, Java 18-এ (JEP 421) সরিয়ে ফেলার জন্য চিহ্নিত |
| উদাহরণ | final double VAT = 0.15; | try { … } finally { lock.unlock(); } | ব্যবহার করবেন না; বিকল্প Cleaner বা AutoCloseable |
উপসংহার: final reference মানে reference বদলাবে না, object-এর ভেতর নয় — final List<String> xs-এ xs.add(…) চলে। finally চলে না শুধু চরম ক্ষেত্রে, যেমন System.exit() বা JVM নিজেই বন্ধ হয়ে গেলে। finalize কখন চলবে, আদৌ চলবে কি না — কোনো নিশ্চয়তা ছিল না; সেটাই তার বাদ পড়ার কারণ।
ঝালিয়ে নিন: পর্ব ১৮ · static আর final, পর্ব ১৬, পর্ব ২৯
খ-০৫Method overloading আর method overriding-এর পার্থক্য লিখুন। (সহজ)
| বিষয় | Overloading | Overriding |
|---|---|---|
| সংজ্ঞা | একই class-এ একই নামের একাধিক method, parameter আলাদা | subclass superclass-এর method একই signature-এ নতুন করে লেখে |
| কোথায় | একই class (বা inherit করা method-এর সাথে) | দুটি class — parent ও child |
| Signature | parameter-এর সংখ্যা, টাইপ বা ক্রম আলাদা হতেই হবে; শুধু return type আলাদা হলে চলে না | হুবহু এক; return type একই বা তার subtype (covariant return) |
| সিদ্ধান্ত কখন | compile-এর সময় — static polymorphism | চলার সময়, object-এর আসল টাইপ দেখে — dynamic dispatch |
| Access | যেকোনো | কমানো যাবে না (public-কে protected করা যাবে না) |
| Checked exception | যেকোনো | নতুন বা বড় checked exception ছোড়া যাবে না |
| static / private / final | overload করা যায় | override হয় না (static হলে method hiding) |
int area(int side) { return side * side; } // overloading
double area(double w, double h) { return w * h; }
class Payment { long fee(long amount) { return 0; } }
class Bkash extends Payment {
@Override long fee(long amount) { return amount * 185 / 10_000; } // overriding
}উপসংহার: override করার সময় সবসময় @Override লিখুন — নাম বা parameter-এ টাইপো হলে compiler ধরবে; না লিখলে ভুলটি নীরবে একটি নতুন overload হয়ে যায়।
ঝালিয়ে নিন: পর্ব ১২ · overloading, পর্ব ২০ · polymorphism আর dynamic dispatch
খ-০৬Abstract class আর interface-এর পার্থক্য লিখুন। Java 8-এর পর পার্থক্য কতটা কমেছে? (মাঝারি)
Abstract class হলো abstract চিহ্নিত class, যার object বানানো যায় না; তাতে abstract method (শরীর নেই) আর সাধারণ method, field, constructor — সবই থাকতে পারে। Interface হলো একটি চুক্তি — কোন কোন method থাকতে হবে তার তালিকা; class implements করে সেই চুক্তি পূরণ করে।
| বিষয় | Abstract class | Interface |
|---|---|---|
| কয়টি নেওয়া যায় | একটি (extends) | অনেকগুলো (implements A, B) |
| Field | যেকোনো — instance state রাখা যায় | শুধু public static final constant |
| Constructor | থাকে | নেই |
| Method | abstract ও সাধারণ, যেকোনো access | abstract; Java 8 থেকে default ও static; Java 9 থেকে private |
| সম্পর্ক | “is-a” — একই পরিবারের সাধারণ কোড | “can-do” — সক্ষমতা (Comparable, Runnable) |
| Lambda | না | একটি মাত্র abstract method থাকলে (functional interface) হ্যাঁ |
interface Payable { long fee(long amount); } // চুক্তি
abstract class Shape { // আংশিক নকশা
private final String name; // state
Shape(String name) { this.name = name; } // constructor
abstract double area(); // subclass লিখবে
String describe() { return name + ": " + area(); } // ভাগের কোড
}উপসংহার: Java 8-এর default method-এর পর interface-এও কোড থাকে, কিন্তু মূল পার্থক্য রয়ে গেছে — interface-এ instance state আর constructor নেই। প্রচলিত পরামর্শ: চুক্তির জন্য আগে interface; একই পরিবারের class-গুলোর মধ্যে state ও কোড ভাগ করতে হলে abstract class (প্রায়ই interface-এর একটি আংশিক বাস্তবায়ন হিসেবে, যেমন AbstractList).
ঝালিয়ে নিন: পর্ব ২১ · abstract class আর interface
খ-০৭Java-তে class-এর multiple inheritance নেই কেন? Interface-এর default method-এ একই সমস্যা হলে কী করতে হয়? (মাঝারি)
কারণ — diamond problem: B আর C দুটিই A থেকে এসেছে আর দুজনেই hello() override করেছে। D যদি B ও C দুটিকেই extend করত, d.hello() কোনটি চালাবে? আর A-র field কি দুই কপি থাকবে? C++ এর জন্য virtual inheritance-এর মতো জটিল নিয়ম রাখে। Java-র নকশাকারেরা ভাষা সরল রাখতে class-এ একটিমাত্র parent রেখেছেন (single inheritance), কিন্তু interface অনেকগুলো নেওয়া যায় — কারণ পুরোনো interface-এ state বা কোড ছিল না।
Java 8-এর পর: দুটি interface-এ একই default method থাকলে compiler বাধ্য করে class-টিকে নিজে override করতে, আর চাইলে নির্দিষ্ট একটিকে ডাকতে:
interface Camera { default String info() { return "camera"; } }
interface Phone { default String info() { return "phone"; } }
class SmartPhone implements Camera, Phone {
@Override public String info() { // না লিখলে compile error
return Phone.super.info() + " + " + Camera.super.info();
}
}নিয়মের ক্রম: (১) class-এর নিজের বা superclass-এর method সবসময় জেতে; (২) তারপর বেশি নির্দিষ্ট interface (sub-interface); (৩) তাতেও মীমাংসা না হলে class-কে নিজে override করতে হয়। state নেই বলে field-এর দুই কপির সমস্যা ওঠে না।
ঝালিয়ে নিন: পর্ব ১৯ · inheritance, পর্ব ২১
খ-০৮টীকা লিখুন: composition বনাম inheritance — “is-a” আর “has-a”. (মাঝারি)
সংজ্ঞা: Inheritance হলো “is-a” — SavingsAccount একটি Account. Composition হলো “has-a” — একটি Car-এর একটি Engine আছে; Car-এর ভেতরে Engine-এর একটি field, আর Car কাজ পাঠায় সেই object-কে।
- Inheritance-এর ঝুঁকি: subclass parent-এর ভেতরের খুঁটিনাটির ওপর নির্ভর করে; parent বদলালে child ভাঙে (fragile base class). সম্পর্কটি compile-এর সময় স্থির — চলার সময় বদলানো যায় না।
- Composition-এর সুবিধা: ভেতরের object interface দিয়ে রাখলে চলার সময় বদলানো যায় (
PaymentGateway-এ bKash বা Nagad), টেস্টে নকল object বসানো যায়, আর শুধু দরকারি কাজটুকু বাইরে দেখানো যায়। - ক্লাসিক উদাহরণ: Java-র নিজের
Stack extends Vector— ফলে stack-এর মাঝখানেinsertElementAtকরা যায়, যা stack-এর নিয়ম ভাঙে। এ কারণেই এখনArrayDequeপরামর্শ দেওয়া হয়।
উপসংহার: “Favor composition over inheritance” — Gang of Four-এর Design Patterns (১৯৯৪) বইয়ের একটি মূলনীতি, যা Joshua Bloch-এর Effective Java-তেও জোর দিয়ে বলা হয়েছে। inheritance তখনই, যখন সত্যিকারের “is-a” সম্পর্ক আর parent-টি extend করার জন্যই নকশা করা।
ঝালিয়ে নিন: পর্ব ১৯ · inheritance, পর্ব ৪৮ · design pattern
৫ · অংশ গ — আধুনিক টাইপ ও ভুল সামলানো (মডিউল ৪)
রিভিশনের জন্য: পর্ব ২৩, পর্ব ২৪, পর্ব ২৫, পর্ব ২৬, পর্ব ২৭, পর্ব ২৮, পর্ব ২৯.
এই অংশের প্রশ্নে পরীক্ষকেরা প্রায়ই দেখেন আপনি আধুনিক Java (record, sealed, pattern matching) জানেন কি না, আর exception-এর শ্রেণিবিভাগ পরিষ্কার কি না।
গ-০১== আর equals()-এর পার্থক্য উদাহরণসহ লিখুন। equals override করলে hashCode-ও কেন override করতে হয়? (মাঝারি)
== primitive-এ মান তুলনা করে, আর reference-এ দেখে দুটি ভ্যারিয়েবল একই object-কে দেখাচ্ছে কি না (reference equality). equals() হলো Object-এর একটি method, যা দেখে দুটি object অর্থে সমান কি না। Object-এর নিজের equals আসলে ==-ই করে; String, Integer, record-এর মতো class সেটিকে override করে মান তুলনা করে।
import java.util.Objects;
class Point {
private final int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point p)) return false;
return x == p.x && y == p.y;
}
@Override
public int hashCode() { return Objects.hash(x, y); }
}
class Main {
public static void main(String[] args) {
String a = "Dhaka";
String b = "Dhaka"; // একই pool object
String c = new String("Dhaka"); // heap-এ নতুন object
System.out.println(a == b); // true
System.out.println(a == c); // false
System.out.println(a.equals(c)); // true
System.out.println(a == c.intern()); // true
Point p1 = new Point(2, 3), p2 = new Point(2, 3);
System.out.println(p1 == p2); // false: আলাদা object
System.out.println(p1.equals(p2)); // true: একই মান
System.out.println(p1.hashCode() == p2.hashCode());
}
}আউটপুট: true, false, true, true, false, true, true. দুটি একই literal String pool-এর একই object, কিন্তু new String সবসময় নতুন object বানায়; intern() pool-এর কপিটি ফেরত দেয়। Point-এ equals-এর ভেতরে o instanceof Point p — Java 16-এর pattern matching — cast আলাদা করে লিখতে হয়নি। শেষ লাইনে দুটি সমান Point-এর hashCode-ও সমান, যা নিচের চুক্তির দাবি।
equals–hashCode চুক্তি: a.equals(b) সত্য হলে a.hashCode() == b.hashCode() হতেই হবে (উল্টোটা জরুরি নয় — আলাদা object-এর hash মিলতে পারে, তাকে collision বলে)। HashMap আর HashSet আগে hashCode দিয়ে bucket খোঁজে, তারপর equals দিয়ে মেলায়। শুধু equals override করলে দুটি “সমান” Point আলাদা bucket-এ যায় — set.contains(new Point(2, 3)) false দিতে পারে। equals-কে reflexive, symmetric, transitive, consistent হতে হবে, আর x.equals(null) হবে false.
ঝালিয়ে নিন: পর্ব ২৩ · equals, hashCode, toString আর compareTo, পর্ব ০৮ · String pool
গ-০২টীকা লিখুন: Java-র enum. সাধারণ int constant-এর চেয়ে এটি ভালো কেন? (সহজ)
enum (Java 5) হলো নির্দিষ্ট কয়েকটি মানের একটি টাইপ — প্রতিটি মান ওই টাইপের একটি public static final object. Java-র enum আসলে পূর্ণ class: field, constructor (সবসময় private), method, এমনকি প্রতিটি মানের আলাদা আচরণ রাখা যায়।
enum OrderStatus {
PLACED("অর্ডার হয়েছে"), PAID("পরিশোধিত"), DELIVERED("পৌঁছেছে");
private final String label;
OrderStatus(String label) { this.label = label; }
String label() { return label; }
}
// OrderStatus.valueOf("PAID"), OrderStatus.values(), s.ordinal()- Type safety:
int status = 7;ভুল হলেও compile হয়;OrderStatus s = 7;হয় না। - switch-এ নিরাপদ: switch expression-এ সব মান না ধরলে compiler জানায়।
- বিশেষ collection:
EnumMap,EnumSet— ভেতরে array বা bit, খুব দ্রুত। - Singleton: এক মানের enum হলো thread-safe ও serialization-নিরাপদ singleton-এর সহজতম উপায়।
উপসংহার: ডেটাবেসে ordinal() রাখবেন না — মাঝখানে নতুন মান যোগ হলে সব সংখ্যা সরে যায়; নাম (name()) রাখুন।
ঝালিয়ে নিন: পর্ব ২৪ · enum
গ-০৩Record কী? সাধারণ class-এর সাথে এর পার্থক্য লিখুন। (সহজ)
Record (Java 16-এ স্থায়ী) হলো শুধু ডেটা বহনের জন্য একটি সংক্ষিপ্ত class. record Student(String name, int roll) { } লিখলেই compiler বানিয়ে দেয়: private final field, সব field নেওয়া constructor (canonical constructor), name()/roll() accessor, আর মানভিত্তিক equals, hashCode, toString.
| বিষয় | record | সাধারণ class |
|---|---|---|
| Field | সব private final; নতুন instance field যোগ করা যায় না | যেকোনো |
| equals/hashCode/toString | আপনাআপনি, মানভিত্তিক | নিজে লিখতে হয় |
| Inheritance | implicitly final; অন্য class extend করতে পারে না (ভেতরে java.lang.Record) | extend করা ও হওয়া যায় |
| Interface | implement করতে পারে | পারে |
| Getter-এর নাম | name() | প্রচলিত getName() |
যাচাই: compact constructor-এ নিয়ম বসানো যায়: record Money(long paisa) { Money { if (paisa < 0) throw new IllegalArgumentException(); } }
উপসংহার: record shallow immutable — field-এ একটি List থাকলে তালিকার ভেতর বাইরে থেকে বদলানো যায়; constructor-এ List.copyOf দিয়ে রক্ষা করুন। DTO, মানভিত্তিক object, Map-এর key — record-এর আদর্শ জায়গা।
ঝালিয়ে নিন: পর্ব ২৫ · record
গ-০৪Sealed class আর pattern matching for switch কী সমস্যার সমাধান করে? উদাহরণ দিন। (মাঝারি)
Sealed class/interface (Java 17-এ স্থায়ী) ঠিক করে দেয় কোন কোন class তাকে extend বা implement করতে পারবে — permits তালিকা দিয়ে। Pattern matching for switch (Java 21-এ স্থায়ী) switch-এ টাইপ ধরে একই সাথে ভ্যারিয়েবল বের করতে দেয়; record pattern দিয়ে record-এর ভেতরের মানও খুলে নেওয়া যায়।
sealed interface PaymentResult permits Success, Failed {}
record Success(String txId) implements PaymentResult {}
record Failed(String reason) implements PaymentResult {}
static String message(PaymentResult r) {
return switch (r) { // default লাগে না
case Success(String id) -> "সফল, transaction " + id;
case Failed(String why) -> "ব্যর্থ: " + why;
};
}কোন সমস্যা: আগে সম্ভাব্য সব টাইপ জানা থাকলেও compiler তা জানত না, তাই instanceof-এর লম্বা শিকল আর একটি “এখানে আসার কথা নয়” else লিখতে হতো। sealed হলে compiler জানে তালিকা সম্পূর্ণ (exhaustiveness) — নতুন টাইপ (ধরা যাক Pending) যোগ করলে যেসব switch সেটি ধরেনি, সবই compile error দেখায়। ভুলটা ধরা পড়ে চলার আগেই।
উপসংহার: এটি algebraic data type-এর Java রূপ — record হলো “এবং” (product), sealed হলো “অথবা” (sum). পরিবর্তনশীল আচরণের জন্য polymorphism এখনো ভালো; স্থির টাইপের তালিকার ওপর অনেক রকম কাজ হলে sealed + switch.
ঝালিয়ে নিন: পর্ব ২৬ · sealed class আর pattern matching
গ-০৫Generics কেন দরকার? Type erasure কী, আর এর ফলে কী কী সীমাবদ্ধতা আসে? (কঠিন)
Generics (Java 5) টাইপকে parameter বানায় — List<String>. লাভ দুটি: compile-এর সময় টাইপ যাচাই (ভুল টাইপ ঢোকালে error), আর বের করার সময় cast লাগে না। Java 5-এর আগে List-এ সবকিছু Object, আর ভুল ধরা পড়ত চলার সময় ClassCastException হয়ে।
Type erasure: generic টাইপের তথ্য শুধু compile-এর সময় থাকে; compiler যাচাই শেষে তা মুছে ফেলে (T → Object বা তার bound) আর দরকারি জায়গায় cast বসায়। bytecode-এ List<String> আর List<Integer> একই List. কারণ — পুরোনো (Java 5-এর আগের) কোড আর library-র সাথে মিল রাখা।
new T()বাnew T[10]লেখা যায় না।obj instanceof List<String>অবৈধ — চলার সময় String-এর তথ্য নেই।List<int>নয় — primitive চলে না, wrapper লাগে।void f(List<String>)আরvoid f(List<Integer>)overload করা যায় না — erasure-এর পর দুটির signature এক।
Wildcard ও PECS: List<? extends Number> থেকে পড়া যায় (producer), List<? super Integer>-এ লেখা যায় (consumer) — “Producer Extends, Consumer Super” (PECS). List<Integer> কিন্তু List<Number>-এর subtype নয় (generics invariant).
ঝালিয়ে নিন: পর্ব ২৮ · generics — type parameter আর wildcard
গ-০৬Checked আর unchecked exception-এর পার্থক্য লিখুন। Java-র exception hierarchy আঁকুন। (সহজ)
Throwable
/ \
Error Exception
(OutOfMemoryError, / \
StackOverflowError) IOException, RuntimeException
SQLException (NullPointerException,
(checked) ArithmeticException,
IllegalArgumentException …)
(unchecked)
| বিষয় | Checked | Unchecked |
|---|---|---|
| কোনগুলো | Exception-এর subclass, কিন্তু RuntimeException নয় | RuntimeException ও তার subclass (আর Error) |
| Compiler কী বলে | হয় catch করুন, নয় throws-এ ঘোষণা করুন — না হলে compile error | কিছু বাধ্য করে না |
| সাধারণ কারণ | প্রোগ্রামের বাইরের ঘটনা — ফাইল নেই, নেটওয়ার্ক বন্ধ | প্রোগ্রামারের ভুল — null, ভুল সূচক, ভুল argument |
| উদাহরণ | IOException, SQLException, InterruptedException | NullPointerException, ArrayIndexOutOfBoundsException, NumberFormatException |
উপসংহার: Error সাধারণত catch করা হয় না — JVM-এর গুরুতর সমস্যা, প্রোগ্রাম সাধারণত সামলাতে পারে না। checked exception নিয়ে বিতর্ক আছে: lambda আর stream-এর সাথে এটি অস্বস্তিকর, তাই অনেক আধুনিক library unchecked ব্যবহার করে (যেমন UncheckedIOException). Kotlin বা C#-এর মতো ভাষায় checked exception নেই।
ঝালিয়ে নিন: পর্ব ২৯ · exception — checked, unchecked আর try-with-resources
গ-০৭throw আর throws-এর পার্থক্য লিখুন। (সহজ)
| বিষয় | throw | throws |
|---|---|---|
| কী | একটি statement — এখনই exception ছোড়ে | method signature-এর একটি অংশ — ঘোষণা |
| কোথায় লেখা | method-এর শরীরে | parameter তালিকার পরে |
| পরে কী থাকে | একটি exception object: throw new IllegalStateException("…") | এক বা একাধিক exception class: throws IOException, SQLException |
| কয়টি | একবারে একটি | কমা দিয়ে অনেকগুলো |
| উদ্দেশ্য | ভুল ঘটেছে জানানো | ডাকারীকে সতর্ক করা: “এই checked exception আসতে পারে, সামলাও” |
String readConfig(Path p) throws IOException { // ঘোষণা
if (!Files.exists(p)) throw new NoSuchFileException(p.toString()); // ছোড়া
return Files.readString(p);
}উপসংহার: unchecked exception-এর জন্য throws লেখা ঐচ্ছিক (লিখলে নথি হিসেবে কাজ করে)। দুটি শব্দ মনে রাখার কৌশল: “throw — কাজ; throws — সতর্কবার্তা”।
ঝালিয়ে নিন: পর্ব ২৯
গ-০৮ব্যাংক থেকে টাকা তোলার জন্য একটি custom checked exception (InsufficientBalanceException) বানিয়ে প্রোগ্রাম লিখুন। (মাঝারি)
পদ্ধতি: “ব্যালান্স কম” প্রত্যাশিত একটি ব্যবসায়িক অবস্থা, যা ডাকারীকে সামলাতেই হবে — তাই Exception extend করে checked custom exception. বাড়তি তথ্য (কত টাকা কম) একটি field-এ। আর ঋণাত্মক পরিমাণ প্রোগ্রামারের ভুল — তার জন্য unchecked IllegalArgumentException.
class InsufficientBalanceException extends Exception {
private final long shortBy;
InsufficientBalanceException(long shortBy) {
super("ব্যালান্স কম: আরও " + shortBy + " টাকা লাগবে");
this.shortBy = shortBy;
}
long getShortBy() { return shortBy; }
}
class Account {
private long balance;
Account(long balance) { this.balance = balance; }
void withdraw(long amount) throws InsufficientBalanceException {
if (amount <= 0) throw new IllegalArgumentException("পরিমাণ শূন্যের বেশি হতে হবে");
if (amount > balance) throw new InsufficientBalanceException(amount - balance);
balance -= amount;
}
long getBalance() { return balance; }
}
class Main {
public static void main(String[] args) {
Account acc = new Account(5000);
long[] requests = {2000, 4000, -100, 3000};
for (long r : requests) {
try {
acc.withdraw(r);
System.out.println(r + " টাকা তোলা হলো, বাকি " + acc.getBalance());
} catch (InsufficientBalanceException e) {
System.out.println(e.getMessage() + " (ঘাটতি " + e.getShortBy() + ")");
} catch (IllegalArgumentException e) {
System.out.println("ভুল অনুরোধ: " + e.getMessage());
}
}
}
}আউটপুট চার লাইন: 2000 টাকা তোলা হলো, বাকি 3000; ব্যালান্স কম: আরও 1000 টাকা লাগবে (ঘাটতি 1000); ভুল অনুরোধ: পরিমাণ শূন্যের বেশি হতে হবে; 3000 টাকা তোলা হলো, বাকি 0. ব্যর্থ অনুরোধে balance বদলায়নি — যাচাই আগে, বদল পরে। super(message) দিয়ে বার্তা পাঠানো হয়েছে, তাই getMessage() কাজ করে। টাকা long-এ রাখা হয়েছে; ভগ্নাংশ লাগলে পয়সায় long বা BigDecimal — double নয়। নিচু স্তরের exception মুড়ে দিতে চাইলে super(message, cause) constructor-ও রাখুন।
ঝালিয়ে নিন: পর্ব ২৯ · exception, পর্ব ১৭ · encapsulation
গ-০৯টীকা লিখুন: try-with-resources. এটি finally-এর চেয়ে ভালো কেন? (সহজ)
try-with-resources (Java 7) এমন একটি try, যার বন্ধনীতে খোলা রিসোর্স (AutoCloseable বাস্তবায়ন করে এমন যেকোনো object) block শেষে আপনাআপনি close() হয় — স্বাভাবিকভাবে শেষ হোক বা exception-এ।
try (BufferedReader in = Files.newBufferedReader(Path.of("marks.txt"))) {
System.out.println(in.readLine());
} // এখানে in.close() নিজে থেকেই- কম কোড, কম ভুল: finally-তে null যাচাই আর close-এর নিজের try-catch লিখতে হয় না।
- একাধিক রিসোর্স: সেমিকোলন দিয়ে কয়েকটি খোলা যায়; বন্ধ হয় খোলার উল্টো ক্রমে।
- Exception হারায় না: শরীরে exception আর close-এও exception হলে আসলটি ছোড়া হয়, close-এরটি suppressed হিসেবে তার সাথে যুক্ত থাকে (
getSuppressed())। পুরোনো finally-পদ্ধতিতে close-এর exception আসলটিকে ঢেকে দিত।
ঝালিয়ে নিন: পর্ব ২৯, পর্ব ৩৭ · ফাইল I/O
৬ · অংশ ঘ — Collections ও functional Java (মডিউল ৫)
রিভিশনের জন্য: পর্ব ৩০, পর্ব ৩১, পর্ব ৩২, পর্ব ৩৩, পর্ব ৩৪, পর্ব ৩৫, পর্ব ৩৬.
Collection-এর প্রশ্নে পরীক্ষকেরা প্রায় সবসময় তিনটি জিনিস চান: ভেতরের গঠন, complexity, আর ক্রম (order) রাখে কি না। এই তিনটি সারি প্রতিটি টেবিলে রাখুন।
ঘ-০১ArrayList আর LinkedList-এর পার্থক্য লিখুন। কখন কোনটি ব্যবহার করবেন? (সহজ)
পূর্ণ মডেল উত্তর অংশ ২-এর ডায়াগ্রামে ধাপে ধাপে দেখানো হয়েছে। এখানে মূল টেবিল আর কয়েকটি বাড়তি তথ্য, যা ভালো উত্তরকে আলাদা করে:
| বিষয় | ArrayList | LinkedList |
|---|---|---|
| ভেতরের গঠন | dynamic array | doubly linked list |
get(i) | O(1) | O(n) |
শেষে add | amortized O(1) | O(1) |
| শুরুতে বা মাঝে যোগ/বাদ | O(n) — পরের উপাদান সরাতে হয় | O(1) জায়গায় পৌঁছানোর পর; পৌঁছাতে O(n) |
| মেমরি | কম; পাশাপাশি | বেশি; প্রতি node-এ দুটি বাড়তি reference |
| যে interface | List, RandomAccess | List, Deque |
বাড়তি তথ্য: ArrayList ভরে গেলে প্রায় দেড়গুণ বড় নতুন array বানিয়ে কপি করে — তাই একটি add মাঝে মাঝে O(n), কিন্তু গড়ে O(1) (amortized). আকার আগে জানা থাকলে new ArrayList<>(1000). দুটির কোনোটিই thread-safe নয়।
উপসংহার: ডিফল্ট ArrayList; queue বা stack হিসেবে ArrayDeque. LinkedList-এর আসল সুবিধা শুধু তখন, যখন iterator দিয়ে হাঁটতে হাঁটতে অনেক যোগ-বাদ করতে হয় — বাস্তবে বিরল।
ঝালিয়ে নিন: পর্ব ৩০ · ArrayList আর LinkedList, পর্ব ৩২ · Queue ও Deque
ঘ-০২HashMap, TreeMap আর LinkedHashMap-এর পার্থক্য লিখুন। HashMap ভেতরে কীভাবে কাজ করে? (মাঝারি)
তিনটিই Map — key-value জোড়া, প্রতিটি key একবার। পার্থক্য ভেতরের গঠন আর ক্রমে।
| বিষয় | HashMap | TreeMap | LinkedHashMap |
|---|---|---|---|
| গঠন | hash table (bucket-এর array) | red-black tree | hash table + সব entry জুড়ে একটি doubly linked list |
| get/put | গড়ে O(1) | O(log n) | গড়ে O(1) |
| ক্রম | নিশ্চিত নয় | key অনুযায়ী সাজানো | ঢোকানোর ক্রম (চাইলে access-এর ক্রম) |
null key | একটি চলে | স্বাভাবিক ক্রমে চলে না — NullPointerException | একটি চলে |
| key-এর শর্ত | ঠিকঠাক equals + hashCode | Comparable বা একটি Comparator | equals + hashCode |
| বাড়তি সুবিধা | সবচেয়ে দ্রুত | firstKey, floorKey, subMap — পরিসর খোঁজা | LRU cache (removeEldestEntry) |
HashMap কীভাবে কাজ করে: put(k, v)-এ (১) k.hashCode() থেকে একটি hash বের হয়, যার ওপরের bit নিচে মিশিয়ে নেওয়া হয়; (২) hash থেকে array-র একটি ঘর (bucket) বাছা হয়; (৩) ঘরে আগে থেকে entry থাকলে equals দিয়ে মেলানো হয় — মিললে মান বদলায়, না মিললে একই ঘরে যোগ হয় (collision). ডিফল্ট শুরুর ধারণক্ষমতা ১৬, load factor ০.৭৫ — উপাদান ধারণক্ষমতার ৭৫%-এর বেশি হলে array দ্বিগুণ হয় আর সব entry নতুন ঘরে যায় (rehashing). Java 8 থেকে একটি ঘরে অনেক entry জমলে (প্রায় ৮টির বেশি, আর table-এ অন্তত ৬৪টি ঘর থাকলে; ছোট table হলে আগে array বড় করা হয়) linked list-কে tree-তে বদলানো হয়, ফলে খারাপ ক্ষেত্রেও খোঁজা মোটামুটি O(log n).
উপসংহার: ডিফল্ট HashMap; সাজানো ক্রম বা পরিসর খুঁজতে TreeMap; ঢোকানোর ক্রম রাখতে (যেমন রিপোর্টে কলামের ক্রম) LinkedHashMap. একাধিক thread-এ ConcurrentHashMap — পুরোনো Hashtable নয়। আর মনে রাখুন: HashMap-এর ক্রমের ওপর নির্ভর করে লেখা কোড বা আউটপুট ভুল।
ঝালিয়ে নিন: পর্ব ৩১ · Set আর Map, পর্ব ২৩ · equals ও hashCode
ঘ-০৩একটি বাক্যে প্রতিটি শব্দ কতবার এসেছে, বর্ণানুক্রমে ছাপানোর প্রোগ্রাম লিখুন। সবচেয়ে বেশি আসা শব্দটিও বের করুন। (সহজ)
পদ্ধতি: frequency count-এর জন্য Map; বর্ণানুক্রমে ছাপাতে হবে বলে TreeMap. merge(key, 1, Integer::sum) এক লাইনে কাজ সারে — key না থাকলে 1 বসায়, থাকলে পুরোনো মানের সাথে 1 যোগ করে।
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
class Main {
public static void main(String[] args) {
String text = "the cat and the hat and the bat";
Map<String, Integer> freq = new TreeMap<>(); // key বর্ণানুক্রমে
for (String w : text.split("\\s+")) {
freq.merge(w, 1, Integer::sum); // নেই হলে 1, থাকলে +1
}
System.out.println(freq);
String top = Collections.max(freq.entrySet(), Map.Entry.comparingByValue()).getKey();
System.out.println("most frequent: " + top);
Map<Character, Integer> chars = new TreeMap<>();
for (char ch : "banana".toCharArray()) chars.merge(ch, 1, Integer::sum);
System.out.println(chars);
}
}আউটপুট: {and=2, bat=1, cat=1, hat=1, the=3}, most frequent: the, {a=3, b=1, n=2}. TreeMap-এর toString key-এর ক্রমে ছাপে, তাই আউটপুট প্রতিবার একই। HashMap দিলে গণনা একই হতো, কিন্তু ছাপার ক্রম নিশ্চিত থাকত না। Collections.max মান অনুযায়ী সবচেয়ে বড় entry দেয়; সমান মানের একাধিক শব্দ থাকলে কোনটি আসবে, তা নিয়ে খাতায় একটি নিয়ম লিখে দিন (যেমন “বর্ণানুক্রমে প্রথমটি”)। Stream দিয়ে একই কাজ: Collectors.groupingBy(w -> w, TreeMap::new, Collectors.counting()).
ঝালিয়ে নিন: পর্ব ৩১ · HashMap, TreeMap
ঘ-০৪Comparable আর Comparator-এর পার্থক্য উদাহরণসহ লিখুন। (মাঝারি)
| বিষয় | Comparable | Comparator |
|---|---|---|
| Package | java.lang | java.util |
| Method | compareTo(T other) | compare(T a, T b) |
| কোথায় লেখা | class-এর নিজের ভেতরে | class-এর বাইরে, আলাদা object বা lambda |
| কয়টি ক্রম | একটি — natural ordering | যত খুশি |
| অন্যের class-এ | সম্ভব নয় (source বদলাতে হয়) | সম্ভব |
| ব্যবহার | Collections.sort(list), TreeSet | list.sort(cmp), new TreeMap<>(cmp) |
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
record Student(String name, int roll, double gpa) implements Comparable<Student> {
@Override
public int compareTo(Student other) { // স্বাভাবিক ক্রম: roll
return Integer.compare(roll, other.roll);
}
}
class Main {
public static void main(String[] args) {
List<Student> list = new ArrayList<>(List.of(
new Student("Karim", 3, 3.50), new Student("Ayesha", 1, 3.90),
new Student("Rafi", 2, 3.50), new Student("Mitu", 4, 3.75)));
Collections.sort(list); // Comparable ব্যবহার করে
list.forEach(s -> System.out.print(s.roll() + ":" + s.name() + " "));
System.out.println();
list.sort(Comparator.comparingDouble(Student::gpa).reversed()
.thenComparing(Student::name)); // Comparator
list.forEach(s -> System.out.print(s.gpa() + ":" + s.name() + " "));
System.out.println();
}
}আউটপুট: প্রথম লাইন 1:Ayesha 2:Rafi 3:Karim 4:Mitu — roll অনুযায়ী। দ্বিতীয় লাইন 3.9:Ayesha 3.75:Mitu 3.5:Karim 3.5:Rafi — GPA বড় থেকে ছোট, আর সমান GPA-তে নামের ক্রমে (tie-breaker). লক্ষ করুন, compareTo-তে roll - other.roll না লিখে Integer.compare — বিয়োগ বড় সংখ্যায় overflow করে ভুল চিহ্ন দিতে পারে। double ছাপায় 3.9, 3.90 নয়।
উপসংহার: একটি স্বাভাবিক, সবার মেনে নেওয়া ক্রম থাকলে Comparable (সংখ্যা, তারিখ, roll); পরিস্থিতিভেদে আলাদা ক্রম হলে Comparator. compareTo-কে equals-এর সাথে সামঞ্জস্যপূর্ণ রাখুন — নইলে TreeSet দুটি আলাদা object-কে “একই” ভেবে একটি বাদ দিতে পারে।
ঝালিয়ে নিন: পর্ব ৩৩ · Comparable আর Comparator
ঘ-০৫Lambda expression আর functional interface কী? Method reference-এর চারটি ধরন লিখুন। (সহজ)
Functional interface হলো ঠিক একটি abstract method-ওয়ালা interface — যেমন Runnable, Comparator, Predicate<T>, Function<T,R>. @FunctionalInterface লিখলে compiler শর্তটি পাহারা দেয়। Lambda (Java 8) হলো সেই একটি method-এর সংক্ষিপ্ত, নামহীন বাস্তবায়ন: (a, b) -> a + b.
Predicate<Integer> pass = m -> m >= 40;
Function<String, Integer> len = String::length; // unbound instance method
Supplier<List<String>> maker = ArrayList::new; // constructor
Function<String, Integer> parse = Integer::parseInt; // static method
Consumer<String> out = System.out::println; // নির্দিষ্ট object-এর methodনিয়ম: lambda বাইরের local ভ্যারিয়েবল ব্যবহার করতে পারে কেবল যদি সেটি final বা effectively final হয়। lambda-র ভেতরে this মানে বাইরের object — anonymous class-এর মতো নতুন object নয়।
উপসংহার: lambda কোডকে ডেটার মতো পাঠাতে দেয় — sort-এর নিয়ম, filter-এর শর্ত, পরে চলবে এমন কাজ। লম্বা lambda-কে নাম দেওয়া method-এ সরিয়ে method reference দিয়ে ডাকলে পড়া সহজ হয়।
ঝালিয়ে নিন: পর্ব ৩৪ · lambda, functional interface আর method reference
ঘ-০৬Stream-এর intermediate আর terminal operation-এর পার্থক্য কী? একটি record আর stream দিয়ে অঞ্চলভিত্তিক বিক্রির রিপোর্ট বানান। (মাঝারি)
Stream (Java 8) হলো ডেটার ওপর ধাপে ধাপে কাজের একটি পাইপলাইন; এটি ডেটা রাখে না, আর একবারই ব্যবহার করা যায়। Intermediate operation (filter, map, sorted) নতুন stream ফেরত দেয় এবং lazy — terminal না আসা পর্যন্ত কিছুই চলে না। Terminal operation (collect, forEach, count, sum) পাইপলাইন চালিয়ে ফল দেয়।
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
record Sale(String region, String item, int qty, long priceTaka) {
Sale {
if (qty <= 0 || priceTaka < 0) throw new IllegalArgumentException("invalid sale");
}
long total() { return qty * priceTaka; }
}
class Main {
public static void main(String[] args) {
List<Sale> sales = List.of(
new Sale("Dhaka", "Pen", 10, 10), new Sale("Khulna", "Book", 2, 250),
new Sale("Dhaka", "Book", 3, 250), new Sale("Sylhet", "Pen", 5, 10),
new Sale("Khulna", "Pen", 20, 10));
Map<String, Long> byRegion = sales.stream().collect(Collectors.groupingBy(
Sale::region, TreeMap::new, Collectors.summingLong(Sale::total)));
byRegion.forEach((region, taka) -> System.out.printf("%-7s %5d%n", region, taka));
Map<String, Long> countByItem = sales.stream().collect(
Collectors.groupingBy(Sale::item, TreeMap::new, Collectors.counting()));
System.out.println(countByItem);
long grand = sales.stream().mapToLong(Sale::total).sum();
System.out.println("grand total = " + grand);
}
}আউটপুট: Dhaka 850, Khulna 700, Sylhet 50 (কলাম মিলিয়ে), তারপর {Book=2, Pen=3} আর grand total = 1600. groupingBy-এর তিন argument-এর রূপে দ্বিতীয়টি TreeMap::new — তাই অঞ্চলগুলো বর্ণানুক্রমে; map-এর ধরন না বললে কোন Map আসবে তার নিশ্চয়তা নেই (বাস্তবে সাধারণত HashMap), তাই ক্রমও নিশ্চিত থাকত না। তৃতীয়টি downstream collector — প্রতিটি দলের ভেতরে কী হিসাব হবে। record-এর compact constructor ভুল ডেটা ঢোকার আগেই আটকায়।
উপসংহার: lazy হওয়ায় filter(…).findFirst() প্রথম মিল পেলেই থামে — পুরো তালিকা ঘোরে না। stream-এর ভেতরে বাইরের ভ্যারিয়েবল বদলানো (side effect) এড়িয়ে চলুন; ফল collect দিয়ে নিন।
ঝালিয়ে নিন: পর্ব ৩৫ · Stream API, পর্ব ২৫ · record
ঘ-০৭টীকা লিখুন: Optional. কোথায় ব্যবহার করবেন, কোথায় করবেন না? (সহজ)
Optional<T> (Java 8) হলো একটি ছোট বাক্স, যাতে হয় একটি মান আছে, নয় খালি। method-এর return type-এ Optional দেখলে ডাকারী বোঝেন “ফল না-ও থাকতে পারে” — null ফেরত দেওয়ার চেয়ে স্পষ্ট।
Optional<User> u = repo.findByPhone("01711000000");
String name = u.map(User::name).orElse("অতিথি");
u.ifPresent(x -> sendSms(x));
User must = u.orElseThrow(); // খালি হলে NoSuchElementException- ব্যবহার করুন: খুঁজে না-ও পাওয়া যেতে পারে এমন method-এর return type-এ।
- করবেন না: field, method parameter বা collection-এর উপাদান হিসেবে; খালি তালিকার বদলে
Optional<List>নয় — খালি তালিকাই ফেরত দিন। - ফাঁদ:
opt.get()যাচাই ছাড়া ডাকা আসলেnull-এর পুরোনো সমস্যাই ফিরিয়ে আনে;Optionalভ্যারিয়েবল নিজেnullহওয়া উচিত নয়।
ঝালিয়ে নিন: পর্ব ৩৬ · Optional
৭ · অংশ ঙ — সিস্টেম, JVM আর পেশাদার Java (মডিউল ৬–৭)
রিভিশনের জন্য: পর্ব ৩৭, পর্ব ৩৮, পর্ব ৩৯, পর্ব ৪০, পর্ব ৪১, পর্ব ৪২, পর্ব ৪৩, পর্ব ৪৪, পর্ব ৪৫, পর্ব ৪৬, পর্ব ৪৭, পর্ব ৪৮, পর্ব ৪৯, পর্ব ৫০, পর্ব ৫১, পর্ব ৫২, পর্ব ৫৩, পর্ব ৫৪, পর্ব ৫৫.
Concurrency-র প্রশ্নে আউটপুট প্রায়ই thread-এর সময়ের ওপর নির্ভর করে। খাতায় এমন কোড দিলে লিখে দিন কোন অংশ নিশ্চিত আর কোন অংশ নয় — নিচের প্রোগ্রামগুলো এমনভাবে বানানো, যাতে ছাপা ফল প্রতিবার একই হয়।
ঙ-০১Process আর thread-এর পার্থক্য লিখুন। (সহজ)
Process হলো চলমান একটি প্রোগ্রাম, যার নিজের আলাদা মেমরি (address space) আর OS-এর রিসোর্স আছে। Thread হলো একটি process-এর ভেতরের স্বাধীনভাবে চলা একটি কাজের ধারা; একই process-এর সব thread heap ভাগ করে, কিন্তু প্রত্যেকের নিজের stack থাকে।
| বিষয় | Process | Thread |
|---|---|---|
| মেমরি | নিজস্ব, আলাদা | process-এর heap ভাগ করে; stack নিজের |
| তৈরির খরচ | বেশি | কম |
| যোগাযোগ | IPC — pipe, socket, ফাইল | ভাগের মেমরি দিয়ে সরাসরি (তাই synchronization লাগে) |
| একটি crash করলে | অন্য process সাধারণত নিরাপদ | ধরা না পড়া সমস্যা পুরো process-কে প্রভাবিত করতে পারে |
| Java-তে | ProcessBuilder; প্রতিটি java কমান্ড একটি JVM process | Thread, ExecutorService, virtual thread |
উপসংহার: একটি রেস্তোরাঁকে process ভাবুন — নিজের রান্নাঘর, নিজের মজুত। ভেতরের রাঁধুনিরা thread — একই রান্নাঘর ভাগ করেন, তাই একই চুলা নিয়ে ধাক্কা এড়াতে নিয়ম (lock) লাগে।
ঝালিয়ে নিন: পর্ব ৪০ · thread আর synchronization
ঙ-০২synchronized, volatile আর atomic class-এর পার্থক্য লিখুন। কোনটি কখন? (কঠিন)
তিনটিই একাধিক thread-এর মধ্যে ডেটা নিরাপদ রাখার উপায়, কিন্তু দুটি আলাদা সমস্যার আলাদা অংশ সমাধান করে: দৃশ্যমানতা (visibility — এক thread-এর লেখা অন্যটি দেখবে কি না) আর অবিভাজ্যতা (atomicity — কাজের মাঝখানে অন্য thread ঢুকতে পারবে কি না)।
| বিষয় | synchronized | volatile | Atomic (AtomicInteger) |
|---|---|---|---|
| দৃশ্যমানতা | হ্যাঁ | হ্যাঁ | হ্যাঁ |
| Atomicity | হ্যাঁ — পুরো block | না — count++ নিরাপদ নয় | হ্যাঁ — একটি ভ্যারিয়েবলের একটি কাজ |
| কৌশল | lock (monitor); অন্য thread অপেক্ষা করে | lock নেই; পড়া-লেখা সরাসরি মূল মেমরির নিয়মে | lock নেই; CAS CPU instruction |
| কোথায় বসে | method বা block | field | class (AtomicLong, AtomicReference…) |
| সেরা ব্যবহার | কয়েকটি ভ্যারিয়েবল একসাথে বদলানো, check-then-act | একটি flag — “থামো” সংকেত | counter, sequence নম্বর |
import java.util.concurrent.atomic.AtomicInteger;
class Main {
private static int syncCount = 0;
private static final AtomicInteger atomicCount = new AtomicInteger();
private static synchronized void incrementSync() { syncCount++; }
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 100_000; i++) {
incrementSync(); // lock নিয়ে ++
atomicCount.incrementAndGet(); // lock ছাড়া CAS দিয়ে ++
}
};
Thread t1 = new Thread(task), t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("synchronized: " + syncCount);
System.out.println("atomic: " + atomicCount.get());
}
}আউটপুট: synchronized: 200000 আর atomic: 200000 — প্রতিবার। দুই thread-এর কাজ কোন ক্রমে মিশল তা প্রতিবার আলাদা, কিন্তু দুটি পদ্ধতিই কোনো যোগ হারাতে দেয় না, তাই শেষ ফল নিশ্চিত। একটি সাধারণ int-এ lock ছাড়া ++ করলে ফল সাধারণত ২,০০,০০০-এর কম আর প্রতিবার আলাদা হতো (race condition) — সেটি এখানে ইচ্ছা করে ছাপানো হয়নি, কারণ সেটি নিশ্চিত নয়। join()-এর পর পড়া মান নিরাপদ, কারণ join একটি happens-before সম্পর্ক তৈরি করে।
উপসংহার: volatile দিয়ে counter বানানো একটি ক্লাসিক ভুল। অনেক thread একসাথে একটি counter বাড়ালে LongAdder আরও দ্রুত। আর সবচেয়ে ভালো ভাগের অবস্থা হলো যা নেই — immutable object আর thread-এর নিজের ডেটা।
ঝালিয়ে নিন: পর্ব ৪০ · thread আর synchronization
ঙ-০৩BlockingQueue দিয়ে একটি producer–consumer প্রোগ্রাম লিখুন এবং ব্যাখ্যা করুন। (কঠিন)
Producer–consumer হলো এমন নকশা, যেখানে এক বা একাধিক thread কাজ তৈরি করে একটি সারিতে রাখে, আর অন্যরা সারি থেকে নিয়ে কাজ করে। মাঝের সারি দুই পক্ষকে আলাদা রাখে — কারও গতি অন্যের ওপর সরাসরি নির্ভর করে না। BlockingQueue-এর put সারি ভরা থাকলে অপেক্ষা করে, take খালি থাকলে অপেক্ষা করে — নিজে wait/notify লিখতে হয় না।
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
class Main {
static final int POISON = -1; // "আর কাজ নেই" সংকেত
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2); // ধারণক্ষমতা ২
long[] total = {0};
Thread producer = new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) queue.put(i * 100); // ভরা হলে অপেক্ষা
queue.put(POISON);
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
Thread consumer = new Thread(() -> {
try {
while (true) {
int order = queue.take(); // খালি হলে অপেক্ষা
if (order == POISON) break;
total[0] += order;
System.out.println("processed order " + order);
}
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
producer.start();
consumer.start();
producer.join();
consumer.join();
System.out.println("total = " + total[0]);
}
}আউটপুট: processed order 100 থেকে processed order 500 পর্যন্ত পাঁচ লাইন, তারপর total = 1500. দুই thread কখন কতটুকু চলবে তা প্রতিবার আলাদা, তবু আউটপুট নিশ্চিত — কারণ (১) শুধু consumer ছাপে, (২) একটিই producer আর queue FIFO, তাই অর্ডার ঢোকার ক্রমেই বের হয়, (৩) total পড়া হয় দুটি join()-এর পরে। সারির ধারণক্ষমতা মাত্র ২, তাই producer বারবার put-এ আটকে consumer-এর জন্য অপেক্ষা করে — একে বলে back-pressure. শেষে poison pill (−1) consumer-কে থামতে বলে। InterruptedException ধরলে interrupt flag আবার বসানো হয়েছে — এটি গিলে ফেলা ভুল।
উপসংহার: একাধিক producer থাকলে ঢোকার ক্রম আর নিশ্চিত থাকে না; একাধিক consumer থাকলে প্রত্যেককে একটি করে poison pill দিতে হয়। বাস্তবে প্রায়ই ExecutorService নিজেই ভেতরে এমন একটি সারি রাখে।
ঝালিয়ে নিন: পর্ব ৪০, পর্ব ৩২ · Queue, পর্ব ৪১ · Executor
ঙ-০৪Platform thread আর virtual thread-এর পার্থক্য লিখুন। Virtual thread কোথায় লাভ দেয়, কোথায় দেয় না? (মাঝারি)
Platform thread হলো OS thread-এর একটি পাতলা মোড়ক — প্রতিটি Java thread-এর পেছনে একটি OS thread. Virtual thread (Java 21-এ স্থায়ী, JEP 444) JVM নিজে সামলায়: অনেক virtual thread অল্প কয়েকটি OS thread-এর (carrier thread) ওপর চলে, আর I/O-তে আটকালে JVM তাকে carrier থেকে নামিয়ে অন্যটিকে বসায়।
| বিষয় | Platform thread | Virtual thread |
|---|---|---|
| কে সামলায় | OS | JVM |
| খরচ | বেশি — বড় stack, OS-এর রিসোর্স | খুব কম — stack heap-এ, দরকারমতো বাড়ে |
| কতগুলো | সাধারণত কয়েক হাজার | লাখের ঘরেও সম্ভব |
| Pool করা | হ্যাঁ — thread pool | না — প্রতি কাজে নতুন একটি |
| লাভ | CPU-ভারী কাজ | I/O-তে অপেক্ষা করা অনেক কাজ (HTTP, database) |
| তৈরি | new Thread(…), Thread.ofPlatform() | Thread.ofVirtual(), Executors.newVirtualThreadPerTaskExecutor() |
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.IntStream;
class Main {
public static void main(String[] args) throws Exception {
long start = System.nanoTime();
try (ExecutorService ex = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<Integer>> futures = IntStream.range(0, 10_000)
.mapToObj(i -> ex.submit(() -> { Thread.sleep(100); return i; }))
.toList(); // ১০,০০০ virtual thread
long sum = 0;
for (Future<Integer> f : futures) sum += f.get();
System.out.println("tasks = " + futures.size() + ", sum = " + sum);
}
long ms = (System.nanoTime() - start) / 1_000_000;
System.out.println("finished in under 5 s? " + (ms < 5000));
Thread vt = Thread.ofVirtual().unstarted(() -> { });
Thread pt = Thread.ofPlatform().unstarted(() -> { });
System.out.println(vt.isVirtual() + " " + pt.isVirtual());
}
}আউটপুট: tasks = 10000, sum = 49995000, finished in under 5 s? true, true false. দশ হাজার কাজের প্রত্যেকটি ১০০ মিলিসেকেন্ড ঘুমায় — এক এক করে চালালে লাগত প্রায় ১,০০০ সেকেন্ড, কিন্তু virtual thread-এ সব একসাথে অপেক্ষা করে, তাই মোট সময় সাধারণত এক সেকেন্ডের কাছাকাছি। সঠিক মিলিসেকেন্ড মেশিনভেদে বদলায়, তাই শুধু “৫ সেকেন্ডের কম কি না” ছাপানো হয়েছে। try-with-resources-এর শেষে executor-এর close() সব কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করে।
উপসংহার: virtual thread কাজকে দ্রুত করে না — অপেক্ষাকে সস্তা করে। CPU-ভারী হিসাবে লাভ নেই। Java 21-এ synchronized block-এর ভেতরে আটকালে virtual thread carrier-এ আটকে থাকে (pinning); Java 24-এ JEP 491 এই সমস্যার বড় অংশ দূর করেছে। আর একসাথে লাখ কাজ database-এ গেলে connection pool-এর সীমা মানতে হয় — দরকার হলে Semaphore.
ঝালিয়ে নিন: পর্ব ৪২ · virtual thread, পর্ব ৪১
ঙ-০৫JVM-এর মেমরি এলাকাগুলো ব্যাখ্যা করুন। Garbage collection কীভাবে কাজ করে? (মাঝারি)
- Heap: সব object আর array; সব thread ভাগ করে। GC এখানে কাজ করে। প্রচলিত collector-এ ভাগ: young generation (Eden + survivor) আর old generation.
- Stack (প্রতি thread-এ একটি): প্রতিটি method ডাকে একটি stack frame — local ভ্যারিয়েবল, parameter, অস্থায়ী মান। primitive local সরাসরি এখানে, object-এর শুধু reference. গভীর recursion-এ
StackOverflowError. - Metaspace: class-এর metadata (Java 8 থেকে; আগে PermGen); heap-এর বাইরে native মেমরিতে।
- অন্যান্য: প্রতি thread-এর program counter, native method stack, আর JIT-এর বানানো machine code রাখার code cache.
Garbage collection: GC খুঁজে বের করে কোন object আর পৌঁছানো যায় না — GC root (চলমান thread-এর local ভ্যারিয়েবল, static field ইত্যাদি) থেকে reference ধরে হেঁটে। যাদের কাছে পৌঁছানো যায় না, তাদের মেমরি ফেরত নেওয়া হয়। বেশিরভাগ object অল্প সময় বাঁচে (generational hypothesis), তাই নতুন object-এর young এলাকা ঘন ঘন আর দ্রুত পরিষ্কার হয়; বেশি দিন বাঁচা object old এলাকায় ওঠে।
উপসংহার: Java 9 থেকে বেশিরভাগ ক্ষেত্রে ডিফল্ট collector G1; খুব কম বিরতির জন্য ZGC (Java 21-এ generational ZGC যোগ হয়েছে)। GC থাকলেও memory leak হয় — অপ্রয়োজনীয় object-এর reference কোনো static collection-এ রয়ে গেলে GC তাকে সরাতে পারে না। System.gc() শুধু অনুরোধ, নিশ্চয়তা নয়।
ঝালিয়ে নিন: পর্ব ৪৪ · JVM মেমরি আর garbage collection, পর্ব ০৫
ঙ-০৬JDBC-তে Statement আর PreparedStatement-এর পার্থক্য লিখুন। SQL injection কীভাবে ঠেকায়? (মাঝারি)
| বিষয় | Statement | PreparedStatement |
|---|---|---|
| SQL কীভাবে | পুরো SQL String জুড়ে বানানো | আগে থেকে ঠিক করা SQL, মানের জায়গায় ? |
| মান বসানো | String-এ জোড়া | setString(1, …), setLong(2, …) — আলাদাভাবে পাঠানো |
| SQL injection | ঝুঁকি আছে | ঠেকায় — মান কখনো SQL হিসেবে পড়া হয় না |
| গতি | প্রতিবার নতুন করে parse | database ও driver পরিকল্পনা আবার ব্যবহার করতে পারে |
| টাইপ | নিজে quote আর format সামলাতে হয় | তারিখ, সংখ্যা, null — driver সামলায় |
// বিপজ্জনক: phone = "' OR '1'='1" দিলে সব সারি ফেরত আসে
String sql = "SELECT * FROM users WHERE phone = '" + phone + "'";
// নিরাপদ
String safe = "SELECT id, name FROM users WHERE phone = ?";
try (PreparedStatement ps = conn.prepareStatement(safe)) {
ps.setString(1, phone);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) System.out.println(rs.getString("name"));
}
}উপসংহার: ব্যবহারকারীর দেওয়া যেকোনো মান থাকলে সবসময় PreparedStatement. তবে ? শুধু মানের জায়গায় বসে — table বা column-এর নাম ? দিয়ে দেওয়া যায় না; সেগুলো একটি অনুমোদিত তালিকা থেকে যাচাই করে বসাতে হয়। Connection, Statement, ResultSet — সব try-with-resources-এ।
ঝালিয়ে নিন: পর্ব ৪৯ · JDBC আর ডেটাবেস
ঙ-০৭Spring-এ @Component আর @Bean-এর পার্থক্য লিখুন। Dependency injection কী? (মাঝারি)
Dependency injection মানে একটি object তার দরকারি অন্য object নিজে new দিয়ে বানায় না; বাইরে থেকে (সাধারণত constructor দিয়ে) পায়। Spring-এর container এই object-গুলো (bean) বানায়, জোড়ে আর জীবনচক্র সামলায়। Bean ঘোষণার দুটি প্রধান পথ:
| বিষয় | @Component (ও @Service, @Repository) | @Bean |
|---|---|---|
| কোথায় বসে | class-এর ওপর | @Configuration class-এর একটি method-এর ওপর |
| কীভাবে খুঁজে পায় | component scanning — package ঘুরে | method-টি ডেকে, তার return করা object নিয়ে |
| কার class | নিজের লেখা class | যেকোনো — বাইরের library-র class-ও (যার source-এ annotation বসানো যায় না) |
| তৈরির নিয়ন্ত্রণ | Spring constructor ডাকে | আপনি method-এ পুরো তৈরি-প্রক্রিয়া লেখেন |
@Service
class OrderService {
private final PaymentGateway gateway;
OrderService(PaymentGateway gateway) { this.gateway = gateway; } // constructor injection
}
@Configuration
class AppConfig {
@Bean
Clock clock() { return Clock.system(ZoneId.of("Asia/Dhaka")); } // JDK-র class
}উপসংহার: নিজের class-এ @Component পরিবারের stereotype annotation; অন্যের class বা জটিল তৈরি হলে @Bean. constructor injection প্রস্তাবিত — dependency স্পষ্ট, field final রাখা যায়, আর Spring ছাড়াই টেস্টে new OrderService(fakeGateway) লেখা যায়।
ঝালিয়ে নিন: পর্ব ৫০ · Spring Boot-এর শুরু
ঙ-০৮REST API-তে PUT আর PATCH-এর পার্থক্য লিখুন। Idempotent মানে কী? (মাঝারি)
Idempotent মানে একই অনুরোধ একবার পাঠানো আর দশবার পাঠানোর ফল server-এর অবস্থায় একই। নেটওয়ার্ক ব্যর্থ হলে client নিশ্চিন্তে আবার পাঠাতে পারে কি না — এটাই প্রশ্ন।
| বিষয় | PUT | PATCH |
|---|---|---|
| অর্থ | পুরো resource পাঠানো রূপ দিয়ে বদলে দাও | শুধু উল্লেখ করা অংশ বদলাও |
| Body | সম্পূর্ণ প্রতিনিধিত্ব; না দেওয়া field সাধারণত মুছে যায় বা ডিফল্ট হয় | শুধু বদলানো field (বা বদলের নির্দেশ) |
| Idempotent? | হ্যাঁ — HTTP-র সংজ্ঞাতেই | নিশ্চিত নয় — যেমন “stock ৫ কমাও” দুবার পাঠালে দুবার কমে |
| উদাহরণ | PUT /products/7 + পুরো product | PATCH /products/7 + {"price": 120} |
প্রসঙ্গ: GET, PUT, DELETE idempotent; POST নয় (দুবার পাঠালে দুটি অর্ডার)। সাধারণ status code: 200 OK, 201 Created (POST-এ নতুন resource, সাথে Location header), 204 No Content, 400 Bad Request, 404 Not Found, 409 Conflict.
উপসংহার: পেমেন্টের মতো POST-কে নিরাপদে আবার পাঠানোর জন্য client একটি অনন্য idempotency key পাঠায়, server সেটি মনে রেখে দ্বিতীয়বার একই কাজ করে না।
ঝালিয়ে নিন: পর্ব ৫১ · Spring Boot দিয়ে REST API
ঙ-০৯টীকা লিখুন: JUnit 5 দিয়ে unit testing. একটি ছোট উদাহরণ দিন। (সহজ)
Unit test হলো কোডের একটি ছোট অংশ — সাধারণত একটি method বা class — জানা ইনপুটে প্রত্যাশিত ফল দেয় কি না, স্বয়ংক্রিয়ভাবে যাচাই করার কোড। JUnit 5 তিন অংশে গঠিত: Platform (test চালানোর ভিত্তি), Jupiter (নতুন API), আর Vintage (পুরোনো JUnit 4 test চালানোর জন্য)।
class AccountTest {
@Test
void withdrawReducesBalance() throws Exception {
Account acc = new Account(5000); // Arrange
acc.withdraw(2000); // Act
assertEquals(3000, acc.getBalance()); // Assert
}
@Test
void overdrawIsRejected() {
Account acc = new Account(100);
assertThrows(InsufficientBalanceException.class, () -> acc.withdraw(500));
}
}- গঠন: Arrange–Act–Assert; একটি test-এ একটি আচরণ।
- দরকারি annotation:
@Test,@BeforeEach,@ParameterizedTest,@DisplayName. - ভালো test: দ্রুত, একে অপরের ওপর নির্ভরহীন, প্রতিবার একই ফল; edge case আর ব্যর্থতার পথও যাচাই করে।
ঝালিয়ে নিন: পর্ব ৪৭ · টেস্টিং — JUnit 5, পর্ব ৪৬ · Maven আর Gradle
ঙ-১০Singleton pattern কী? Java-তে thread-safe singleton বানানোর দুটি উপায় লিখুন। এর সমালোচনা কী? (কঠিন)
Singleton হলো এমন একটি class, যার পুরো প্রোগ্রামে ঠিক একটি object থাকবে, আর সেটি পাওয়ার একটি নির্দিষ্ট পথ থাকবে। Gang of Four-এর ২৩টি design pattern-এর একটি (creational).
// ১. Enum — সবচেয়ে সরল; thread-safe, serialization-নিরাপদ
enum AppConfig { INSTANCE; String currency() { return "BDT"; } }
// ২. Holder idiom — প্রথম ব্যবহারের সময় তৈরি (lazy), lock ছাড়াই নিরাপদ
final class IdGenerator {
private IdGenerator() { }
private static class Holder { static final IdGenerator INSTANCE = new IdGenerator(); }
static IdGenerator getInstance() { return Holder.INSTANCE; }
}কেন নিরাপদ: JVM একটি class-কে ঠিক একবার initialize করে আর সেই কাজ নিজেই synchronize করে। Holder class প্রথমবার getInstance() ডাকা পর্যন্ত লোডই হয় না। পুরোনো double-checked locking-এ field-টি volatile না হলে অর্ধেক-তৈরি object দেখা যেতে পারত — ভাইভায় এটি একটি প্রিয় ফলো-আপ।
সমালোচনা: singleton আসলে একটি global state — যেকোনো জায়গা থেকে ব্যবহার করা যায়, তাই কোন কোড কার ওপর নির্ভর করে তা লুকিয়ে যায়, আর টেস্টে নকল বসানো কঠিন। আধুনিক পথ: Spring-এর মতো DI container-কে বলুন একটিই object বানাতে (Spring bean-এর ডিফল্ট scope singleton), আর সেটি constructor দিয়ে পাঠান।
ঝালিয়ে নিন: পর্ব ৪৮ · design pattern আর clean code, পর্ব ২৪ · enum
ঙ-১১TCP আর UDP-র পার্থক্য লিখুন। Java-তে একটি TCP সার্ভার কীভাবে কাজ করে — ServerSocket, accept(), Socket — আর framing ও timeout কেন জরুরি? (মাঝারি)
| বিষয় | TCP | UDP |
|---|---|---|
| সংযোগ | আগে three-way handshake (SYN, SYN-ACK, ACK) | নেই — সরাসরি datagram পাঠানো |
| নির্ভরযোগ্যতা | হারালে আবার পাঠায়, ক্রম ঠিক রাখে | হারাতে বা উল্টো ক্রমে আসতে পারে |
| সীমানা | byte-এর স্রোত — message-এর সীমানা নেই | প্রতিটি datagram একটি পুরো message |
| Java class | Socket, ServerSocket | DatagramSocket, DatagramPacket |
| উদাহরণ | HTTP/1.1, HTTP/2, ডেটাবেস, SSH | DNS, ভিডিও কল, অনলাইন গেম, QUIC |
try (var server = new ServerSocket(5000); // port খুলে listen
var pool = Executors.newVirtualThreadPerTaskExecutor()) {
while (true) {
Socket client = server.accept(); // client না আসা পর্যন্ত অপেক্ষা
pool.submit(() -> handle(client)); // প্রতি সংযোগে একটি virtual thread
}
}
// handle(): s.setSoTimeout(2_000); UTF-8 দিয়ে BufferedReader/PrintWriter;
// readLine() == null হলে অন্য প্রান্ত বন্ধ — লুপ শেষকীভাবে চলে: ServerSocket একটি port-এ নতুন সংযোগের অপেক্ষা করে। accept() একটি client না আসা পর্যন্ত আটকে থাকে, এলে শুধু সেই client-এর জন্য একটি নতুন Socket দেয়; আসল পড়া-লেখা হয় এই Socket-এর stream দিয়ে। একজন ধীর client যেন বাকিদের আটকে না রাখে, তাই প্রতি সংযোগ আলাদা thread-এ — Java 21-এ virtual thread-এ সহজ ব্লকিং কোডেই হাজারো সংযোগ।
framing: TCP একটি byte-স্রোত। দুবার আলাদা করে লেখা “TEA” আর “DAL” অন্য প্রান্তে একটি read()-এ “TEADAL” হয়ে আসতে পারে। তাই message-এর সীমানা application-কে ঠিক করতে হয় — প্রতিটি message-এর শেষে newline (readLine()), অথবা আগে দৈর্ঘ্য পাঠিয়ে (writeInt + readFully), আর দৈর্ঘ্যের একটি সর্বোচ্চ সীমা যাচাই করে।
timeout: ডিফল্টে socket-এ কোনো timeout নেই — মরা সংযোগে read() চিরকাল অপেক্ষা করে। socket.connect(address, ms) দেয় connect timeout, setSoTimeout(ms) দেয় প্রতি-পড়ার timeout (পার হলে SocketTimeoutException); এর সাথে পুরো request-এর মোট সময়সীমাও রাখা ভালো।
উপসংহার: TCP নির্ভরযোগ্য কিন্তু সীমানাহীন স্রোত, UDP দ্রুত কিন্তু নিশ্চয়তাহীন। নেটওয়ার্ক কোডের তিনটি অভ্যাস — স্পষ্ট framing, প্রতিটি ধাপে timeout, আর client-এর পাঠানো আকারে সীমা।
ঝালিয়ে নিন: পর্ব ৪৩ · নেটওয়ার্কিং — socket, HttpClient আর WebSocket, পর্ব ৪২ · virtual thread
ঙ-১২JPA-তে persistence context আর entity-র জীবনচক্র ব্যাখ্যা করুন। dirty checking কী? N+1 সমস্যা কী, আর কীভাবে সমাধান করবেন? (মাঝারি)
JPA (Jakarta Persistence) object আর টেবিল মেলানোর মানক API; Hibernate তার সবচেয়ে প্রচলিত বাস্তবায়ন, আর Spring Data JPA তার ওপর repository বানায়। Persistence context হলো একটি transaction-এর managed entity-র খাতা: এক id-তে এক object (first-level cache), আর প্রতিটির লোডের সময়ের একটি snapshot.
| অবস্থা | কীভাবে আসে | বৈশিষ্ট্য |
|---|---|---|
| Transient | new Product(...) | খাতায় নেই, id নেই |
| Managed | persist(), find(), query | বদল নজরে থাকে; flush-এ SQL |
| Detached | transaction বা context বন্ধ | বদলালে SQL যায় না; lazy সম্পর্ক ছুঁলে LazyInitializationException |
| Removed | remove() | flush-এ DELETE |
Dirty checking: commit-এর আগে (flush-এ) Hibernate প্রতিটি managed entity-র বর্তমান মান snapshot-এর সাথে মেলায়, আর যেটা বদলেছে তার জন্য নিজেই UPDATE চালায়। তাই @Transactional method-এ product.setStock(47) লিখলেই যথেষ্ট — save() লাগে না।
N+1 সমস্যা: ১টি query-তে N টি অর্ডার এল, তারপর লুপে প্রতিটির LAZY getCustomer() ছোঁয়ায় আরও একটি করে SELECT — মোট ১ + N. ছোট ডেটায় টের পাওয়া যায় না, ১০০০ অর্ডারে ১০০১টি round trip. সমাধান:
join fetch—select o from Order o join fetch o.customer, একটি SQL;@EntityGraph(attributePaths = "customer")repository method-এ;- batch fetching —
hibernate.default_batch_fetch_size, proxy-গুলো একসাথেin (...)query-তে; - পড়ার পাতায় DTO projection — শুধু দরকারি কলাম।
সম্পর্ক EAGER করে দেওয়া সমাধান নয় — JPQL query-র পরে Hibernate প্রায়ই আলাদা SELECT চালায়, আর বাকি সব query-তে বাড়তি ডেটা আসে। মনে রাখুন, @ManyToOne আর @OneToOne ডিফল্টে EAGER, তাই সেখানে fetch = FetchType.LAZY স্পষ্ট লিখুন।
উপসংহার: ORM-এর প্রতিটি সুবিধার পেছনে SQL আছে। SQL log চালু রেখে গুনে দেখুন — তালিকা বড় হলে query-র সংখ্যা বাড়লেই সেটা N+1.
ঝালিয়ে নিন: পর্ব ৫২ · Spring Data JPA আর Hibernate, পর্ব ৪৯ · JDBC আর ডেটাবেস
ঙ-১৩Spring Security-তে authentication আর authorization-এর পার্থক্য লিখুন — কখন 401 আর কখন 403 আসে?পাসওয়ার্ড কীভাবে সংরক্ষণ করবেন, আর stateless JWT API-তে CSRF কেন প্রায়ই বন্ধ রাখা হয়? (কঠিন)
| বিষয় | Authentication | Authorization |
|---|---|---|
| প্রশ্ন | “আপনি কে?” | “এই কাজ কি আপনি করতে পারেন?” |
| প্রমাণ | পাসওয়ার্ড, OTP, token | role, authority, মালিকানার নিয়ম |
| ব্যর্থ হলে | 401 Unauthorized (আসলে “unauthenticated”) | 403 Forbidden |
| Spring-এ | authentication filter, UserDetailsService, PasswordEncoder | authorizeHttpRequests, @PreAuthorize, ownership check |
পাসওয়ার্ড সংরক্ষণ: কখনো সরাসরি নয়, MD5 বা SHA-256-এর মতো দ্রুত hash-এও নয় — এগুলো দ্রুত হওয়ার জন্যই বানানো, ফাঁস হওয়া ডেটাবেসে কোটি কোটি অনুমান সস্তা। ব্যবহার করুন salt আর cost factor-সহ ধীর hash — BCrypt, Argon2 বা PBKDF2. Spring-এ:
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder(); // নতুন hash: {bcrypt}$2a$10$...
}
// সাইন-আপ: hash = encoder.encode(raw); লগইন: encoder.matches(raw, hash)প্রতিটি ব্যবহারকারীর আলাদা salt একই পাসওয়ার্ডের hash আলাদা করে, cost factor প্রতিটি অনুমান ব্যয়বহুল করে, আর তুলনা হয় সমান সময়ে (timing attack এড়াতে)।
CSRF আর JWT: CSRF-এর ঝুঁকি আসে কারণ ব্রাউজার cookie নিজে থেকে প্রতিটি request-এ জুড়ে দেয়, অন্য সাইটের পাতা থেকে শুরু হলেও। session cookie-ভিত্তিক সাইটে তাই CSRF token চালু রাখতে হয়। stateless API-তে token যায় Authorization: Bearer header-এ, যা ব্রাউজার নিজে জোড়ে না — অন্য সাইটের request-এ পরিচয়ই থাকে না, তাই সেখানে CSRF বন্ধ রাখা যুক্তিসংগত। কিন্তু JWT cookie-তে রাখলে আবার CSRF সুরক্ষা লাগবে। আর মনে রাখুন, JWT-এর payload এনক্রিপ্ট নয় — যে কেউ পড়তে পারে, শুধু স্বাক্ষরের কারণে বদলাতে পারে না।
উপসংহার: পরিচয় যাচাই আর অনুমতি দুটি আলাদা স্তর; role-এর পাশাপাশি “এটা কি আপনার ডেটা?” পরীক্ষাও নিজে লিখতে হয় (BOLA ঠেকাতে)। নিরাপদ ডিফল্ট রাখুন, আর কোনো সুরক্ষা বন্ধ করলে ঠিক কোন কারণে নিরাপদ, তা বলতে পারুন।
ঝালিয়ে নিন: পর্ব ৫৩ · Spring Security, পর্ব ৫১ · REST API
৮ · ভাইভায় কথা বলার কৌশল — আর নিজের প্রজেক্ট নিয়ে কথা
লিখিত পরীক্ষায় আপনি ভাবার সময় পান, কাটাকাটি করতে পারেন। ভাইভায় পারেন না — প্রশ্ন আসে মুখে, উত্তরও দিতে হয় তখনই। আর পরীক্ষক আপনার প্রথম উত্তর শুনেই পরের প্রশ্ন বানান। এমন প্রশ্নকে বলে follow-up প্রশ্ন. তাই ভাইভার আসল দক্ষতা দুটি: ছোট, গোছানো উত্তর, আর প্রশ্নের শিকল সামলানো।
তিন ধাপের কাঠামো: সংজ্ঞা → উদাহরণ → trade-off
প্রশ্ন: “Interface কী?” দুর্বল উত্তর: “Interface হলো… মানে… যেখানে abstract method থাকে… আর implements করতে হয়…”. গোছানো উত্তর: “Interface হলো একটি চুক্তি — কোন method থাকতে হবে তার তালিকা (সংজ্ঞা)। যেমন Comparable implement করলে যেকোনো class-কে sort করা যায় (উদাহরণ)। Abstract class-এর সাথে পার্থক্য হলো, এতে instance state নেই, কিন্তু একটি class অনেকগুলো interface নিতে পারে (trade-off).” পনেরো সেকেন্ড, তিন বাক্য — আর পরীক্ষকের হাতে পরের প্রশ্নের তিনটি সূত্র।
ভাইভার উত্তরকে রিকশাওয়ালাকে পথ বলার মতো ভাবুন। প্রথমে গন্তব্য বলেন (“ধানমন্ডি ২৭”) — সংজ্ঞা। তারপর একটি চেনা চিহ্ন (“মসজিদের পাশের গলি”) — উদাহরণ। শেষে একটি সতর্কতা (“মিরপুর রোডে এখন জ্যাম, ভেতর দিয়ে যান”) — trade-off. পুরো শহরের মানচিত্র বোঝাতে বসলে রিকশা আর চলে না।
- আগে উত্তর, পরে বিস্তার: পরীক্ষক চাইলে নিজেই “আরেকটু বলুন” বলবেন। নিজে থেকে পাঁচ মিনিট বললে বাকি প্রশ্নের সময় কমে, আর ভুল বলার সুযোগ বাড়ে।
- Think aloud: নিশ্চিত না হলে ভাবনাটা জোরে বলুন — “HashMap-এ key-এর hashCode বদলে গেলে… তাহলে সে অন্য bucket-এ খুঁজবে… তাই পুরোনো entry খুঁজে পাবে না।” পরীক্ষক আপনার যুক্তির পথ দেখতে চান।
- অনুমান স্পষ্ট করুন: “Integer cache কত পর্যন্ত?” — “ডিফল্ট সেটিংসে −128 থেকে 127.” “HashSet কোন ক্রমে ছাপবে?” — “নিশ্চিত নয়; ক্রম চাইলে LinkedHashSet বা TreeSet.” এই সতর্কতা অভিজ্ঞতার চিহ্ন।
- সংস্করণ বলুন: “record Java 16-এ স্থায়ী, virtual thread Java 21-এ।” আধুনিক Java জানা আছে, এটা বোঝানোর সবচেয়ে সহজ উপায়।
- বোর্ড বা কাগজ চান: “একটু এঁকে দেখাই?” — HashMap-এর bucket বা stack ও heap-এর ছবি মুখের কথার চেয়ে শক্তিশালী।
নিচের ডায়াগ্রামে একটি বাস্তবধর্মী ভাইভার শিকল দেখুন। প্রতিটি ধাপে প্রশ্ন একটু গভীরে যাচ্ছে। শেষ ধাপে প্রার্থী পুরো নিশ্চিত নন — তবু সঠিকভাবে সামলাচ্ছেন।
পরীক্ষক: HashMap কী?
আপনি: key-value জোড়া রাখার একটি Map, ভেতরে hash table.
যেমন ফোন নম্বর থেকে গ্রাহক খোঁজা — গড়ে O(1).
তবে ক্রম নিশ্চিত নয়; ক্রম লাগলে LinkedHashMap বা TreeMap.
পরীক্ষক: put করলে ভেতরে কী হয়?
আপনি: key-এর hashCode থেকে array-র একটি ঘর (bucket) বের হয়।
ঘরে কিছু থাকলে equals দিয়ে মেলায় — মিললে মান বদলায়,
না মিললে একই ঘরে যোগ হয়। ৭৫% ভরলে array দ্বিগুণ।
পরীক্ষক: সব key একই ঘরে গেলে?
আপনি: তখন সেই ঘরে লম্বা তালিকা — খোঁজা O(n)-এর দিকে যায়।
Java 8 থেকে একটি ঘরে অনেক entry জমলে তালিকাটি
tree হয়ে যায়, ফলে খারাপ ক্ষেত্রেও O(log n).
পরীক্ষক: key হিসেবে mutable object দিলে কী সমস্যা?
আপনি: ঢোকানোর পর key-এর যে field থেকে hashCode আসে তা বদলালে,
get সেটিকে নতুন hash-এর ঘরে খুঁজবে — পুরোনো ঘরে থাকা
entry আর পাওয়া যাবে না। তাই key হিসেবে String বা
record-এর মতো immutable টাইপ ভালো।
পরীক্ষক: ConcurrentHashMap ভেতরে কীভাবে thread-safe হয়? আপনি: পুরো খুঁটিনাটি নিশ্চিত নই, তবে যা জানি: পুরো map-এ একটি lock নয় — তাহলে Hashtable-এর মতো ধীর হতো। আমার ধারণা এটি আলাদা আলাদা bucket স্তরে lock বা CAS ব্যবহার করে, যাতে ভিন্ন bucket-এ একসাথে লেখা যায়। (ঠিক দিকেই: Java 8 থেকে খালি bucket-এ CAS, আর ভরা bucket-এর প্রথম node-এ synchronized — সূক্ষ্ম lock.)
- সহজ শুরু। সংজ্ঞা, উদাহরণ, trade-off — তিন বাক্য। শেষ বাক্যটিই পরীক্ষককে পরের প্রশ্নের সূত্র দিল।
- “কীভাবে” প্রশ্ন। hashCode → bucket → equals — তিনটি শব্দ আর এক লাইনের প্রবাহ। load factor-এর উল্লেখ দেখায় আপনি শুধু ব্যবহার নয়, ভেতরটাও জানেন।
- খারাপ ক্ষেত্র। “গড়ে O(1)” বলার পর পরীক্ষক প্রায়ই worst case জানতে চান। Java 8-এর tree-তে রূপান্তরের কথা বললে উত্তর আলাদা হয়ে যায়।
- ফাঁদের প্রশ্ন। mutable key অনেক বাস্তব বাগের উৎস। কারণসহ উত্তর — “নতুন hash-এর ঘরে খুঁজবে” — পূর্ণ কৃতিত্ব পায়।
- “জানি না” সামলানো। প্রার্থী সৎভাবে বলছেন নিশ্চিত নন, তারপর যা জানেন তা থেকে যুক্তি দিয়ে এগোচ্ছেন — আর যুক্তিটি সঠিক দিকেই গেছে। এভাবে ভেবে বলা উত্তর প্রায়ই অন্তত আংশিক কৃতিত্ব পায়।
যে প্রশ্নের উত্তর জানেন না
- থামুন, প্রশ্নটি নিশ্চিত হয়ে নিন: “আপনি কি HashMap-এর কথা বলছেন, নাকি Hashtable-এর?” অনেক সময় প্রশ্ন বুঝতেই ভুল হয়।
- যা জানেন সেখান থেকে শুরু করুন: “ঠিক এটা পড়িনি, তবে কাছাকাছি জিনিস জানি — …”.
- যুক্তি দিয়ে এগোন, জোরে: আন্দাজকে আন্দাজ বলেই বলুন — “আমার ধারণা…”.
- না পারলে সৎভাবে বলুন: “এটা আমি জানি না, পরে দেখে নেব।” আন্দাজে ভুল তথ্য জোর দিয়ে বললে পরীক্ষক আপনার বাকি ঠিক উত্তরগুলো নিয়েও সন্দেহ করেন।
- পরের প্রশ্নে মন দিন: একটি প্রশ্ন না পারা পুরো ভাইভা নয়। ঘাবড়ে গিয়ে পরের সহজ প্রশ্নেও ভুল করা সবচেয়ে বড় ক্ষতি।
নিজের প্রজেক্ট নিয়ে কথা বলা
প্রায় সব ভাইভা আর ইন্টারভিউতে একটি প্রশ্ন আসে: “আপনার একটি প্রজেক্টের কথা বলুন।” এই কোর্সে আপনার দুটি প্রজেক্ট আছে — পর্ব ২২-এর মাঝপথের প্রজেক্ট “হিসাব খাতা” (array আর Command interface দিয়ে একটি CLI টুল) আর পর্ব ৫৫-এর ক্যাপস্টোন “দোকানদার” (stock, অর্ডার, পেমেন্ট — port আর adapter, JDBC, Spring REST). একটি প্রচলিত কাঠামো হলো STAR: Situation (প্রেক্ষাপট), Task (আপনার দায়িত্ব), Action (কী করলেন), Result (ফল)।
| অংশ | কী বলবেন | “দোকানদার”-এর উদাহরণ |
|---|---|---|
| ৩০ সেকেন্ডের পরিচয় | কী সমস্যা, কার জন্য, কোন প্রযুক্তি | “ছোট দোকানের stock আর অর্ডারের backend — Java 21, Spring Boot, PostgreSQL.” |
| একটি নকশার সিদ্ধান্ত | কী বেছে নিয়েছেন, কেন, বিকল্প কী ছিল | “টাকা double-এ নয়, পয়সায় long-এ — কারণ 0.1 + 0.2 ঠিক 0.3 হয় না।” |
| একটি কঠিন সমস্যা | কী ভাঙছিল, কীভাবে ধরলেন, কীভাবে সারালেন | “শেষ পিসটি দুজন একসাথে কিনতে পারত — শর্তযুক্ত UPDATE আর টেস্ট দিয়ে ঠিক করেছি।” |
| প্রমাণ | টেস্ট, README, ছোট demo | “core-এর টেস্ট Spring ছাড়াই চলে; README-তে সিদ্ধান্তের কারণ লেখা।” |
| আবার করলে | কী ভিন্নভাবে করতেন | “শুরুতেই idempotency key রাখতাম — পরে যোগ করতে বেশি কাজ লেগেছে।” |
প্রজেক্টের যে অংশ আপনি নিজে বোঝেন না — হয়তো AI বা বন্ধু লিখে দিয়েছে — সেটি নিয়ে বড় দাবি করবেন না। পরীক্ষকেরা প্রায়ই ঠিক সেই লাইন ধরে জিজ্ঞেস করেন: “এখানে synchronized কেন?”, “এই query-তে index আছে?” নিজের প্রজেক্টের প্রতিটি সিদ্ধান্তের কারণ নিজের ভাষায় বলতে পারা — এটাই সবচেয়ে বড় প্রস্তুতি।
প্রজেক্ট নিয়ে সাধারণত যে ফলো-আপ আসে: সবচেয়ে কঠিন অংশ কোনটি ছিল? ব্যবহারকারী দশগুণ হলে কী ভাঙবে? কীভাবে টেস্ট করেছেন? ভুল ইনপুট এলে কী হয়? দলে কাজ করলে আপনার অংশ কোনটি? প্রতিটির জন্য দুই–তিন বাক্যের উত্তর আগে থেকে ভেবে রাখুন।
৯ · ভাইভা কুইকফায়ার — ৬৮টি প্রশ্ন ও ফলো-আপ
ভাইভায় প্রশ্ন আসে দ্রুত, উত্তরও হতে হয় এক–তিন বাক্যে। জোরে জোরে উত্তর বলুন, তারপর মেলান — প্রতিটিতে ২০ সেকেন্ডের বেশি নয়। “ফলো-আপ” লেখা প্রশ্নগুলো আগের প্রশ্নের উত্তর থেকে জন্মানো; এগুলো পরপর পড়ুন, যেন একজন পরীক্ষক আপনাকে জেরা করছেন।
ভিত্তি ও মূল ভাষা (পর্ব ০১–১৩)
রিভিশনের জন্য: পর্ব ০১, পর্ব ০৪, পর্ব ০৫, পর্ব ০৬, পর্ব ০৭, পর্ব ০৮, পর্ব ১০, পর্ব ১৩.
ভ-০১Java কে, কবে বানিয়েছেন? (সহজ)
Sun Microsystems-এ James Gosling-এর নেতৃত্বে একটি দল ১৯৯১ সালে কাজ শুরু করে; প্রথম নাম ছিল Oak. ১৯৯৫ সালে Java নামে প্রকাশ্যে আসে। ২০১০ সালে Oracle, Sun-কে কিনে নেয়। পর্ব ০১
ভ-০২Java কি পুরোপুরি (pure) object-oriented? (মাঝারি)
না। int, double-এর মতো primitive type object নয়, আর static method কোনো object ছাড়াই চলে। তবে Java-তে সব কোড কোনো না কোনো class-এর ভেতরে থাকে। পর্ব ০৬
ভ-০৩main কেন public static void? (সহজ)
public — JVM বাইরে থেকে ডাকে; static — কোনো object বানানোর আগেই ডাকতে হয়; void — কিছু ফেরত দেয় না (exit code লাগলে System.exit). String[] args-এ আসে command-line argument. পর্ব ০৪
ভ-০৪ফলো-আপ: main overload করা যায়? (মাঝারি)
যায় — যেকোনো method-এর মতো। কিন্তু প্রোগ্রাম শুরু করতে JVM শুধু public static void main(String[] args) রূপটিই খোঁজে; বাকিগুলো সাধারণ method, নিজে ডাকতে হয়। পর্ব ০৪
ভ-০৫JIT compiler কী করে? (সহজ)
যে method বারবার চলে, চলার সময় তাকে native machine code-এ compile করে, যাতে পরের ডাকগুলো দ্রুত হয়। তাই Java প্রোগ্রাম কিছুক্ষণ চলার পর গতি পায় (warm-up). পর্ব ০৫
ভ-০৬Java-তে int কত বিটের? char? (সহজ)
int সবসময় ৩২-bit, যেকোনো platform-এ — C-এর মতো compiler-নির্ভর নয়। long ৬৪-bit, আর char ১৬-bit unsigned — একটি UTF-16 code unit. পর্ব ০৬
ভ-০৭var কি Java-কে dynamic typed বানায়? (মাঝারি)
না। var (Java 10) শুধু local ভ্যারিয়েবলের টাইপ ডান দিক দেখে compile-এর সময় বের করে (type inference); টাইপ তারপর স্থির। field বা parameter-এ var চলে না। পর্ব ০৬
ভ-০৮Integer a = 128, b = 128; হলে a == b কী? (মাঝারি)
ডিফল্ট সেটিংসে false — Integer cache শুধু −128 থেকে 127; 128-এ দুটি আলাদা object. a.equals(b) true. 127 হলে ==-ও true হতো। পর্ব ০৬
ভ-০৯0.1 + 0.2 == 0.3 কেন false? (মাঝারি)
double binary floating point; 0.1 বাইনারিতে ঠিকঠাক লেখা যায় না, তাই যোগফল ছাপে 0.30000000000000004. টাকার হিসাবে BigDecimal বা পয়সায় long; double তুলনায় একটি ছোট সহনসীমা (epsilon). পর্ব ০৭
ভ-১০10 / 0 আর 10.0 / 0-এর ফল কী? (মাঝারি)
পূর্ণসংখ্যায় ArithmeticException: / by zero; floating point-এ কোনো exception নেই — ফল Infinity (আর 0.0 / 0 হলে NaN). পর্ব ০৭
ভ-১১&& আর &-এর পার্থক্য? (সহজ)
&& short-circuit — বাঁ দিক false হলে ডান দিক চালায়ই না; তাই s != null && s.isEmpty() নিরাপদ। & boolean-এ দুই দিকই চালায়, আর পূর্ণসংখ্যায় bitwise AND. পর্ব ০৭
ভ-১২Switch expression পুরোনো switch থেকে কীভাবে আলাদা? (সহজ)
Java 14-এ স্থায়ী switch expression একটি মান ফেরত দেয়, case X -> লেখায় fall-through নেই বলে break লাগে না, আর enum বা sealed টাইপে সব case না ধরলে compiler জানায়। block থেকে মান দিতে yield. পর্ব ১০
ভ-১৩s.toUpperCase(); লিখলে s কি বদলায়? (সহজ)
না — String immutable; method নতুন String ফেরত দেয়, যা এখানে হারিয়ে গেল। লিখতে হবে s = s.toUpperCase();. নতুনদের খুব সাধারণ ভুল। পর্ব ০৮
ভ-১৪Array, String আর List-এর দৈর্ঘ্য কীভাবে পান? (সহজ)
Array-তে field arr.length, String-এ method s.length(), collection-এ list.size(). খাতায় তিনটি গুলিয়ে ফেলা খুব প্রচলিত ভুল। পর্ব ১৩
অবজেক্ট-ওরিয়েন্টেড Java (পর্ব ১৫–২২)
রিভিশনের জন্য: পর্ব ১৫, পর্ব ১৬, পর্ব ১৮, পর্ব ১৯, পর্ব ২০, পর্ব ২১.
ভ-১৫Class আর object-এর পার্থক্য এক লাইনে? (সহজ)
Class নকশা, object সেই নকশা থেকে new দিয়ে বানানো আসল নমুনা — যেমন বাড়ির নকশা আর আসল বাড়ি। একটি class থেকে অনেক object. পর্ব ১৫
ভ-১৬this কী? (সহজ)
বর্তমান object-এর reference. field আর parameter-এর নাম এক হলে আলাদা করতে (this.name = name), আর this(…) দিয়ে একই class-এর আরেকটি constructor ডাকতে। static method-এ this নেই। পর্ব ১৬
ভ-১৭Constructor কি private হতে পারে? কেন করবেন? (মাঝারি)
পারে। বাইরে থেকে new বন্ধ করতে — singleton, শুধু static method-ওয়ালা utility class, বা of(…)-এর মতো static factory method দিয়ে object বানাতে। পর্ব ১৬
ভ-১৮ফলো-আপ: constructor কি final, static বা abstract হতে পারে? (মাঝারি)
না। constructor inherit হয় না, তাই override-এর প্রশ্নই ওঠে না — final/abstract অর্থহীন; আর এর কাজই একটি object গড়া, তাই static-ও অর্থহীন। লিখলে compile error. পর্ব ১৬
ভ-১৯Static method কি override করা যায়? (মাঝারি)
ভ-২০super কী কাজে লাগে? (সহজ)
parent class-এর constructor ডাকতে (super(…), অবশ্যই প্রথম লাইনে), আর override করা method-এর parent সংস্করণ ডাকতে (super.describe())। না লিখলে compiler নিজে super() বসায়। পর্ব ১৯
ভ-২১Java-তে multiple inheritance আছে? (সহজ)
Class-এ নেই — একটি class একটিই class extend করে। interface অনেকগুলো implement করা যায়, তাই টাইপের multiple inheritance আছে। কারণ diamond problem এড়ানো (খ-০৭)। পর্ব ১৯
ভ-২২Dynamic dispatch কী? (মাঝারি)
চলার সময় object-এর আসল টাইপ দেখে override করা method বাছাই। Animal a = new Dog(); a.sound(); — ঘোষিত টাইপ Animal, কিন্তু চলে Dog-এর sound(). Java-তে non-static, non-private, non-final method ডিফল্টভাবেই এভাবে চলে। পর্ব ২০
ভ-২৩ফলো-আপ: field-ও কি এভাবে polymorphic? (কঠিন)
না। parent আর child-এ একই নামের field থাকলে a.name ঘোষিত টাইপ (Animal)-এর field পড়ে — field hiding. শুধু instance method dynamic dispatch পায়; তাই field private রেখে method দিয়ে পড়াই নিরাপদ। পর্ব ২০
ভ-২৪Abstract class-এর object বানানো যায় না, তবু constructor থাকে কেন? (মাঝারি)
subclass-এর object তৈরির সময় super(…) দিয়ে abstract parent-এর constructor চলে আর parent-এর অংশের field (যেমন name) initialize করে। নিয়মটা এক জায়গায় থাকে, প্রতিটি subclass-এ আলাদা লিখতে হয় না। পর্ব ২১
ভ-২৫Interface-এ ভ্যারিয়েবল রাখা যায়? (সহজ)
শুধু constant — interface-এর প্রতিটি field আপনাআপনি public static final. instance state রাখা যায় না; এটাই abstract class থেকে মূল পার্থক্য। পর্ব ২১
ভ-২৬Marker interface কী? (মাঝারি)
কোনো method নেই এমন interface, যা শুধু একটি চিহ্ন দেয় — যেমন Serializable, Cloneable, RandomAccess. আজকাল এমন তথ্য দিতে বেশিরভাগ ক্ষেত্রে annotation ব্যবহার হয়। পর্ব ২১
ভ-২৭Upcasting আর downcasting-এর পার্থক্য? (মাঝারি)
Upcasting (child → parent) আপনাআপনি ও নিরাপদ। Downcasting (parent → child) লিখে করতে হয়, আর object আসলে সেই টাইপের না হলে ClassCastException. আগে if (a instanceof Dog d) দিয়ে যাচাই করুন। পর্ব ২০
ভ-২৮JDK-র একটি final class-এর নাম বলুন। কেন final? (সহজ)
String (আর Integer-এর মতো wrapper). কেউ subclass বানিয়ে আচরণ বদলাতে পারলে immutability আর নিরাপত্তার নিশ্চয়তা ভেঙে যেত। পর্ব ১৮
আধুনিক টাইপ ও ভুল সামলানো (পর্ব ২৩–২৯)
রিভিশনের জন্য: পর্ব ২৩, পর্ব ২৪, পর্ব ২৫, পর্ব ২৬, পর্ব ২৭, পর্ব ২৮, পর্ব ২৯.
ভ-২৯toString() override না করলে println(obj) কী ছাপে? (সহজ)
class-এর নাম, @, আর hashCode-এর hexadecimal রূপ — যেমন Point@1b6d3586. সংখ্যাটি চালানো থেকে চালানোয় বদলাতে পারে, তাই এর ওপর নির্ভর করবেন না। record-এ toString আপনাআপনি সুন্দর। পর্ব ২৩
ভ-৩০দুটি object-এর hashCode সমান হলে কি তারা equals-এ সমান? (মাঝারি)
না, জরুরি নয় — আলাদা object-এর hash মিলতে পারে (collision). চুক্তিটি উল্টো দিকে: equals সমান হলে hashCode সমান হতেই হবে। পর্ব ২৩
ভ-৩১Enum কি অন্য class extend করতে পারে? (মাঝারি)
না — প্রতিটি enum আপনাআপনি java.lang.Enum extend করে, আর Java-তে একটিই parent. তবে enum interface implement করতে পারে, আর প্রতিটি মানের আলাদা method body থাকতে পারে। পর্ব ২৪
ভ-৩২Record-এ setter লেখা যায়? (সহজ)
অর্থপূর্ণভাবে না — record-এর field final, তাই বদলানো যায় না। বদলানো মান চাইলে নতুন record ফেরত দেয় এমন method লিখুন: Money plus(Money o) { return new Money(paisa + o.paisa); }. পর্ব ২৫
ভ-৩৩Sealed class-এর অনুমোদিত subclass-কে কী হতে হয়? (কঠিন)
তিনটির একটি: final (আর extend হবে না), sealed (নিজেও সীমিত তালিকা দেবে), বা non-sealed (আবার সবার জন্য খোলা)। record আপনাআপনি final; enum-ও আপনাআপনি final (constant-এর নিজস্ব body থাকলে sealed). পর্ব ২৬
ভ-৩৪Inner class আর static nested class-এর পার্থক্য? (মাঝারি)
Inner class-এর প্রতিটি object বাইরের class-এর একটি object-এর লুকানো reference রাখে, তাই বাইরের object ছাড়া বানানো যায় না। Static nested class-এ সেই reference নেই। বাইরের object-এর দরকার না হলে static nested — লুকানো reference memory leak-এর কারণ হতে পারে। পর্ব ২৭
ভ-৩৫List<Object> parameter-এ List<String> পাঠানো যায়? (কঠিন)
না — generics invariant. যেত হলে method-টি সেই তালিকায় একটি Integer ঢুকিয়ে String-এর তালিকা নষ্ট করতে পারত। শুধু পড়ার জন্য নিতে লিখুন List<?> বা List<? extends Object>. পর্ব ২৮
ভ-৩৬try-তে return থাকলে finally চলে? (মাঝারি)
চলে — return-এর মান ঠিক হওয়ার পর, method থেকে বের হওয়ার আগে। finally-তে আবার return লিখলে সেটি try-এর return আর যেকোনো exception — দুটোকেই ঢেকে দেয়, তাই কখনো লিখবেন না। পর্ব ২৯
ভ-৩৭ফলো-আপ: finally কখন চলে না? (মাঝারি)
System.exit() ডাকলে, JVM হঠাৎ বন্ধ বা crash হলে, বা try-এর ভেতরের thread চিরকাল আটকে থাকলে। সাধারণ exception বা return-এ চলে। পর্ব ২৯
ভ-৩৮Multi-catch কী? এর একটি নিয়ম বলুন। (মাঝারি)
Java 7 থেকে এক catch-এ কয়েকটি টাইপ: catch (IOException | SQLException e). নিয়ম: টাইপগুলো একে অপরের subclass হতে পারবে না (তাহলে compile error), আর e আপনাআপনি final. পর্ব ২৯
Collections ও functional Java (পর্ব ৩০–৩৬)
রিভিশনের জন্য: পর্ব ৩০, পর্ব ৩১, পর্ব ৩২, পর্ব ৩৪, পর্ব ৩৫.
ভ-৩৯Collection আর Collections-এর পার্থক্য? (সহজ)
Collection একটি interface — List, Set, Queue-এর মূল। Collections একটি utility class, যাতে sort, reverse, max, unmodifiableList-এর মতো static method. পর্ব ৩০
ভ-৪০List, Set আর Map — এক লাইনে করে? (সহজ)
List — ক্রম আছে, সূচক আছে, ডুপ্লিকেট চলে। Set — ডুপ্লিকেট নেই। Map — key থেকে value, key অনন্য; Map Collection-এর অংশ নয়। পর্ব ৩১
ভ-৪১HashSet ভেতরে কী দিয়ে বানানো? (মাঝারি)
একটি HashMap দিয়ে — set-এর প্রতিটি উপাদান map-এর key, আর value একটি স্থির dummy object. তাই HashSet-এর নিয়ম (hashCode + equals, ক্রম নিশ্চিত নয়) HashMap-এর মতোই। পর্ব ৩১
ভ-৪২Fail-fast iterator কী? (মাঝারি)
iteration চলার সময় collection সরাসরি বদলালে (যেমন for-each-এর ভেতরে list.remove) পরের ধাপে ConcurrentModificationException ছোড়ে। এটি সর্বোচ্চ চেষ্টা, নিশ্চয়তা নয় — কিছু ক্ষেত্রে ধরা পড়ে না। সমাধান iterator.remove() বা removeIf. পর্ব ৩০
ভ-৪৩ফলো-আপ: ConcurrentHashMap-এর iterator-ও কি exception ছোড়ে? (কঠিন)
না — এর iterator weakly consistent: iteration-এর সময় অন্য thread বদলালেও exception নেই; কিছু বদল দেখা যেতে পারে, কিছু না-ও। তাই একাধিক thread-এ নিরাপদ, কিন্তু “এক মুহূর্তের নিখুঁত ছবি” নয়। পর্ব ৩১
ভ-৪৪List.of(…) আর Arrays.asList(…)-এর পার্থক্য? (মাঝারি)
List.of (Java 9) পুরোপুরি unmodifiable — add, remove, set সবেই UnsupportedOperationException, আর null নেয় না। Arrays.asList fixed-size — set চলে কিন্তু add/remove চলে না, আর পেছনের array-র সাথে যুক্ত। পর্ব ৩০
ভ-৪৫PriorityQueue কীভাবে কাজ করে? (মাঝারি)
ভেতরে একটি binary heap; ডিফল্টে সবচেয়ে ছোট উপাদান মাথায় (min-heap). offer/poll O(log n), peek O(1). ফাঁদ: for-each বা toString সাজানো ক্রমে দেখায় না — শুধু বারবার poll করলে সাজানো ক্রম পাবেন। পর্ব ৩২
ভ-৪৬java.util.function-এর চারটি মূল functional interface? (সহজ)
Predicate<T> — T নেয়, boolean দেয়; Function<T,R> — T নেয়, R দেয়; Consumer<T> — নেয়, কিছু দেয় না; Supplier<T> — কিছু নেয় না, T দেয়। পর্ব ৩৪
ভ-৪৭একটি stream কি দুবার ব্যবহার করা যায়? (সহজ)
না — terminal operation-এর পর stream শেষ; আবার ব্যবহার করলে IllegalStateException. দরকার হলে উৎস (list) থেকে নতুন stream বানান। পর্ব ৩৫
ভ-৪৮map আর flatMap-এর পার্থক্য? (মাঝারি)
map প্রতিটি উপাদানকে একটি উপাদানে বদলায়। flatMap প্রতিটি উপাদান থেকে একটি stream বানিয়ে সবগুলো এক stream-এ চ্যাপ্টা করে — যেমন বাক্যের তালিকা থেকে সব শব্দের এক তালিকা। পর্ব ৩৫
সিস্টেম, JVM আর পেশাদার Java (পর্ব ৩৭–৫৫)
রিভিশনের জন্য: পর্ব ৩৯, পর্ব ৪০, পর্ব ৪১, পর্ব ৪৪, পর্ব ৪৫, পর্ব ৪৩, পর্ব ৪৬, পর্ব ৪৯, পর্ব ৫০, পর্ব ৫২, পর্ব ৫৩.
ভ-৪৯Java-তে thread বানানোর উপায়গুলো? (সহজ)
Thread extend করা, Runnable দিয়ে new Thread(task), ফল লাগলে Callable + ExecutorService, আর Java 21-এ virtual thread. বাস্তবে সরাসরি thread নয়, executor-এ কাজ জমা দেওয়াই প্রচলিত। পর্ব ৪০
ভ-৫০start() আর run()-এর পার্থক্য? (সহজ)
start() নতুন thread তৈরি করে, আর সেই thread-এ run() চলে। সরাসরি run() ডাকলে নতুন thread হয় না — বর্তমান thread-এই সাধারণ method-এর মতো চলে। একই Thread-এ দুবার start() করলে IllegalThreadStateException. পর্ব ৪০
ভ-৫১Deadlock কী? এড়াবেন কীভাবে? (মাঝারি)
দুই বা ততোধিক thread একে অপরের ধরে রাখা lock-এর জন্য চিরকাল অপেক্ষা করে — T1 ধরেছে A, চায় B; T2 ধরেছে B, চায় A. সমাধান: সব জায়গায় একই ক্রমে lock নেওয়া (lock ordering), বা tryLock সময়সীমাসহ। পর্ব ৪০
ভ-৫২wait() আর sleep()-এর পার্থক্য? (মাঝারি)
wait() Object-এর method, synchronized-এর ভেতরেই ডাকতে হয়, আর অপেক্ষার সময় lock ছেড়ে দেয়। Thread.sleep() static, কোনো lock ছাড়ে না — শুধু সময় পার করে। আধুনিক কোডে দুটির বদলে প্রায়ই BlockingQueue বা CountDownLatch. পর্ব ৪০
ভ-৫৩সরাসরি thread না বানিয়ে ExecutorService কেন? (সহজ)
thread আবার ব্যবহার হয় (তৈরির খরচ বাঁচে), একসাথে কতগুলো চলবে তার সীমা থাকে, আর Future দিয়ে ফল ও exception পাওয়া যায়। শেষে shutdown() বা try-with-resources ভুলবেন না। পর্ব ৪১
ভ-৫৪CompletableFuture কী? (মাঝারি)
ভবিষ্যতে আসবে এমন একটি ফল, যার পরে কী হবে তা আগেই জুড়ে রাখা যায়: thenApply (ফল বদলানো), thenCompose (আরেকটি async কাজ), thenCombine (দুটি ফল মেলানো), exceptionally (ভুল সামলানো)। পর্ব ৪১
ভ-৫৫GC থাকলেও Java-তে memory leak হয়? (মাঝারি)
হয়। GC শুধু পৌঁছানো যায় না এমন object সরায়; অপ্রয়োজনীয় object-এর reference কোথাও রয়ে গেলে সে থেকে যায় — যেমন static collection-এ জমতে থাকা ডেটা, সরানো হয়নি এমন listener, বা thread pool-এ পরিষ্কার না করা ThreadLocal. পর্ব ৪৪
ভ-৫৬Serialization কী? transient কী করে? (মাঝারি)
Serialization হলো object-কে byte বা লেখায় (যেমন JSON) রূপান্তর, যাতে ফাইলে রাখা বা নেটওয়ার্কে পাঠানো যায়। transient field Java-র নিজস্ব serialization-এ বাদ পড়ে — যেমন পাসওয়ার্ড বা cache. অবিশ্বস্ত উৎসের ডেটা Java native deserialization-এ পড়া নিরাপত্তার বড় ঝুঁকি; আজ JSON বেশি প্রচলিত। পর্ব ৩৯
ভ-৫৭Reflection কী? এর ঝুঁকি কী? (মাঝারি)
চলার সময় একটি class-এর field, method, annotation দেখা আর ডাকা — Spring, JUnit, Jackson এভাবেই কাজ করে। ঝুঁকি: সাধারণ ডাকের চেয়ে ধীর, compile-time যাচাই হারায়, আর private ভেঙে encapsulation নষ্ট করতে পারে। পর্ব ৪৫
ভ-৫৮Maven আর Gradle — এক লাইনে পার্থক্য? (সহজ)
দুটিই build tool — dependency নামানো, compile, test, প্যাকেজ। Maven XML (pom.xml) আর নির্দিষ্ট lifecycle মানে; Gradle Kotlin বা Groovy DSL-এ লেখা, বেশি নমনীয়, আর incremental build-এ সাধারণত দ্রুত। পর্ব ৪৬
ভ-৫৯@SpringBootApplication আসলে কী? (মাঝারি)
তিনটি annotation একসাথে: @Configuration (bean-এর উৎস), @EnableAutoConfiguration (classpath দেখে ডিফল্ট সেটআপ) আর @ComponentScan (এই package ও নিচের package-এ component খোঁজা)। পর্ব ৫০
ভ-৬০Transaction-এর ACID কী? JDBC-তে কীভাবে transaction করবেন? (মাঝারি)
ACID — Atomicity (সব নয়তো কিছুই না), Consistency (নিয়ম ভাঙে না), Isolation (একসাথে চলা transaction একে অপরকে নষ্ট করে না), Durability (commit হলে টিকে থাকে)। JDBC-তে conn.setAutoCommit(false), কাজ শেষে commit(), ভুল হলে rollback(). পর্ব ৪৯
ভ-৬১TCP আর UDP — মূল পার্থক্য কী? (সহজ)
TCP সংযোগভিত্তিক, নির্ভরযোগ্য, ক্রম-ঠিক byte-স্রোত — কিন্তু message-এর সীমানা রাখে না, তাই framing নিজে করতে হয়। UDP সংযোগহীন; প্রতিটি datagram আলাদা message, তবে হারাতে বা উল্টো ক্রমে আসতে পারে। ফলো-আপ: “DNS বা ভিডিও কল কেন UDP?” — দেরিতে আসা ডেটা না আসার সমান, আর handshake-এর খরচ নেই। পর্ব ৪৩
ভ-৬২Socket-এ timeout কেন দেবেন, আর কয় রকম? (মাঝারি)
ডিফল্টে timeout নেই — মরা সংযোগে read() চিরকাল আটকে থাকে আর thread নষ্ট হয়। connect timeout (connect(address, ms)), প্রতি-পড়ার timeout (setSoTimeout, পার হলে SocketTimeoutException), আর পুরো request-এর মোট সময়সীমা। HttpClient-এও connectTimeout আর request-এর timeout নিজে দিতে হয়; তার redirect নীতিও ডিফল্টে NEVER. পর্ব ৪৩
ভ-৬৩JPA আর Hibernate-এর পার্থক্য? (সহজ)
JPA (এখন Jakarta Persistence) একটি মানক API — annotation, EntityManager, JPQL; নিজে কোনো SQL চালায় না। Hibernate সেই API-র সবচেয়ে প্রচলিত বাস্তবায়ন; আরেকটি বাস্তবায়নের নাম EclipseLink. Spring Data JPA তার ওপর interface থেকে repository বানায়। পর্ব ৫২
ভ-৬৪LAZY আর EAGER loading — ডিফল্ট কোথায় কী? LazyInitializationException কেন হয়? (মাঝারি)
@ManyToOne/@OneToOne ডিফল্টে EAGER, @OneToMany/@ManyToMany LAZY; পরামর্শ — সব LAZY, দরকারি জায়গায় join fetch বা @EntityGraph. LAZY proxy নিজের ডেটা আনতে খোলা persistence context চায়; transaction শেষ হওয়ার পর (যেমন controller-এ) ছুঁলে “no Session” — এই exception. সমাধান EAGER নয়, service-এর ভেতরেই দরকারি ডেটা এনে DTO বানানো। পর্ব ৫২
ভ-৬৫@Transactional থাকলেও কখন rollback হয় না, বা transaction-ই শুরু হয় না? (মাঝারি)
ডিফল্টে শুধু unchecked exception (RuntimeException, Error)-এ rollback; checked exception-এ commit — দরকারে rollbackFor = Exception.class. Spring proxy দিয়ে কাজ করে, তাই একই class-এর ভেতর থেকে ডাকলে (self-invocation) বা private method-এ annotation নীরবে উপেক্ষিত। ফলো-আপ: “দুজন একসাথে একই স্টক বদলালে?” — @Version দিয়ে optimistic locking; দ্বিতীয় জন OptimisticLockException পায়। পর্ব ৫২
ভ-৬৬401 আর 403-এর পার্থক্য? (সহজ)
401 Unauthorized মানে authentication ব্যর্থ — পরিচয় জানা যায়নি (token নেই, ভুল বা মেয়াদোত্তীর্ণ)। 403 Forbidden মানে পরিচয় জানা, কিন্তু এই কাজের অনুমতি নেই (authorization ব্যর্থ)। অন্যের ডেটা চাইলে অনেক API 404 দেয়, যাতে ডেটাটির অস্তিত্বই ফাঁস না হয়। পর্ব ৫৩
ভ-৬৭JWT কী? এটা কি এনক্রিপ্ট করা? (মাঝারি)
JSON Web Token (RFC 7519) — header.payload.signature, তিনটি অংশ Base64URL-এ। payload-এ claim (sub, exp, role…) থাকে, আর স্বাক্ষর গোপন key দিয়ে বানানো। এনক্রিপ্ট নয় — যে কেউ পড়তে পারে, তাই গোপন তথ্য রাখা চলে না; কিন্তু key ছাড়া বদলালে স্বাক্ষর মেলে না। মেয়াদ ছোট রাখুন, key কোডের বাইরে, যাচাইয়ে প্রতিষ্ঠিত লাইব্রেরি — Spring-এ OAuth2 Resource Server. পর্ব ৫৩
ভ-৬৮CSRF কী, আর কখন এর সুরক্ষা লাগে? (মাঝারি)
Cross-Site Request Forgery — লগইন করা অবস্থায় অন্য সাইটের পাতা ব্যবহারকারীর অজান্তে আপনার সাইটে অবস্থা-বদলানো request পাঠায়, আর ব্রাউজার session cookie নিজে থেকে জুড়ে দেয়। cookie-ভিত্তিক লগইনে CSRF token (আর SameSite cookie) লাগে; শুধু Authorization header-এ token পাঠানো stateless API-তে ঝুঁকি নেই, তাই সেখানে বন্ধ রাখা চলে — কিন্তু শুধু এই কারণেই। পর্ব ৫৩
পরীক্ষকেরা সাধারণত যে ফলো-আপ করেন
প্রথম প্রশ্নের উত্তর দেওয়ার সময়ই পরের প্রশ্নের জন্য প্রস্তুত থাকুন। নিচের শিকলগুলো ভাইভা আর ইন্টারভিউতে খুব প্রচলিত:
| প্রথম প্রশ্ন | সাধারণ ফলো-আপ | কোথায় দেখবেন |
|---|---|---|
| String immutable কেন? | String pool কোথায় থাকে? new String("a") কয়টি object বানায়? লুপে জোড়া কেন ধীর? | ক-০৪, গ-০১ |
| equals কী? | hashCode-এর সাথে চুক্তি কী? শুধু equals override করলে HashSet-এ কী হয়? | গ-০১ |
| abstract class বনাম interface? | Java 8-এর default method কেন এলো? দুটি interface-এ একই default থাকলে? | খ-০৬, খ-০৭ |
| checked বনাম unchecked? | নিজের exception কোনটা থেকে বানাবেন? exception গিলে ফেলা কেন খারাপ? | গ-০৬, গ-০৮ |
| ArrayList বনাম LinkedList? | ArrayList কীভাবে বড় হয়? amortized O(1) মানে কী? queue-র জন্য কোনটি? | অংশ ২, ঘ-০১ |
| synchronized কী? | volatile দিয়ে counter কেন হয় না? deadlock কীভাবে হয়? | ঙ-০২, ভ-৫১ |
| virtual thread কী? | CPU-ভারী কাজে লাভ আছে? pinning কী? pool কেন করা হয় না? | ঙ-০৪ |
| PreparedStatement কেন? | SQL injection-এর একটি উদাহরণ দিন। table-এর নাম কি ? দিয়ে দেওয়া যায়? | ঙ-০৬ |
১০ · AI-কে ভাইভা পরীক্ষক বানান — আর তাকে যাচাই করুন
ভাইভা অনুশীলনের সবচেয়ে বড় সমস্যা হলো প্রশ্ন করার মানুষ না থাকা। AI এখানে কাজের সঙ্গী — ক্লান্ত হয় না, যেকোনো সময় প্রস্তুত, আর আপনার উত্তর থেকে follow-up প্রশ্ন বানাতে পারে। কিন্তু নিজে থেকে AI প্রায়ই খুব নরম পরীক্ষক — সব উত্তরেই প্রশংসা করে। আর Java-র সংস্করণভিত্তিক তথ্যে (কোন বৈশিষ্ট্য কোন সংস্করণে স্থায়ী, কোনটি এখনো preview) বা সূক্ষ্ম আচরণে (Integer cache, HashMap-এর ক্রম, thread-এর আউটপুট) AI-ও আত্মবিশ্বাসের সাথে ভুল বলতে পারে। তাই তাকে স্পষ্ট নিয়ম দিন, আর প্রতিটি দাবি যাচাই করুন।
নিচের prompt-টি কপি করে যেকোনো AI চ্যাটে দিন। বিষয়ের জায়গায় যে মডিউল ঝালাতে চান সেটি লিখুন:
লিখিত উত্তরের জন্য খাতার উত্তর টাইপ করে দিন এবং বলুন: “এটি একটি পার্থক্যের প্রশ্নের উত্তর। পরীক্ষক হিসেবে নম্বর দাও, আর সংজ্ঞা, টেবিল, উদাহরণ, উপসংহার — কোন অংশ দুর্বল বলো; কিন্তু পুরো উত্তর নতুন করে লিখে দিও না।” শেষ শর্তটি জরুরি — নইলে আপনি শিখবেন না, শুধু আরেকটি উত্তর মুখস্থ করবেন। নিজের প্রজেক্ট নিয়েও একই কাজ করুন: README দিয়ে বলুন “এই প্রজেক্ট নিয়ে আমাকে পাঁচটি কঠিন ভাইভা প্রশ্ন করো” — তবে কোডে কোনো পাসওয়ার্ড বা API key থাকলে আগে সরিয়ে নিন।
Java নিয়ে AI-এর উত্তরে যেসব ভুল প্রায়ই থাকে
| AI যা বলে বা লেখে | আসল সত্য |
|---|---|
| “Java object-এর ক্ষেত্রে pass-by-reference” | সবসময় pass-by-value; reference-এর কপি যায় (ক-০৫) |
| “HashMap ঢোকানোর ক্রম রাখে” বা নির্দিষ্ট ক্রমের আউটপুট দেখানো | ক্রম নিশ্চিত নয়; LinkedHashMap বা TreeMap (ঘ-০২) |
| “volatile দিয়ে counter thread-safe” | volatile atomicity দেয় না; AtomicInteger বা lock (ঙ-০২) |
| “interface-এ কোনো method body থাকতে পারে না” | Java 8 থেকে default ও static, Java 9 থেকে private (খ-০৬) |
| “virtual thread সব কাজ দ্রুত করে” | অপেক্ষা সস্তা করে; CPU-ভারী কাজে লাভ নেই (ঙ-০৪) |
| preview বৈশিষ্ট্যকে (যেমন String template) স্থায়ী বলা | সংস্করণ মিলিয়ে নিন; preview চালাতে --enable-preview লাগে, আর পরে বদলাতে বা বাদ পড়তে পারে — String template Java 21–22-এ preview ছিল, পরে তুলে নেওয়া হয় |
কোডে raw type (List list = new ArrayList();), টাকায় double | generics দিন; টাকা পয়সায় long বা BigDecimal |
AI-এর উত্তর যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
এগুলো মুখস্থের প্রশ্ন নয় — পরীক্ষা আর শেখা নিয়ে একটু থেমে ভাবার প্রশ্ন। নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।
প্র ০১প্রায় সব Java ভাইভা OOP-এর চার স্তম্ভ দিয়ে শুরু হয় কেন? প্রশ্নটি আসলে কী যাচাই করে?
ইতিহাস দিয়ে শুরু করা যাক। Object-ভিত্তিক চিন্তার প্রথম ভাষা ধরা হয় Simula 67-কে, যা নরওয়েতে Ole-Johan Dahl আর Kristen Nygaard বানিয়েছিলেন — মূলত বাস্তব জগতের simulation লেখার জন্য। সেখান থেকেই class আর object-এর ধারণা। ১৯৭০-এর দশকে Xerox PARC-এ Alan Kay-এর দল Smalltalk বানায়, আর “object-oriented” নামটি Alan Kay-এর মুখেই জনপ্রিয় হয়। কিন্তু OOP মূলধারায় আসে ১৯৮০–৯০-এর দশকে C++ আর বিশেষ করে ১৯৯৫ সালের Java-র হাত ধরে — Java-তে প্রতিটি লাইন কোনো না কোনো class-এর ভেতরে লিখতে হয়। ফলে Java শেখানো মানেই OOP শেখানো, আর পরীক্ষাও সেই পথে গেছে।
মজার ব্যাপার হলো, “চারটি স্তম্ভ” কোনো আনুষ্ঠানিক সংজ্ঞা নয়। Alan Kay নিজে OOP-কে বর্ণনা করেছিলেন মূলত message পাঠানো, ভেতরের অবস্থা লুকানো আর দেরিতে সিদ্ধান্ত নেওয়া (late binding) হিসেবে। চারটি স্তম্ভের তালিকা পাঠ্যবইয়ের একটি সুবিধাজনক ভাগ — কেউ তিনটি বলেন (abstraction বাদ দিয়ে), কেউ পাঁচটি।
তাহলে পরীক্ষকেরা এটি জিজ্ঞেস করেন কেন? কারণ প্রশ্নটি সহজে শুরু হয়, কিন্তু যত গভীরে ইচ্ছা যাওয়া যায়। “encapsulation কী?” — সবাই বলতে পারেন “ডেটা লুকানো”। কিন্তু ফলো-আপ: “getter-setter দিয়ে সব field খুলে দিলে কি encapsulation থাকে?” — এখানেই বোঝা যায় কে মুখস্থ করেছেন আর কে বুঝেছেন। আসল encapsulation মানে object-এর নিয়ম (invariant) রক্ষা করা — balance কখনো ঋণাত্মক হবে না — শুধু private লেখা নয়। একইভাবে polymorphism-এর প্রশ্ন থেকে dynamic dispatch, সেখান থেকে interface নকশা পর্যন্ত যাওয়া যায়।
মূল উপলব্ধি: চার স্তম্ভের প্রশ্ন আসলে একটি দরজা। সংজ্ঞা মুখস্থ বললে দরজা খোলে, কিন্তু ভেতরের ঘরগুলো দেখায় বোঝা — নিজের প্রজেক্ট থেকে একটি করে উদাহরণ প্রস্তুত রাখুন।
প্র ০২গভীরতা নাকি বিস্তৃতি — অল্প বিষয় খুব ভালো জানা ভালো, নাকি অনেক বিষয় মোটামুটি?
লিখিত পরীক্ষা আর ভাইভা দুই রকম চাপ দেয়। লিখিত পরীক্ষায় প্রশ্ন আসে পুরো সিলেবাস থেকে, তাই বিস্তৃতি দরকার — কোনো অংশ একেবারে না জানলে সেই প্রশ্নের নম্বর শূন্য। ভাইভায় পরীক্ষক কয়েকটি বিষয় নিয়ে গভীরে যান, তাই গভীরতা দরকার — প্রথম ফলো-আপেই থেমে গেলে বিস্তৃতি কাজে আসে না।
সফটওয়্যার শিল্পে এর একটি প্রচলিত উত্তর “T-shaped” দক্ষতা: অনেক বিষয়ে মোটামুটি পরিচয় (T-এর আনুভূমিক দাগ), আর এক–দুটি বিষয়ে গভীর জ্ঞান (খাড়া দাগ)। Java-র ক্ষেত্রে আনুভূমিক দাগ মানে এই পাতার প্রতিটি অংশ থেকে অন্তত সংজ্ঞা আর একটি উদাহরণ বলতে পারা। খাড়া দাগ মানে এক–দুটি বিষয় — ধরা যাক collections আর concurrency — এত ভালো জানা যে পাঁচটি ফলো-আপের পরেও কথা বলতে পারেন।
শিক্ষা-মনোবিজ্ঞানের একটি পুরোনো পর্যবেক্ষণও এখানে কাজে লাগে: যে জিনিস নিজের পুরোনো জ্ঞানের সাথে জুড়ে শেখা হয়, তা বেশি দিন মনে থাকে। গভীরভাবে জানা একটি বিষয় অন্যগুলোর খুঁটি হয়ে দাঁড়ায় — HashMap ভালো বুঝলে HashSet, equals-hashCode, এমনকি ConcurrentHashMap-ও সহজ লাগে। তাই গভীরতা আর বিস্তৃতি আসলে প্রতিদ্বন্দ্বী নয়।
বাস্তব কৌশল: প্রথম ধাপে বিস্তৃতি — এই পাতার সব লিখিত প্রশ্নের সংজ্ঞা অংশ দ্রুত একবার। দ্বিতীয় ধাপে দুটি বিষয় বেছে নিন যা আপনার পরীক্ষা বা কাজের সাথে সবচেয়ে বেশি মেলে, আর সেগুলোর পর্ব আবার পড়ুন, কোড চালান, ফলো-আপের শিকল নিজে বানান।
মূল উপলব্ধি: সব বিষয়ে “শূন্য নয়”, আর কয়েকটি বিষয়ে “অসাধারণ” — এই মিশ্রণই লিখিত আর মৌখিক দুই পরীক্ষাতেই সবচেয়ে নিরাপদ।
প্র ০৩মডেল উত্তর মুখস্থ করলে সমস্যা কী? নিজের ভাষায় বলতে পারা কেন এত গুরুত্বপূর্ণ?
মুখস্থ উত্তরের সমস্যা ধরা পড়ে প্রথম ফলো-আপেই। ধরা যাক আপনি “abstract class বনাম interface”-এর টেবিল হুবহু মনে রেখেছেন। পরীক্ষক জিজ্ঞেস করলেন: “তাহলে AbstractList কেন আছে, List interface তো আছেই?” টেবিলে এর উত্তর নেই। যিনি বুঝেছেন, তিনি যুক্তি দিয়ে বলবেন: “interface চুক্তি দেয়, আর abstract class সেই চুক্তির ভাগের অংশ একবার লিখে দেয়, যাতে নতুন List বানাতে কম কাজ লাগে।”
পদার্থবিজ্ঞানী Richard Feynman-এর নামে একটি শেখার পদ্ধতি প্রচলিত — “Feynman technique”: একটি ধারণা এমনভাবে ব্যাখ্যা করার চেষ্টা করুন যেন একজন নতুন শিক্ষার্থীকে বোঝাচ্ছেন; যেখানে আটকে যান বা কঠিন শব্দের আড়ালে লুকাতে হয়, সেখানেই আপনার বোঝায় ফাঁক। পদ্ধতিটি তিনি নিজে এই নামে লেখেননি, কিন্তু সহজ ভাষায় ব্যাখ্যা করার প্রতি তাঁর জোর সুপরিচিত।
ভাইভা আসলে এই পরীক্ষাই। পরীক্ষক আপনার মুখের ভাষায় শুনতে চান, আর ভিন্ন দিক থেকে প্রশ্ন করে দেখেন ধারণাটি নড়ে কি না। মুখস্থ উত্তর একটি নির্দিষ্ট পথে চলে; পথ থেকে সরলেই হারিয়ে যায়। বোঝা উত্তর একটি মানচিত্রের মতো — যেকোনো দিক থেকে এলেও পথ খুঁজে পাওয়া যায়।
অনুশীলনের উপায়: প্রতিটি মডেল উত্তর পড়ার পর পাতা বন্ধ করে জোরে বলুন। তারপর নিজেকে তিনটি “কেন” জিজ্ঞেস করুন। এই পাতার প্রোগ্রামগুলো চালানোর আগে আউটপুট আন্দাজ করুন, তারপর একটি লাইন বদলে আবার আন্দাজ করুন। এভাবে মডেল উত্তর হয়ে ওঠে কাঠামো, যার ভেতরে আপনার নিজের বোঝা বসে।
মূল উপলব্ধি: মডেল উত্তর হলো কাঠামো ও মান বোঝার নমুনা, মুখস্থের জিনিস নয়। আপনার লক্ষ্য একই তথ্য নিজের ভাষায়, নিজের উদাহরণে বলতে পারা।
প্র ০৪“জানি না” বলা কেন অনেক সময় আন্দাজে উত্তর দেওয়ার চেয়ে ভালো? আত্মবিশ্বাস আর জ্ঞানের সম্পর্ক কী?
১৯৯৯ সালে মনোবিজ্ঞানী Justin Kruger আর David Dunning একটি গবেষণা প্রকাশ করেন, যা পরে “Dunning–Kruger effect” নামে পরিচিত হয়। তাঁদের পরীক্ষায় দেখা যায়, কোনো বিষয়ে সবচেয়ে কম দক্ষ অংশগ্রহণকারীরা প্রায়ই নিজের দক্ষতাকে অনেক বেশি মনে করেছেন — কারণ ভুল চেনার জন্যও কিছু জ্ঞান লাগে। ফলাফলটির ব্যাখ্যা ও মাত্রা নিয়ে পরে গবেষকদের মধ্যে বিতর্কও হয়েছে, তবে মূল শিক্ষাটি ভাইভায় খুব প্রাসঙ্গিক: আত্মবিশ্বাস আর জ্ঞান এক জিনিস নয়।
পরীক্ষকেরা এটা জানেন। তাই একজন প্রার্থী জোর দিয়ে ভুল বললে — ধরা যাক “volatile দিয়ে counter thread-safe হয়” — পরীক্ষক শুধু ওই প্রশ্নের নম্বর কাটেন না; বাকি সব উত্তর নিয়েও সন্দিহান হন। “আমি কি এর বলা ঠিক তথ্যগুলোও বিশ্বাস করতে পারি?” অন্যদিকে “এটা নিশ্চিত জানি না, তবে এভাবে ভাবছি…” বলা প্রার্থী দেখান যে তিনি নিজের জ্ঞানের সীমা জানেন।
সফটওয়্যার কাজে এই গুণ আরও জরুরি। production সিস্টেমে কেউ আন্দাজে “এটা নিরাপদ” বলে কোড merge করলে ক্ষতি হয় গ্রাহকের — হয়তো bKash-এ দুবার টাকা কাটে। যে ডেভেলপার বলেন “নিশ্চিত নই, একটি টেস্ট লিখে দেখি”, দল তাঁর ওপর বেশি ভরসা করে। ইন্টারভিউয়াররা তাই প্রায়ই ইচ্ছা করে এমন প্রশ্ন করেন, যার উত্তর প্রার্থী জানবেন না — দেখতে, তিনি কী করেন।
কিন্তু সীমা আছে: সব প্রশ্নেই “জানি না” বললে প্রস্তুতির অভাব বোঝায়। সবচেয়ে ভালো পথ হলো মাঝখানে — যা জানেন তা বলা, যেখানে অনুমান সেখানে “আমার ধারণা” বলা, আর একেবারে না জানলে সৎভাবে স্বীকার করা।
মূল উপলব্ধি: ভাইভায় আপনার বিশ্বাসযোগ্যতাই সবচেয়ে বড় সম্পদ। একটি সৎ “জানি না” বিশ্বাসযোগ্যতা বাড়ায়; একটি আত্মবিশ্বাসী ভুল তা নষ্ট করে।
প্র ০৫Vector, Hashtable, StringBuffer, finalize — পুরোনো, প্রায় অব্যবহৃত জিনিস নিয়ে এখনো প্রশ্ন আসে কেন?
Java-র একটি বড় প্রতিশ্রুতি হলো পেছনের দিকে সামঞ্জস্য (backward compatibility): বহু বছর আগে লেখা কোড নতুন JVM-এও সাধারণত চলে। তাই পুরোনো class সহজে মুছে ফেলা হয় না। Java 1.0-তে (১৯৯৬) ছিল Vector, Hashtable, StringBuffer — সবার method synchronized, কারণ তখন ধরে নেওয়া হয়েছিল নিরাপত্তার জন্য সব জায়গায় lock ভালো।
অভিজ্ঞতা উল্টো বলল: বেশিরভাগ collection একটিই thread ব্যবহার করে, তাই প্রতিটি ডাকে lock নেওয়া অপচয়; আর যেখানে সত্যিই একাধিক thread, সেখানে একেকটি method-এ lock থাকলেও “check-then-act”-এর মতো কয়েক ধাপের কাজ নিরাপদ হয় না। Java 1.2-তে (১৯৯৮) Joshua Bloch-এর নকশায় Collections Framework এলো — ArrayList, HashMap, lock ছাড়া। Java 5-এ (২০০৪) এলো StringBuilder আর java.util.concurrent (ConcurrentHashMap-সহ)। finalize Java 9-এ deprecated হলো, আর Java 18-এ JEP 421 একে সরিয়ে ফেলার জন্য চিহ্নিত করল।
তাহলে প্রশ্ন কেন আসে? প্রথমত, বাস্তবে পুরোনো কোড প্রচুর — ব্যাংক, সরকারি আর বড় প্রতিষ্ঠানের সিস্টেমে আপনাকে এগুলো পড়তে ও বদলাতে হতে পারে। দ্বিতীয়ত, “Vector আর ArrayList-এর পার্থক্য কী, কেন Vector এখন ব্যবহার করা হয় না” — এই প্রশ্নের ভালো উত্তর দিতে synchronization-এর খরচ, নকশার বিবর্তন আর সঠিক বিকল্প জানতে হয়। পুরোনো জিনিসের প্রশ্ন আসলে নকশার কারণ বোঝার প্রশ্ন।
উত্তর দেওয়ার কৌশল: পুরোনো জিনিসের প্রশ্নে তিনটি অংশ বলুন — এটি কী ছিল, কেন সমস্যা হলো, আজ এর বদলে কী ব্যবহার করা হয়। যেমন: “Hashtable সব method-এ synchronized; একাধিক thread-এ এখন ConcurrentHashMap, একটিতে HashMap.”
মূল উপলব্ধি: একটি ভাষার ইতিহাস তার ভুল থেকে শেখার ইতিহাস। পুরোনো API কেন বাদ পড়ল তা জানলে নতুন API কেন এভাবে বানানো, সেটাও স্পষ্ট হয়।
নিজেকে যাচাই করুন — উত্তর লেখার কৌশল ও Java-র মূল তথ্য
প্রথমে একটি ক্রম সাজানোর প্রশ্ন, তারপর উত্তর লেখার কৌশল আর Java-র ক্লাসিক ভাইভা তথ্য নিয়ে MCQ. ভুল হলে কারণসহ ব্যাখ্যা পাবেন।
ক্রম“X আর Y-এর পার্থক্য লিখুন” প্রশ্নের একটি ভালো উত্তরের অংশগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- 📌 X আর Y-এর এক লাইন করে সংজ্ঞা
- 📊 একই মাপকাঠিতে সারি দিয়ে তুলনার টেবিল
- 💻 দুই পাশের ছোট উদাহরণ কোড
- 🗺️ মেমরি বা গঠনের ছোট চিত্র
- ✅ উপসংহার — কখন কোনটি বেছে নেবেন
“abstract class আর interface-এর পার্থক্য লিখুন” — একটি ৫ নম্বরের প্রশ্নে কোন উত্তরটি পূর্ণ নম্বরের সবচেয়ে কাছে?
- দুই পাতা জুড়ে শুধু interface-এর বিস্তারিত বর্ণনা
- দুটির এক লাইনের সংজ্ঞা, state, constructor, কয়টি নেওয়া যায়, default method-এর সারিসহ টেবিল, ছোট উদাহরণ আর কখন কোনটি
- “interface-এ সব method abstract, abstract class-এ নয়” — এক লাইন
- ব্যাখ্যা ছাড়া দুটি বড় প্রোগ্রাম
ভাইভায় এমন প্রশ্ন এলো, যার উত্তর আপনি পুরোপুরি জানেন না। সবচেয়ে ভালো পদক্ষেপ কোনটি?
- আত্মবিশ্বাস দেখাতে আন্দাজে একটি উত্তর জোর দিয়ে বলা
- চুপ করে থাকা, যতক্ষণ না পরের প্রশ্ন আসে
- “পুরো নিশ্চিত নই, তবে এভাবে ভাবছি…” বলে যা জানেন তা থেকে যুক্তি দিয়ে এগোনো
- প্রশ্ন এড়িয়ে নিজের জানা অন্য বিষয়ে কথা বলা শুরু করা
ডিফল্ট JVM সেটিংসে Integer a = 128, b = 128; লিখলে a == b আর a.equals(b)-এর মান কী?
- false আর true
- true আর true
- false আর false
- Compile error
কোন Map বাস্তবায়ন key-গুলো ঢোকানোর ক্রমে রাখে এবং গড়ে O(1)-এ খোঁজে?
HashMapTreeMapHashtableLinkedHashMap
JDBC-তে Statement-এর বদলে PreparedStatement ব্যবহারের সবচেয়ে গুরুত্বপূর্ণ কারণ কোনটি?
- এতে database connection-এর প্রয়োজন হয় না
- ব্যবহারকারীর ইনপুট SQL হিসেবে পড়া হয় না, তাই SQL injection ঠেকে
- এতে table-এর নামও
?দিয়ে বদলানো যায় - এটি আপনাআপনি transaction শুরু ও commit করে
দুটি thread একই counter বাড়াচ্ছে। কোন সমাধানটি যথেষ্ট নয়?
- increment method-টি
synchronizedকরা AtomicInteger.incrementAndGet()ব্যবহার করা- counter field-কে
volatileকরা ReentrantLockদিয়ে lock নিয়ে বাড়ানো
REST API-তে PUT আর PATCH নিয়ে কোন বক্তব্যটি সঠিক?
- PUT পুরো resource বদলায় এবং idempotent; PATCH আংশিক বদলায়, আর idempotent হবেই এমন নিশ্চয়তা নেই
- PUT আংশিক বদলায়, PATCH পুরো resource বদলায়
- PUT, PATCH আর POST — তিনটিই সবসময় idempotent
- PATCH আসলে GET-এর একটি বিশেষ রূপ
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বে ব্যবহৃত সব শব্দ এখানে একসাথে:
মনে রাখুন
- বড় প্রশ্নে পাঁচ অংশ: সংজ্ঞা → ব্যাখ্যা → উদাহরণ কোড → টেবিল বা চিত্র → উপসংহার; “পার্থক্য লিখুন” প্রশ্নে দুটির সংজ্ঞা আর একই মাপকাঠির টেবিল।
- খাতার কোডে আধুনিক Java: generics, বাঁ দিকে interface, record,
@Override— আর নিচে আউটপুট ও edge case. - ক্রম বা সময়-নির্ভর আউটপুটে অনুমান স্পষ্ট করুন: HashMap-এর ক্রম নিশ্চিত নয়, thread-এর interleaving নিশ্চিত নয়, Integer cache ডিফল্টে −128 থেকে 127.
- ভাইভায় সংজ্ঞা → উদাহরণ → trade-off, তিন বাক্যে; না জানলে সৎভাবে যুক্তি দিয়ে এগোন; নিজের প্রজেক্টের প্রতিটি সিদ্ধান্তের কারণ নিজের ভাষায় বলতে পারুন।
- AI দিয়ে ভাইভা অনুশীলন করুন, কিন্তু তার প্রতিটি কোড চালিয়ে আর প্রতিটি সংস্করণ-দাবি মিলিয়ে নিন।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৫৯ · Java কোডিং ইন্টারভিউ — সমস্যা থেকে সমাধানপরবর্তী পর্বসমস্যা বোঝা থেকে কোড লেখা পর্যন্ত ইন্টারভিউয়ের পুরো পথ।
- পর্ব ৫৭ · MCQ প্রশ্নব্যাংক — যেকোনো পরীক্ষার প্রস্তুতিআগের পর্বযেকোনো পরীক্ষার MCQ অংশের জন্য বিষয়ভিত্তিক অনুশীলন।
- পর্ব ৫৬ · আউটপুট কী হবে? — Java কোড পড়ার অনুশীলনঅনুশীলনকোড পড়ে আউটপুট বলা — লিখিত পরীক্ষা আর ইন্টারভিউর আরেকটি প্রিয় প্রশ্ন।
- পর্ব ৫৫ · ক্যাপস্টোন — “দোকানদার”ফিরে দেখুনভাইভায় যে প্রজেক্ট নিয়ে কথা বলবেন, তার সিদ্ধান্তগুলো আবার ঝালিয়ে নিন।
- Java প্রোগ্রামিং · কোর্স হোম৫৯টি পর্বযে পর্বে দুর্বলতা পেলেন, সেখানে ফিরে যান।
- C++ · লিখিত ও মৌখিক প্রশ্নপাশের ট্র্যাকএকই কাঠামোয় C++-এর প্রশ্নব্যাংক — দুই ভাষার তুলনার প্রশ্নে কাজে লাগে।