Java 8 aur Functional Programming interview questions & answers
239+ real Java 8 aur Functional Programming interview questions with model answers, plus free lessons to learn the concepts. Prepare in English & Hinglish, then practise with an AI mock interview.
19 topics · 239+ questions
Hirenix kaise padhata hai
Ek chapter. 90 minute.
Interview ke liye taiyaar.
Har concept ek real-world problem se — jaisa production code mein aata hai, waisa. Ratna nahi padta, samajh aa jaata hai. Har question ka model answer diya hai: interviewer ko exactly kya bolna hai, aur kyun. Phir usi chapter ka AI mock interview.
- 📖Concept, 5 min meinJargon nahi — seedhi baat
- 🛠️Real-world problemJaisa production code mein aata hai
- 💬Model answerInterview mein kya bolna hai
- 🧠FlashcardsRevision 10 min mein
- 🤖AI mock interviewFollow-up bhi poochta hai
- 📊Weak topicsKahan phans rahe ho, pata chale

Farq content ka nahi, filter ka hai — sirf wahi jo production mein actually use hota hai aur interview mein actually poocha jaata hai. Kitaabi topics jo industry mein kahin nahi chalte, wo yahan nahi milenge.
What you’ll learn
- ●Java functional kyun bana
- ●Lambda expressions
- Functional interfaces aur @FunctionalInterfaceFree account
- Predicate, Function, Consumer, SupplierFree account
- Method aur constructor referencesFree account
- Interface ke default aur static methodsFree account
- Stream asal mein hai kyaFree account
- Intermediate operationsFree account
- map vs flatMap, aur primitive streamsFree account
- Terminal operations aur short-circuitingFree account
- Collectors: grouping, partitioning, joiningFree account
- Optional aur null check ka antFree account
- Parallel streams: kab fayda, kab nuksanFree account
- Lambda aur stream ke andar exceptionsFree account
- Nayi Date aur Time APIFree account
- RecapFree account
- ●Project: Student Report Card
- Project: Validation Rules EngineFree account
- Project: Imperative se FunctionalFree account
Java functional kyun bana
Sochiye aapne Andheri se Bandra-Kurla Complex ke liye cab book ki hai. Wahan pahunchne ke do bilkul alag tareeke hain, aur inn dono ka fark hi poore Java 8 ka asli idea hai.
Pehla tareeka - cab aap khud chalate hain. "400 metre seedha. Ab left. Ab doosra right. Signal pe ruko." Steering aapke haath mein hai, kab rukna hai aap tay kar rahe hain. Aur ek galti - ek galat turn - poori trip galat.
Doosra tareeka - aap driver ko sirf address bata dete hain. "BKC chaliye." Bas. Kya chahiye, ye bataya; kaise pahunchna hai, ye nahi. Ab route driver ka mamla hai - flyover le le ya jam dekh kar raasta badal le, ye aapki problem nahi, aur isse aapki demand badalti bhi nahi.
In production, pehla tareeka hai for loop aur doosra hai list.forEach(...). Java 8 se pehle Java ke paas sirf pehla tareeka tha. Java 8, jo 2014 mein aayi, ne language ko kaise ki jagah kya kehne ka raasta diya - aur yahi ek badlav wajah hai ki 2014 ke baad likha har Java codebase usse pehle ke har codebase se alag dikhta hai.
💡 External iteration = loop aapka code chalata hai. Aap
forlikhte hain, index ya iterator aap pakadte hain, kab rukna hai aap tay karte hain. Collection sirf sawaalon ka jawab deti hai. 💡 internal iteration = aap library ko ek behaviour thama dete hain aur loop library chalati hai. Index aapko dikhta hi nahi.forEach,removeIf,sortaur pooraStream APIyahi karte hain. 💡 First-class function = wo code jise aap variable mein rakh sakte hain, method mein pass kar sakte hain, aur method se wapas kar sakte hain - bilkulintyaStringki tarah. 💡 Higher-order function = wo method jo behaviour ko argument ki tarah leta hai, ya behaviour wapas karta hai.list.sort(comparator)aisa hi hai: uska argument data nahi, ek faisla hai.
Java badla hi kyun
Java is mamle mein karib atthaarah saal tak jaisa tha waisa hi raha, to wajah dumdaar honi chahiye. Teen wajahein thin, aur teenon ek doosre ko badhati hain.
1. Behaviour pass karna sharmnaak had tak lamba tha. Java 8 se pehle agar aap kisi method ko thoda sa logic dena chahte the, to ek hi savari thi - object. Yaani ek line ke khayal ko dhone ke liye poora anonymous class likhna padta tha:
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
});
System.out.println("A old way = " + names);
names.sort((a, b) -> a.length() - b.length());
System.out.println("B new way = " + names);
A old way = [Diya, Neha, Aarav, Ishaan]
B new way = [Diya, Neha, Aarav, Ishaan]
Wahi list, wahi order, wahi result. Pehle mein a.length() - b.length() ke charon taraf chhe line ki kaagzi karwai, doosre mein zero. Baat hamesha ek hi line ki thi; Java aapse uske charon taraf peti banwa raha tha. (Lambda ka syntax topic 2 theek se sikhata hai - yahan sirf pehle-aur-baad ka farq dikhaya hai.)
2. Hardware badal gaya, language nahi. 2014 tak sabse sasta laptop bhi char core ka tha. Lekin for loop ek waada hai ki aap element 0, phir 1, phir 2 - isi order mein, isi thread pe - visit karenge. Na compiler, na JVM use cores pe baant sakta hai, kyunki aapke loop ka body order pe depend kar sakta hai. Jab tak loop aapka hai, use parallel sirf aap kar sakte hain. Jis lamhe loop library ka ho jaata hai, library faisla kar sakti hai.
3. Collection jami hui thi. Collection interface mein stream() method jodne se duniya ki har wo class toot jaati jo use implement karti hai - raat ke raat, compile time pe. Isliye Java 8 ko Stream API bhejne se pehle interfaces mein default methods invent karne pade. Isi wajah se ek hi release mein do bilkul alag dikhne wale features hain: ek isliye maujood hai taaki doosra maujood ho sake. Ye kahani topic 6 sunata hai.
Code ko value ki tarah dekhna - asli soch ka badlav
Is topic se ye ek line saath le jaaiye: Java 8 se pehle aap methods ko data dete the; Java 8 ke baad aap behaviour bhi de sakte hain.
list.sort(comparator) ko koi number ya naam nahi milta. Use order ke baare mein ek faisla milta hai, jo variable mein rakha hai aur kisi bhi doosri value ki tarah haath mein thama diya gaya hai. Isi ko kehte hain functions ko first-class citizen maanna, aur sort jaisa method jo ise leta hai wo higher-order function hai.
Andar koi jaadu nahi hua. Java mein aisi koi nayi cheez paida nahi hui jo class se azaad ho - runtime pe lambda aaj bhi ek object hi hai jo interface implement karta hai, aur lambda se banaye Runnable pe job.getClass() ek asli class name deta hai. Badla sirf itna ki idea aur compiler ke beech ki typing kam ho gayi, aur - isse kahin zyada ahem - loop kiska hai.
To kya Java ab functional hai, ya abhi bhi object-oriented?
Is chapter ka pehla interview sawaal yahi hai, aur seedha jawab hai dono. Java 8 ne Java ko multi-paradigm bana diya: wo object-oriented hona chhoda nahi, uske upar ek functional paradigm jod diya.
Ise teen hisson mein kahiye, kyunki aadha jawab ratta lagta hai:
- Abhi bhi OO hai. Har cheez aaj bhi class ke andar rehti hai. Encapsulation, inheritance aur polymorphism ek inch nahi hile. Aapka lambda khud ek object hai jo interface implement karta hai.
- Ab functional bhi hai. Aap behaviour ko value ki tarah rakh sakte hain, variable mein daal sakte hain, chhote tukdon ko jod sakte hain, aur loop ki jagah declarative code likh sakte hain.
- Par ye functional language nahi hai. Asli functional language immutability lagu karti hai aur side effects ko kinare pe dhakelti hai. Java dono nahi karta - lambda ke andar aap aaram se field badal sakte hain, console pe print kar sakte hain, database mein likh sakte hain, aur compiler ek shabd nahi bolega. Java functional style deta hai, functional guarantee nahi.
Agar interviewer dabaye - "to functional hai ya nahi?" - jeetne wali line ye hai: Java ek object-oriented language hai jo functional programming paradigm ko support karti hai. Badlav nahi, izafa.
Wo teen cheezein jo ise functional banati hain
| Feature | Aapko kya milta hai |
|---|---|
| Lambda expressions | behaviour likhne ka tareeka bina use class mein lapete - (a, b) -> a.length() - b.length() |
| Functional interfaces | wo type jismein lambda rakha jaata hai. Jis interface mein theek ek abstract method ho, wahi lambda ka khaancha hai |
Stream API |
wo jagah jahan ye sab kaam aata hai - poori library jo internal iteration pe bani hai, jahan aap result batate hain aur loop wo chalati hai |
Ye teenon dar-asal ek hi mechanism ke teen padaav hain: lambda value hai, functional interface uska type hai, aur Stream API uska customer. Topic 2, 3 aur 7 inhe ek-ek karke uthate hain. Agar koi poochhe "kaun se teen features ne Java ko functional banaya", to jawab yahi table hai - Java 8 ke har badlav ki list nahi.
Java 8 mein aur kya-kya aaya
Ye list poochhi jaati hai, isliye naksha dimaag mein rakhiye - chahe inmein se zyadatar aage ke topics hain:
- Lambda expressions aur method references (
String::toUpperCase) - topic 2 aur 5 - Functional interfaces, aur
java.util.functionmein unka banaya-banaya catalogue - topic 3 aur 4 - Interfaces mein
defaultaurstaticmethods - upar wala backward-compatibility ka jugaad - topic 6 Stream API- topic 7 se 13Optional- ek return type jo saaf-saaf kehta hai "yahan value na bhi ho" - topic 12- Naya date-time API (
java.time) - immutable, thread-safe, aur 30 February lene se saaf mana kar deta hai - topic 15 - Metaspace ne PermGen ki jagah li: class metadata fixed-size PermGen se nikal kar native memory mein chala gaya jo zarurat par badhti hai, isi liye
java.lang.OutOfMemoryError: PermGen spaceab hota hi nahi. Isi JDK se saboot:java -XX:MaxPermSize=64m -versionstart hi nahi hota, woUnrecognized VM option 'MaxPermSize=64m'print karta hai. Yahan iske liye bas yahi ek line hai - memory model Ch1memory-heap-stackka mamla hai.
⚠️ Question lists ke baare mein ek warning. Bahut si "Java 8 interview questions" lists aaj bhi Nashorn / JJS poochhti hain, wo JavaScript engine jo Java 8 ke saath aaya tha. Use Java 15 mein hata diya gaya, yaani kisi modern JDK pe wo hai hi nahi aur uska jawab dene se kuch nahi milta. Agar koi list abhi bhi ye poochh rahi hai, to wo list saalon se update nahi hui - uske baaki jawaabon ko bhi utne hi shak se padhiye.
Internal vs external iteration - wo ek idea jis par baaki poora chapter khada hai
Topic 7 ke aage sab kuch isi ek badlav ka nateeja hai, isliye yahan thoda ruk jaaiye.
External iteration - gaadi aap chala rahe hain:
int total = 0;
for (int i = 0; i < batch.size(); i++) {
total = total + batch.get(i).marks;
}
Dekhiye kya-kya likhna pada: ek index, ek limit, ek increment, ek get(i), aur ek accumulator. In paanch mein se theek ek cheez marks jodne ke baare mein hai; baaki chaar sirf dhulai hain - aur har ek off-by-one galti ki jagah hai.
internal iteration - aapne address bata diya:
batch.forEach(s -> box[0] = box[0] + s.marks);
Na index. Na limit. Na get. Aapne bataya ki har student ke saath kya hona chahiye aur chalna ArrayList ne khud chala. Paanch students ke usi batch pe dono ne 323 print kiya - ye number neeche wali chalne-layak file se aaya hai.
External (for) |
Internal (forEach, removeIf, sort, Stream API) |
|
|---|---|---|
| Loop kaun chalata hai | aapka code | library |
| Aap kya likhte hain | kaise chalna hai | kya karna hai |
| Traversal ka order | aapka tay kiya, hamesha sequential | library ka mamla |
| Aapke liye parallel ho sakta hai | nahi | haan - isi wajah se parallelStream() sochna bhi mumkin hai |
| Beech mein nikalna | break, bilkul aasan |
break se nahi; library apne short-circuit deti hai |
| Debugging | kisi bhi IDE mein step through | mushkil - lambda ke andar breakpoint loop ka breakpoint nahi hota |
Chauthi row hi Stream API ke hone ki poori wajah hai. Aur chhathi row wajah hai ki ye chapter aapse kabhi nahi kahega ki loop mar gaye.
Ek correctness ka fayda bhi turant dikhta hai. For-each list ko ghoom raha ho aur usi waqt list se element hataana Java ke sabse aam bugs mein se hai:
for (String s : batch) {
if (s.startsWith("D")) {
batch.remove(s);
}
}
A for-each remove -> java.util.ConcurrentModificationException
B removeIf = [Aarav, Ishaan, Neha]
batch.removeIf(s -> s.startsWith("D")) wahi kaam karta hai aur ye exception de hi nahi sakta, kyunki chalna aur hataana dono ArrayList ke apne haath mein hain, to wo dono ko mila kar rakh sakta hai. Jab loop aapka hota hai, uske bugs bhi aapke hote hain.
Kab use karein: internal iteration - forEach, removeIf, sort, aur aage chal kar Stream API - tab uthaiye jab aap collection ke ek transformation ki baat kar rahe hain: in students ko filter karo, subject ke hisaab se group karo, in marks ka total nikalo. Tab code waise hi padha jaata hai jaise requirement likhi hai, aur library aapke peechhe optimise ya parallel karne ke liye azaad rehti hai.
Kab NAHI use karein: saada for loop hi rakhiye jab aapko index khud chahiye, jab do collections ko saath-saath chalna ho, jab body koi checked exception throw karti ho (lambda se checked exception bahar nikal hi nahi sakti - topic 14), jab aapko break / continue ya bahar wale method se return chahiye, ya jab body ka poora maqsad hi koi side effect ho jaise file mein rows likhna. Aur teen element ki list pe loop hi tez hai, kyunki pipeline khada karna muft nahi hai.
Trade-off: aapko readability, composability aur parallelism ka option milta hai; badle mein step-through debugging, sasta early exit, aur body se checked exception throw karne ki aazadi jaati hai. Topic 19 ek loop-bhare class ko isi style mein likhta hai aur ek loop ko jaan-boojh kar loop hi rehne deta hai, wajah ke saath - kyunki is chapter ka imaandaar version yahi hai ki naya style zyadatar waqt behtar hai, har waqt nahi.
Standard definition: Java 8 introduced functional-programming constructs - lambda expressions, functional interfaces, method references and the Stream API - making Java a multi-paradigm language rather than replacing its object-oriented core. Its central shift is from external iteration, where application code drives the loop, to internal iteration, where the caller supplies behaviour as a first-class value and the library controls the traversal.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Demo {
static class Student {
final String name;
final int marks;
Student(String name, int marks) { this.name = name; this.marks = marks; }
public String toString() { return name + "(" + marks + ")"; }
}
public static void main(String[] args) {
List<Student> batch = new ArrayList<>(List.of(
new Student("Aarav", 82),
new Student("Diya", 47),
new Student("Ishaan", 91),
new Student("Neha", 38),
new Student("Rohan", 65)));
// ---------- EXTERNAL iteration: I drive the loop myself ----------
int total = 0;
for (int i = 0; i < batch.size(); i++) {
total = total + batch.get(i).marks;
}
System.out.println("A external for-loop total = " + total);
// ---------- INTERNAL iteration: I hand the behaviour to the library ----------
int[] box = new int[1];
batch.forEach(s -> box[0] = box[0] + s.marks);
System.out.println("B internal forEach total = " + box[0]);
// ---------- code as value: the SAME list, two different behaviours ----------
List<Student> copy = new ArrayList<>(batch);
copy.sort(Comparator.comparingInt(s -> s.marks));
System.out.println("C sorted by marks = " + copy);
copy.sort(Comparator.comparing(s -> s.name));
System.out.println("D sorted by name = " + copy);
// ---------- the library owns the loop, so it owns the removal too ----------
List<Student> failed = new ArrayList<>(batch);
failed.removeIf(s -> s.marks >= 50);
System.out.println("E below 50 after removeIf = " + failed);
System.out.println("F original list untouched = " + batch);
}
}Lambda expressions
Topic 1 ek waade pe khatam hua tha: Java 8 ke baad loop library chalati hai aur behaviour aap dete hain. Ye topic usi cheez ke baare mein hai jo aap dete hain.
Kanpur ke ek chhote tuition centre ka office sochiye. Owner ko attendance register roll number se sorted chahiye. Java 8 se pehle helper ko koi instruction dene ka ek hi tareeka tha — poori file thamana: upar cover page jis pe helper ka naam, phir index, andar ek signed instruction, aur peeche back cover. Ek line ke asli instruction — "roll number se sort kar do" — ke chaaron taraf chaar page ki kagazi karwai.
Lambda expression wahi ek line hai, ek parchi pe likh kar de di gayi, aur kagazi karwai phenk di gayi. Aur kuch nahi badla — helper abhi bhi helper hai, instruction abhi bhi wahi instruction hai. Sirf lifafa gaya hai.
💡 Lambda expression us interface ka implementation likhne ka chhota tareeka hai jismein theek ek abstract method ho. Ye koi azaad ghoomta hua function nahi hai — Java mein aaj bhi aisi koi cheez hai hi nahi.
Pehle ye ek baat baith jani chahiye
Har seekhne wale ka pehla mental model hota hai — "lambda ek function hai." Java mein ye model galat hai, aur itna galat hai ki das minute ke andar asli confusion paida kar deta hai.
Sahi version ye hai: lambda ek one-method interface ka implementation hai, bas class ka naam-pata likhe bina. Interface abhi bhi maujood hai. Object abhi bhi banta hai. Jo gaya hai wo unke aas-paas likha jaane wala boilerplate hai.
Isi liye ye kabhi compile nahi hoga:
var greet = name -> "Namaste " + name; // koi target type hi nahi — implementation KISKA?
aur ye ho jayega:
interface Greeter { String greet(String name); }
Greeter g = name -> "Namaste " + name;
= ke baayin taraf wala interface hi daayin taraf wale lambda ko matlab deta hai: uske parameter ka type, return type, aur wo method ka naam jise wo implement kar raha hai. Akela lambda ek tukda hai, value nahi. (Is mechanism ka asli naam target typing hai, aur wo theek se topic 3 mein padhaya jaata hai.)
Purana tareeka, poora ka poora
Ch2 ne apna anonymous inner class wala section isi page ki taraf ishara karke khatam kiya tha, to wahin se shuru karte hain. Paanch students ke naam length se sort karna, Java 7 style:
Comparator<String> byLength = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};
old.sort(byLength);
Ab ginye ki usmein kaam kar kya raha hai. Sirf ek expression: a.length() - b.length(). Baaki sab dhancha hai — new, wahi type ka naam do baar, braces, @Override, method ki poori signature, aur aakhir mein wo }; jiska semicolon sab bhool jaate hain. Is dhanche ka naam desh ke har code review mein ek hi hai: boilerplate.
Wahi behaviour, lambda ki shakl mein
neu.sort((a, b) -> a.length() - b.length());
JDK 17 pe dono ne bilkul ek jaisa result diya:
A anonymous class = [Diya, Neha, Aarav, Rohan, Ishaan]
B lambda = [Diya, Neha, Aarav, Rohan, Ishaan]
Wahi jawab, wahi Comparator, wahi sort method. Compiler ab bhi Comparator.compare ka implementation hi bana raha hai — aapne bas wo hisse likhna band kar diya jo wo khud nikal sakta tha.
Fayde, theek us tarah jaise interviewer sunna chahta hai: boilerplate kam, isliye niyat (intent) dikhti hai, dhanche mein dabi nahi rehti; behaviour ek value ban jaata hai jise variable mein rakh sakte hain aur method mein pass kar sakte hain; aur — ye log bhool jaate hain — Stream API mumkin hi isi wajah se hua, kyunki internal iteration pe khadi API bekaar ho jaati agar har behaviour chhe line ka padta.
-> ke dono taraf hota kya hai
(parameters) -> body
-> (jise arrow token kehte hain) hi poora syntax hai. Uske baayin taraf: interface ke us akele method ke parameters. Daayin taraf: wo method karta kya hai.
- Agar body ek expression hai, to uski value hi return value hai — na
return, na braces, na semicolon. - Agar body
{ }wala block hai, to wo saada method body hai aurreturnaapko khud likhna hoga (jab tak methodvoidna ho).
Ek hi lambda, chaar tareeke se likha hua
Yahi wo hissa hai jo asli code ko anjaana bana deta hai. Ye chaaron ek hi lambda hain, aur chaaron ne ek hi number print kiya:
interface Discount { int apply(int amount); }
Discount w1 = (int amount) -> { return amount - amount / 10; }; // sab kuch likha hua
Discount w2 = (amount) -> { return amount - amount / 10; }; // parameter ka type hataya
Discount w3 = amount -> { return amount - amount / 10; }; // ek hi param, parens hataye
Discount w4 = amount -> amount - amount / 10; // expression body: braces + return hataye
C w1 1800 w2 1800 w3 1800 w4 1800
Short forms ke teen hi niyam hain, aur koi nahi:
- Parameter ke types hataye ja sakte hain — hamesha, bas saare ke saare hatane honge.
- Parentheses sirf tab hat sakti hain jab parameter theek ek ho aur uska type bhi hataya gaya ho. Zero parameter ko
()likhna hi padega. Do ya zyada ko(a, b)likhna hi padega. - Braces aur
returnsirf tab hat sakte hain jab body ek hi expression ho.
Niyam 1 ka "ya sab, ya koi nahi" style ki salah nahi, compile error hai:
Fare f = (int km, rate) -> km * rate;
BadMix.java:5: error: invalid lambda parameter declaration
Fare f = (int km, rate) -> km * rate;
^
(cannot mix implicitly-typed and explicitly-typed parameters)
1 error
Asli code mein aapko form 4 har jagah milega aur form 1 kahin nahi. Seekhte waqt form 1 likhne se madad milti ho to zaroor likhiye; ship koi nahi karta.
Type inference: compiler ko pata kaise chalta hai
Jab aapne int likha hi nahi, to amount ko kaise pata ki wo int hai?
Compiler target type se ulta chal kar nikalta hai — yaani assignment ke baayin taraf ka type, ya jis method ko aap call kar rahe hain uske parameter ka type. Wo us interface ka ekmatr abstract method dhoondta hai, uski signature padhta hai, aur wahi aapke lambda pe chipka deta hai:
Discount mein theek ek abstract method hai: int apply(int amount)
^ ^
| +-- isliye aapka parameter int hai
+-- isliye aapki body ko int dena hoga
Isi ko type inference kehte hain, aur yahi machinery neu.sort((a, b) -> ...) ko chalati hai: sort ko Comparator<String> chahiye, jiska akela method int compare(String, String) hai, isliye a aur b String hain aur body ko int dena hoga. Yahan kuch bhi dynamic nahi hai aur runtime pe kuch andaza nahi lagta — body galat type degi to compile error milega, bilkul waise hi jaise anonymous class ke saath milta.
Do baatein yaad rakhne layak:
- Return type bhi infer hota hai. Aap use kabhi declare nahi karte.
- Kyunki inference ko target type chahiye, lambda ko
varyaObjectmein daala nahi ja sakta. Infer karne ko wahan kuch hai hi nahi.
Effectively final: wo error jise sab ulta padhte hain
Lambda apne aas-paas wale method ke local variables padh sakta hai. Ye compile bhi hua aur chala bhi:
int gstPercent = 18; // `final` kahin nahi likha
Discount withGst = amount -> amount + (amount * gstPercent / 100);
System.out.println("F captured local gstPercent = " + withGst.apply(2000));
F captured local gstPercent = 2360
Dhyan se dekhiye: gstPercent par final likha hi nahi hai, phir bhi capture theek se hua. Ab usi method mein ek line jodiye — kahin bhi, lambda ke baad bhi chalega:
int gstPercent = 18;
Discount withGst = amount -> amount + (amount * gstPercent / 100);
gstPercent = 28; // <- sirf yahi ek line nayi hai
BadFinal.java:6: error: local variables referenced from a lambda expression must be final or effectively final
Discount withGst = amount -> amount + (amount * gstPercent / 100);
^
1 error
Is message ko seedha padhiye, ulta nahi. Log final shabd dekhte hain aur samajh lete hain — "matlab mujhe final likhna padega." Message ye keh hi nahi raha. Pehle version mein final tha hi nahi aur wo chal gaya. Asli niyam ye hai:
Lambda jis local variable ko capture kare, use theek ek baar assign hona chahiye. Agar aisa hai to compiler use effectively final maanta hai aur capture karne deta hai. Khud
finallikhne se sirf itna hota hai ki niyat saaf ho jaati hai — aur aage ki galti capture ki jagah assignment pe pakdi jaati hai.
Aur ye bhi dekhiye ki caret kahan ishara kar raha hai — line 6 pe, lambda ke andar wale use pe, line 7 wale reassignment pe nahi. Compiler capture report karta hai, jurm nahi. Isi liye ye error logon ko galat line pe ghoorne bhej deta hai.
Ye niyam hai hi kyun: local variable apne method ke stack frame pe rehta hai, aur method return hote hi wo frame khatam. Lambda usse zyada jee sakta hai. Isliye Java variable capture nahi karta, value ki copy lambda ke andar rakh deta hai. Agar variable baad mein badal sakta, to copy aur asli variable chup-chaap alag ho jaate — dono mein se ek jhooth bolta. Java ye haalat banne hi nahi deta.
Ye niyam locals ke baare mein hai, badalne (mutability) ke baare mein nahi — iska saboot ek field hai:
int gstPercent = 18; // ye INSTANCE FIELD hai, local nahi
void run() {
Discount d = amount -> amount + (amount * gstPercent / 100);
gstPercent = 28; // field ko dobara assign karna bilkul jayaz hai
System.out.println("E field captured, then changed = " + d.apply(2000));
}
E field captured, then changed = 2560
2560, 2360 nahi — lambda ne nayi value dekhi. Field tak this ke zariye pahuncha jaata hai, aur this khud effectively final hai; field heap pe rehta hai, to na kuch copy hua na koi jhooth rokna pada. Yahi standard escape hatch bhi hai: agar lambda ke andar sach mein badalne wala counter chahiye to use field ya ek-element wale array mein daal dijiye — aur phir khud se poochhiye ki saada loop behtar jawab tha ya nahi.
this — wo fark jo sach mein kaatta hai
Anonymous inner class ke andar this ka matlab hota hai wahi anonymous object. Lambda ke andar this ka matlab hai enclosing instance — yaani wo object jiske method mein aapne lambda likha. Lambda this ke liye naya scope banata hi nahi.
Task anon = new Task() {
public void go() {
System.out.println(" anon this.getClass() = " + this.getClass().getName());
System.out.println(" anon Demo.this.label = " + Demo.this.label);
}
};
Task lam = () -> {
System.out.println(" lambda this.getClass() = " + this.getClass().getName());
System.out.println(" lambda this.label = " + this.label);
};
anon this.getClass() = Demo$2
anon Demo.this.label = Hirenix-batch-2026
lambda this.getClass() = Demo
lambda this.label = Hirenix-batch-2026
Demo$2 banaam Demo — yahi ek line poora fark hai. Anonymous class ko bahar wale object tak pahunchne ke liye wo bhadda Demo.this.label likhna pada; lambda ne seedha this.label likh diya, kyunki lambda ke andar this hai hi enclosing Demo. Yahi baat khaali field ke naam ya method call pe bhi lagti hai: lambda mein wo enclosing class pe resolve hoga, anonymous class mein pehle anonymous wale pe.
Ye trivia us din se hat jaata hai jis din aap koi handler likhte hain jo this.retry() call karta hai aur chup-chaap aapko doosra object mil jaata hai.
Lambda banaam anonymous inner class — interview wali table
| Anonymous inner class | Lambda | |
|---|---|---|
| Kya implement kar sakta hai | koi bhi interface ya abstract class, kitne bhi methods | sirf wo interface jismein theek ek abstract method ho |
this |
khud wahi anonymous object | enclosing instance |
| Apne fields / state rakh sakta hai | haan | nahi |
| Bahar wale variable ka naam shadow kar sakta hai | haan | nahi — wo compile error hai |
| Compile hone pe kya banta hai | asli class file (Demo$1.class) |
koi class file banti hi nahi — ek invokedynamic call site |
| Runtime pe class ka naam | Demo$1 |
Demo$$Lambda$5/0x0000000800c02218 |
Aakhri do rows bhi trivia nahi hain; ye is sawaal ka imaandaar jawab hain ki "lambda anonymous class ka syntax sugar hi hai na?" Nahi. Demo compile karne pe do anonymous classes ke liye Demo$1.class aur Demo$2.class bane, aur lambdas ke liye kuch nahi — JVM unka implementation pehli baar use hone pe invokedynamic ke zariye khud banata hai. Print hue naam yahi dikhate hain:
D anon class = Demo$1
E lambda class = Demo$$Lambda$5/0x0000000800c02218
(Wo hex wala hissa ek memory address hai aur aapki machine pe alag aayega — baat shakl ki hai, digits ki nahi.)
Kab use karein: lambda tab use kijiye jab target type ek one-method interface ho aur body chhoti ho — Comparator, click handler, forEach ki body, koi validation rule. Java mein ab yahi default hai; aaj koi reviewer ulta ye poochhega ki aapne anonymous class kyun likhi.
Kab NAHI use karein: anonymous inner class hi rakhiye jab uske andar state chahiye (call counter, cached value), jab ek se zyada method implement karne hon ya kisi abstract class ko extend karna ho, ya jab this ka matlab wahi handler object hona chahiye. Aur jab body do-teen line se badi ho jaye to saada named method — ya loop — hi rakhiye: method call ke andar dabi nau line ki lambda us anonymous class se bhi mushkil padhne mein hoti hai jise usne hataya tha, aur na aap uska unit test likh sakte hain na saaf breakpoint laga sakte hain.
Trade-off: aapko boilerplate mein badi kami milti hai aur behaviour ko value ki tarah ghumane ki aazadi. Badle mein ek naam wala, testable, state rakhne wala object jaata hai, aur aasan stack trace bhi jaata hai — lambda ke andar ki failure lambda$main$0 ban kar dikhti hai, kisi aise method naam ki tarah nahi jo aapko kuch batata ho.
Standard definition: A lambda expression is a concise syntax, introduced in Java 8, for supplying an implementation of a functional interface — an interface with exactly one abstract method. It has the form (parameters) -> body; parameter types and the return type are supplied by the compiler through type inference against the target type. It may read local variables of the enclosing method only if they are final or effectively final, and this inside it refers to the enclosing instance, not to the lambda.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Demo {
// A one-method interface. This is the ONLY thing a lambda can be.
interface Discount {
int apply(int amount);
}
interface Task {
void go();
}
String label = "Hirenix-batch-2026";
public static void main(String[] args) {
List<String> names = List.of("Aarav", "Diya", "Ishaan", "Neha", "Rohan");
// ---------- THE OLD WAY: anonymous inner class ----------
List<String> old = new ArrayList<>(names);
Comparator<String> byLength = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};
old.sort(byLength);
System.out.println("A anonymous class = " + old);
// ---------- THE NEW WAY: the same behaviour, one line ----------
List<String> neu = new ArrayList<>(names);
neu.sort((a, b) -> a.length() - b.length());
System.out.println("B lambda = " + neu);
// ---------- ONE lambda, FOUR legal spellings ----------
Discount w1 = (int amount) -> { return amount - amount / 10; };
Discount w2 = (amount) -> { return amount - amount / 10; };
Discount w3 = amount -> { return amount - amount / 10; };
Discount w4 = amount -> amount - amount / 10;
System.out.println("C w1 " + w1.apply(2000) + " w2 " + w2.apply(2000)
+ " w3 " + w3.apply(2000) + " w4 " + w4.apply(2000));
// ---------- what each one really IS at runtime ----------
System.out.println("D anon class = " + byLength.getClass().getName());
System.out.println("E lambda class = " + w4.getClass().getName());
// ---------- capture: READING a local is fine ----------
int gstPercent = 18;
Discount withGst = amount -> amount + (amount * gstPercent / 100);
System.out.println("F captured local gstPercent = " + withGst.apply(2000));
// ---------- `this` ----------
System.out.println("G this inside anonymous class vs inside lambda:");
new Demo().show();
}
void show() {
Task anon = new Task() {
@Override
public void go() {
System.out.println(" anon this.getClass() = " + this.getClass().getName());
System.out.println(" anon Demo.this.label = " + Demo.this.label);
}
};
Task lam = () -> {
System.out.println(" lambda this.getClass() = " + this.getClass().getName());
System.out.println(" lambda this.label = " + this.label);
};
anon.go();
lam.go();
}
}Project: Student Report Card
Har Indian school ke exam office mein do log hote hain, aur dono ka kaam bilkul alag hota hai.
Pehla register sambhalta hai: har student ke har subject ki ek line, usi tarteeb mein jis tarteeb mein answer sheets wapas aayin. Aarav ka Maths, phir Aarav ka Physics, phir Aarav ki Chemistry, phir Diya ka Maths. Ye ek flat list hai. Isse padh kar koi nahi bata sakta ki Physics mein topper kaun tha.
Doosri report card chhapti hai. Data wahi, shakal bilkul alag: student ke hisaab se grouped, subtotal lagaye hue, rank kiye hue, PASS ya FAIL ki mohar ke saath. Aur mazedaar baat ye hai ki wo register ko kabhi badalti nahi. Wo use padhti hai aur uska ek view banati hai.
Wahi doosri wali stream pipeline hai, aur yahi is project ka kaam hai. Aap ek flat List<Student> se shuru karte hain — 15 rows, paanch students, teen subjects — aur di gayi list ko chhue bagair report ke aath sections nikalte hain.
Saaf kahein to, ye is chapter ka sabse zyada kaam aane wala topic hai. Har Indian interview-prep list ka "write a Java 8 program to…" wala hissa asal mein yahi project tukdon mein kata hua hai: employees ko department se group karo, students ko pass/fail mein baanto, top 3 salary nikalo, har subject ka highest mark nikalo, occurrences gino, group ka average nikalo. Report ek baar bana lijiye aur unhi paanch collectors se lagbhag das sawaal ka jawab aa jaata hai.
🌍 Real-world example: ek ed-tech company ke teacher dashboard par bilkul yahi pipeline chalti hai — subject ka class average, pass line se neeche wale students, das ki merit list. Wahan jo bug production tak pahuncha wo crash nahi tha. Chemistry mein do students 96 par tie the aur merit list mein sirf ek dikha.
limit(10)ne chup-chaap ek bachhi ko us list se hata diya jo uske maa-baap ko dikhayi ja rahi thi. Wahi bug aap section 5 mein jaan-boojh kar chalayenge.
💡 Downstream collector = wo collector jo aap
groupingByke andar dete hain, aur jo tay karta hai ki har group kis cheez mein badlega — naamon ki list, count, average, ya maximum. 💡 Partition = ek haan/na wale sawaal par theek do groups mein baant dena.partitioningByPredicateke liyegroupingByhi hai. 💡 Merit list = rank kiya hua top-N, report card ka wo hissa jise ties todte hain.
Pehla faisla: ek row dikhti kaisi hai?
Kisi bhi pipeline se pehle data model. Do raaste hain, aur beginners lagbhag hamesha galat wala chunte hain.
Lubhaane wala model ye hai ki Student object ke andar Map<String, Integer> ho — subject se marks. Padhne mein achha lagta hai, aur phir report ka har section us map ke andar haath daalta hai, use flat karta hai, wapas rakhta hai — poora project apne hi model se ladte guzar jaata hai.
Is project ka model register wala hai: ek object = ek student-subject-mark row.
class Student {
private final String name;
private final String subject;
private final int marks;
// constructor + teen getters
}
Paanch students × teen subjects = 15 flat rows. Ab har report section ek grouping ki doori par hai, kyunki grouping hi wo operation hai jo flat list ko shakal deta hai. Data ko flat rakhiye aur shakal dene ka kaam collectors par chhodiye — is project ki sabse badi seekh yahi ek line hai.
(Yahan record chhota padta. record Java 16+ hai, Java 8 nahi — isliye ye project saada class use karta hai, taaki code us bande ke yahan bhi chale jiski company aaj bhi 8 par hai.)
Data, marks 100 mein se, pass mark 33:
| Student | Maths | Physics | Chemistry |
|---|---|---|---|
| Aarav Sharma | 88 | 76 | 91 |
| Diya Patel | 94 | 82 | 67 |
| Ishaan Reddy | 29 | 45 | 58 |
| Ananya Nair | 71 | 90 | 84 |
| Kabir Singh | 55 | 31 | 62 |
Do fail marks, jaan-boojh kar. Jis data mein kuch galat hota hi nahi, us par bani report kuch sabit nahi karti.
Section 1 — pass aur fail: pehle loop, phir partitioningBy
Har seekhne wala loop leke aata hai, isliye shuruaat wahin se.
Pehle
int passLoop = 0;
int failLoop = 0;
for (Student s : marks) {
if (s.getMarks() >= PASS_MARK) passLoop++;
else failLoop++;
}
Baad mein
Map<Boolean, Long> split = marks.stream()
.collect(Collectors.partitioningBy(
s -> s.getMarks() >= PASS_MARK,
Collectors.counting()));
Dono print karte hain pass=13 fail=2.
Kya mila: sach kahein to sirf do counters ke liye — bahut kam. Loop chaar line ka hai aur poori tarah saaf hai, aur agar report ko iske aage kuch chahiye hi nahi hota to partitioningBy sirf dikhawa hota. Uski jagah banti hai doosre argument se. Wahan Collectors.counting() ek downstream collector hai, aur use Collectors.toList() se badal dijiye to do numbers ki jagah do lists mil jaati hain — baaki kuch badle bagair. Yahi loop ki chhat hai: counts ke saath lists bhi chahiye to loop mein do aur ArrayList aur do aur add ugte hain.
Do baatein jo poochhi jaati hain, dono yahin chalayi gayi hain:
keys are always both = [false, true]
partitioningBy hamesha dono keys deta hai, chahe ek taraf kuch match hi na kare. Isi data par 95 marks par partition karne wale probe mein — jo kisi ne score kiya hi nahi — true=[] mila, yaani khaali list, null nahi — jabki usi filtered data par groupingBy ne {} diya, ek aisa map jismein koi key hi nahi. Ye fark asli bug ki jad hai: groupingBy(...).get("Maths").size() us din NPE hai jis din Maths mein koi qualify na kare; partitioningBy wala jawab 0 hoga.
Aur Collectors.counting() java.lang.Long deta hai, Integer nahi — getClass().getName() print karke verify kiya gaya. Map<Boolean, Integer> compile nahi hoga.
Section 2 — subject se grouping, aur wo key order jo kaat leta hai
Pehle — haath se bana wo map jo har pre-Java-8 codebase mein milta hai:
Map<String, List<String>> bySubject = new HashMap<>();
for (Student s : marks) {
if (!bySubject.containsKey(s.getSubject()))
bySubject.put(s.getSubject(), new ArrayList<String>());
bySubject.get(s.getSubject()).add(s.getName());
}
Baad mein
Map<String, List<String>> bySubject = marks.stream()
.collect(Collectors.groupingBy(Student::getSubject, TreeMap::new,
Collectors.mapping(Student::getName, Collectors.toList())));
Teen arguments kyun, do kyun nahi. Do-argument wala roop hi har tutorial dikhata hai, aur is data par usne ye chhapa:
plain groupingBy class = HashMap
plain groupingBy keys = [Maths, Chemistry, Physics]
TreeMap::new keys = [Chemistry, Maths, Physics]
[Maths, Chemistry, Physics] na to rows ke aane ka order hai, na alphabetical — ye wahan hai jahan hash buckets ne daal diya. Jis report card ka subject order ek student jodte hi badal jaaye, us par school sign nahi karega. Teen-argument wale groupingBy ka beech wala argument map factory hai, aur TreeMap::new collect ke andar hi keys sort kar deta hai. Apna order khud tay kariye; hash table se viraasat mein mat lijiye.
Teesra argument, Collectors.mapping(Student::getName, Collectors.toList()), downstream collector hai. Iske bina Map<String, List<Student>> milta hai — poore row objects — aur phir naam nikalne ke liye ek aur loop likhna padta hai. mapping wahi tukda hai jo zyadatar log kabhi dhoondh hi nahi paate, aur uske aas-paas jugaad karne se hi saaf pipeline teen nested loops ban jaati hai.
Section 3 — averages, aur wo type jo compile hi nahi hoga
Map<String, Double> avgBySubject = marks.stream()
.collect(Collectors.groupingBy(Student::getSubject, TreeMap::new,
Collectors.averagingInt(Student::getMarks)));
Chemistry 72.40
Maths 67.40
Physics 64.80
Map ko Map<String, Integer> likh dijiye — jo aap chahte bhi yahi hain ki mark int ho — aur javac mana kar deta hai, ek aise message ke saath jise ek baar padh lene par wo kabhi darawna nahi lagta:
BadAvg.java:8: error: incompatible types: inference variable D has incompatible equality constraints Integer,Double
.collect(Collectors.groupingBy(Student::getSubject,
^
averagingInt int padhta hai aur Double lautata hai; naam ka Int input ke baare mein hai, output ke baare mein nahi. Wahi trap jo counting() ke Long lautane mein hai. Collector ka return type padhiye, uska naam nahi.
🔴 Khaali subject wala trap. Maan lijiye timetable mein Biology hai aur usmein koi baitha hi nahi. Us khaali list ka average nikalne ke do tareeqe, do alag jawab — dono yahan chalaye gaye:
averagingInt on empty = 0.0
mapToInt().average() = OptionalDouble.empty
averagingInt Biology ka class average 0.0 batata hai. Biology mein koi fail nahi hua; Biology koi le hi nahi raha tha. Pehla roop chup-chaap jhooth bolta hai aur report par wo zero chhap jaata hai jiske baare mein principal poochhenge; doosra roop type mein hi keh deta hai ki "yahan koi number hai hi nahi". Jab bhi "data nahi hai" aur "zero" ka matlab alag ho — aur report card mein hamesha alag hota hai — mapToInt(...).average() use kariye aur khaali case ko handle kariye.
Section 4 — har student ka total
Map<String, Integer> totals = marks.stream()
.collect(Collectors.groupingBy(Student::getName, TreeMap::new,
Collectors.summingInt(Student::getMarks)));
Aarav Sharma 255
Ananya Nair 245
Diya Patel 243
Ishaan Reddy 132
Kabir Singh 148
Wahi teen-argument wali shakal jo section 2 mein thi, bas downstream alag — aur yahi dohraav asli point hai. summingInt bhi boxed hi hai — collect(...) aapko java.lang.Integer deta hai, bilkul waise hi jaise counting() Long aur averagingInt Double deta hai. Asli int sirf primitive-stream wale raaste se milta hai: mapToInt(...).sum(). Collector ka return type padhiye; uske naam se andaaza mat lagaiye.
Gaur kariye ki register kabhi badla nahi. Sections 2, 3 aur 4 ne wahi 15 rows teen tareeqon se group kiye — do baar subject se, ek baar student se — aur in sabke baad bhi source list waisi ki waisi hai. "View banao, register mat badlo" ka faayda yahi hai.
Section 5 — top 3, aur wo bug jo production tak pahunchta hai
totals.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(3)
.forEach(e -> System.out.println(" " + pad(e.getKey()) + e.getValue()));
Aarav Sharma 255
Ananya Nair 245
Diya Patel 243
sorted(...) phir limit(n) — poora top-N idiom yahi hai, aur interview mein yahi "top 3 salaries / second-highest mark nikalo" bankar aata hai. Iske baare mein do baatein.
Ye muft nahi hai. sorted ek stateful operation hai: pehla element nikalne se pehle use poori stream memory mein leni padti hai aur sort karni padti hai, isliye limit(3) sort par kuch nahi bachata. Paanch students par is baat ka koi matlab nahi. Dus lakh rows mein se teen chahiye, to sab kuch sort karne se behtar ek bounded structure hai — idiom ki chhat pata honi chahiye.
🔴 Aur ye chup-chaap ties gira deta hai. Ye teen tie wali rows par chalaya gaya — Rohan Iyer 90, Meera Joshi 90, Vihaan Rao 72:
maxBy on a tie = Rohan Iyer
sorted+limit(1) on a tie = [Rohan Iyer]
everyone on the top mark = [Rohan Iyer, Meera Joshi]
limit(1) ne ek naam diya. 90 do students ke the. Na kuch throw hua, na koi warning aayi, aur Meera merit list mein hai hi nahi. Java ka sort stable hai, isliye tie us tarteeb par toota jis tarteeb mein rows aa gayi thin — yaani jiski answer sheet pehle entry hui, wahi topper.
Agar "top 3" ka matlab hai teen sabse achhe marks aur unhe paane wale sab log, to limit galat auzaar hai. Pehle cut-off mark nikaliye, phir usi par filter kariye:
int cutoff = /* teesra sabse ooncha total */;
totals.entrySet().stream().filter(e -> e.getValue() >= cutoff)
Aapki report ka matlab in dono mein se kaunsa hai — ye product ka sawaal hai, Java ka nahi. Aur ye sawaal poochhna hi ek developer ko us bande se alag karta hai jisne pipeline kisi blog se copy ki hai.
Section 6 — subject topper, aur Optional yahan kyun aa jaata hai
Map<String, Optional<Student>> topper = marks.stream()
.collect(Collectors.groupingBy(Student::getSubject, TreeMap::new,
Collectors.maxBy(Comparator.comparingInt(Student::getMarks))));
Chemistry Aarav Sharma (91)
Maths Diya Patel (94)
Physics Ananya Nair (90)
Us type mein baitha Optional<Student> pehli baar sabko khatakta hai. Ye Collectors.maxBy ki imaandari hai: khaali group ka maximum hota hi nahi, isliye type keh deta hai ki value gayab ho sakti hai, aur aap use soch-samajh kar kholte hain:
best.map(s -> s.getName() + " (" + s.getMarks() + ")").orElse("no marks")
Ek baat jaan lene laayak hai: groupingBy khaali group kabhi banata hi nahi, isliye is khaas pipeline mein Optional hamesha bhara hua rahega — aur yahi log ko .get() lagane ke liye uksata hai. Mat lagaiye. Use flat karne ka sahi tareeqa Collectors.collectingAndThen(maxBy(...), o -> o.orElse(null)) hai, aur wo wahi null wapas thama deta hai jisse aap bhaag rahe the. Map mein Optional rehne dena aksar behtar jawab hai.
Tie par maxBy ne barabar elements mein se pehla lautaya — upar Rohan Iyer. Ye section 5 wala hi chup-chaap faisla hai, bas naye bhes mein.
Section 7 — toMap, aur wo exception jiski is data mein guarantee hai
"Student se marks ka map bana do" project ki sabse aasan line lagti hai:
Map<String, Integer> flat = marks.stream()
.collect(Collectors.toMap(Student::getName, Student::getMarks));
java.lang.IllegalStateException: Duplicate key Aarav Sharma (attempted merging values 88 and 76)
Doosri hi row par phat jaata hai. Aarav ki teen rows hain — Maths, Physics, Chemistry — aur toMap ko pata hi nahi ki in teenon mein se aapka matlab kaunsi thi, isliye wo andaza lagane ke bajaye mana kar deta hai. Ye is project mein koi kona nahi hai; ye data ki shakal hai. Jo bhi flat register kisi non-unique field par keyed ho, wahan yahi hoga.
Iska ilaaj toMap ka teesra argument hai, ek merge function jo batata hai ki ek key ki do values ka kya karna hai:
Map<String, Integer> bestMark = marks.stream()
.collect(Collectors.toMap(Student::getName, Student::getMarks,
Integer::max, TreeMap::new));
{Aarav Sharma=91, Ananya Nair=90, Diya Patel=94, Ishaan Reddy=58, Kabir Singh=62}
Integer::max ka matlab hai "zyada wala mark rakho" — to ab ye map har student ka best subject score hai, ek alag report line, jaan-boojh kar chuni gayi. Integer::sum totals deta; (a, b) -> a pehla rakh leta. Chautha argument wahi map factory wala idea hai jo groupingBy mein tha, aur TreeMap::new ki wajah se naam alphabetical order mein aate hain.
Niyam: agar aap bol kar nahi bata sakte ki key unique kyun hai, to merge function dijiye. Ye IllegalStateException achhi failure hai — zor se hoti hai, foran hoti hai, aur galat key ka naam bhi le leti hai.
Section 8 — chhapi hui card, jo loop hi rehti hai
Aakhri section har student ki card chhapta hai: teen subject lines, ek total, ek percentage, PASS/FAIL ki mohar. Dekhne mein report ka sabse "stream jaisa" hissa lagta hai. Ye loop hai, aur loop hi rehna chahiye.
for (Map.Entry<String, List<Student>> entry : byStudent.entrySet()) {
List<Student> rows = entry.getValue();
int total = rows.stream().mapToInt(Student::getMarks).sum();
boolean passed = rows.stream().allMatch(s -> s.getMarks() >= PASS_MARK);
System.out.println(" " + entry.getKey());
for (Student s : rows) { /* har subject ki ek line */ }
/* TOTAL wali line */
}
Body print karti hai — yaani side effect — aur paanch alag lines chhapti hai jinka text group se nikale values par tika hai. Yahan pipeline ka matlab hota ek forEach jiske andar multi-statement lambda block ho: wahi code, saath mein { } aur peechhe );, aur haasil kuch nahi. Streams values banane ke liye hain, aur ye section koi value banata hi nahi.
Ye zaroor dekhiye ki stream kya hua: loop ki body ke andar mapToInt(...).sum() aur allMatch(...), kyunki ye do sach mein group ke baare mein value-wale sawaal hain. Mila-jula hi sahi jawab hai, aur jis codebase mein har loop pipeline ban gaya wo utni hi badboo deta hai jitna wo jismein ek bhi nahi bana.
Ishaan Reddy
Maths 29 F
Physics 45 P
Chemistry 58 P
TOTAL 132 44.00% FAIL
Wo FAIL ki mohar allMatch lagata hai, aur wo short-circuit karta hai — Maths par hi ruk jaata hai, baaki do ko dekhta hi nahi. Paanch students par ye dikhta nahi; aadat maayne rakhti hai.
Wo interview sawaal jinka jawab ye akela program de deta hai
| Sawaal, jaise poochha jaata hai | Section |
|---|---|
| employees ko department se group karo | 2 — groupingBy |
| har group mein occurrences gino | 1 — groupingBy/partitioningBy + counting() |
| har department ki average salary | 3 — averagingInt |
| har group ka sum | 4 — summingInt |
| top 3 / highest / second-highest nikalo | 5 — sorted(...).limit(n) |
| har department ka sabse zyada salary wala employee | 6 — maxBy |
| list ko condition par do hisson mein baanto | 1 — partitioningBy |
| list ko map mein badlo | 7 — toMap aur uska merge function |
| list mein duplicates dhoondho | 7 — duplicate key khud hi duplicate detector hai |
| sab/koi element condition poori karta hai kya | 8 — allMatch |
Das sawaal, ek program, paanch collectors. Chapter mein isi jagah ye project isliye hai.
Faisla
Kab use karein: collector pipeline tab uthaiye jab aap ek flat list ko shakal de rahe hon — grouped, counted, averaged, ranked, keyed. Downstream collector ke saath teen-argument wala groupingBy containsKey/put/get ka poora natak aur ek nested inner loop, dono ko ek expression mein khatam kar deta hai — aur teen-chaar report sections tak wo padhne laayak bana rehta hai, jo 60-line ka loop nahi rehta.
Kab NAHI use karein: loop tab rakhiye jab section compute karne ke bajaye print ya write karta ho (section 8), jab aapko row ka index chahiye ho, ya jab ek hi pass mein ek se zyada aapas mein judi counters chalani hon. Paanch statement wale lambda block wala forEach bhes badla hua loop hai — loop hi likh dijiye.
Trade-off: pipeline kaise ka kaam JDK ko de deti hai, aur JDK ke defaults aapki report ke defaults nahi hain. Teen defaults yahan asli keemat maangte hain: groupingBy HashMap deta hai jiske order par bharosa nahi kiya ja sakta, sorted ke baad limit(n) tie wale students ko bina bole gira deta hai, aur averagingInt khaali group ko "data nahi hai" ke bajaye 0.0 bata deta hai. Loop aapse ye faisle likhwata hai; collector aapse ye faisle jaanne ki maang karta hai. Sauda yahi hai — code kam, jaankari zyada zaroori, aur failures chup-chaap wali.
Khud kar ke dekhiye
- Section 3 ko har subject par
mapToInt(Student::getMarks).average()mein badliye aurOptionalDoubleseedha print kariye. Phir ek khaali Biology list jodiye aur dekhiye ki dono averaging styles kaise alag jawab dete hain. Principal ko aap kaunsa dikhayenge? - Ek chautha student jodiye jiska total 255 ho — Aarav ke saath poora tie — aur section 5 dobara chalaiye. Phir use cut-off filter ki tarah likhiye taaki dono dikhein. Dono versions kitni lines maangte hain, giniye.
- Section 7 mein
Integer::maxki jagahInteger::sumaur(a, b) -> arakh kar dekhiye. Teen merge functions, ek hi pipeline se teen bilkul alag report lines. Har ek ko naam dijiye. - Section 2 se
TreeMap::newhata dijiye aur keys ke saathbySubject.getClass().getSimpleName()bhi print kariye. Chhatha student jod kar phir chalaiye — kya subject order hil gaya? - Section 8 mein subject-wise rank ka column jodiye. Uske liye sorted group ke andar ki position chahiye, yaani theek wahi index jise stream pheink deta hai. Pehle pipeline se kariye, phir loop se, aur jise code review mein defend kar sakein wahi merge kariye.
Standard definition: Flat List par report banane ka tareeqa ye hai ki source list ko badla na jaaye aur har section ek collector se derive kiya jaaye: pass/fail ke split ke liye partitioningBy (dono keys hamesha maujood), per-group lists, counts (counting() → Long), averages (averagingInt → Double) aur sums (summingInt → Integer, boxed like the rest) ke liye map factory aur downstream collector wala teen-argument groupingBy, top-N ke liye sorted(...).limit(n) jo ties ko chup-chaap gira deta hai, per-group maximum ke liye maxBy jo Optional lautata hai, aur jahan key unique na ho wahan merge function ke saath toMap — jabki jo sections compute karne ke bajaye print karte hain, wo saadhaaran loop hi rehte hain.
import java.util.*;
import java.util.stream.*;
public class StudentReport {
static final int PASS_MARK = 33;
public static void main(String[] args) {
List<Student> marks = Data.sample();
System.out.println("== Hirenix Class XII - Term 1 report ==");
// ---- 1) how many passed? loop first, then the pipeline ----
int passLoop = 0;
int failLoop = 0;
for (Student s : marks) {
if (s.getMarks() >= PASS_MARK) {
passLoop++;
} else {
failLoop++;
}
}
System.out.println("1) loop pass=" + passLoop + " fail=" + failLoop);
Map<Boolean, Long> split = marks.stream()
.collect(Collectors.partitioningBy(
s -> s.getMarks() >= PASS_MARK,
Collectors.counting()));
System.out.println("1) partitioned pass=" + split.get(true) + " fail=" + split.get(false));
System.out.println(" keys are always both = " + split.keySet());
// ---- 2) grouping: who sat for which subject ----
Map<String, List<String>> bySubject = marks.stream()
.collect(Collectors.groupingBy(Student::getSubject, TreeMap::new,
Collectors.mapping(Student::getName, Collectors.toList())));
System.out.println("2) students per subject");
bySubject.forEach((sub, names) -> System.out.println(" " + pad(sub) + names));
// ---- 3) averages per subject ----
Map<String, Double> avgBySubject = marks.stream()
.collect(Collectors.groupingBy(Student::getSubject, TreeMap::new,
Collectors.averagingInt(Student::getMarks)));
System.out.println("3) subject average");
avgBySubject.forEach((sub, avg) ->
System.out.println(" " + pad(sub) + String.format("%.2f", avg)));
// ---- 4) totals per student ----
Map<String, Integer> totals = marks.stream()
.collect(Collectors.groupingBy(Student::getName, TreeMap::new,
Collectors.summingInt(Student::getMarks)));
System.out.println("4) totals out of 300");
totals.forEach((name, total) -> System.out.println(" " + pad(name) + total));
// ---- 5) top 3 ----
System.out.println("5) top 3 by total");
totals.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(3)
.forEach(e -> System.out.println(" " + pad(e.getKey()) + e.getValue()));
// ---- 6) subject topper: maxBy hands back an Optional ----
Map<String, Optional<Student>> topper = marks.stream()
.collect(Collectors.groupingBy(Student::getSubject, TreeMap::new,
Collectors.maxBy(Comparator.comparingInt(Student::getMarks))));
System.out.println("6) subject topper");
topper.forEach((sub, best) -> System.out.println(" " + pad(sub)
+ best.map(s -> s.getName() + " (" + s.getMarks() + ")").orElse("no marks")));
// ---- 7) the toMap trap: one student has three rows ----
System.out.println("7) toMap name -> marks");
try {
Map<String, Integer> flat = marks.stream()
.collect(Collectors.toMap(Student::getName, Student::getMarks));
System.out.println(" " + flat);
} catch (IllegalStateException e) {
System.out.println(" " + e.getClass().getName() + ": " + e.getMessage());
}
Map<String, Integer> bestMark = marks.stream()
.collect(Collectors.toMap(Student::getName, Student::getMarks,
Integer::max, TreeMap::new));
System.out.println(" with a merge function = " + bestMark);
// ---- 8) the printed report card. This is a LOOP on purpose. ----
Map<String, List<Student>> byStudent = marks.stream()
.collect(Collectors.groupingBy(Student::getName, TreeMap::new,
Collectors.toList()));
System.out.println("8) report cards");
for (Map.Entry<String, List<Student>> entry : byStudent.entrySet()) {
List<Student> rows = entry.getValue();
int total = rows.stream().mapToInt(Student::getMarks).sum();
boolean passed = rows.stream().allMatch(s -> s.getMarks() >= PASS_MARK);
System.out.println(" ------------------------------");
System.out.println(" " + entry.getKey());
for (Student s : rows) {
System.out.println(String.format(" %-10s %3d %s",
s.getSubject(), s.getMarks(), s.getMarks() >= PASS_MARK ? "P" : "F"));
}
System.out.println(String.format(" %-10s %3d %.2f%% %s",
"TOTAL", total, total / 3.0, passed ? "PASS" : "FAIL"));
}
}
static String pad(String s) {
return String.format("%-14s", s);
}
}
class Student {
private final String name;
private final String subject;
private final int marks;
Student(String name, String subject, int marks) {
this.name = name;
this.subject = subject;
this.marks = marks;
}
String getName() { return name; }
String getSubject() { return subject; }
int getMarks() { return marks; }
}
class Data {
static List<Student> sample() {
List<Student> list = new ArrayList<>();
list.add(new Student("Aarav Sharma", "Maths", 88));
list.add(new Student("Aarav Sharma", "Physics", 76));
list.add(new Student("Aarav Sharma", "Chemistry", 91));
list.add(new Student("Diya Patel", "Maths", 94));
list.add(new Student("Diya Patel", "Physics", 82));
list.add(new Student("Diya Patel", "Chemistry", 67));
list.add(new Student("Ishaan Reddy", "Maths", 29));
list.add(new Student("Ishaan Reddy", "Physics", 45));
list.add(new Student("Ishaan Reddy", "Chemistry", 58));
list.add(new Student("Ananya Nair", "Maths", 71));
list.add(new Student("Ananya Nair", "Physics", 90));
list.add(new Student("Ananya Nair", "Chemistry", 84));
list.add(new Student("Kabir Singh", "Maths", 55));
list.add(new Student("Kabir Singh", "Physics", 31));
list.add(new Student("Kabir Singh", "Chemistry", 62));
return list;
}
}Java 8 aur Functional Programminginterview questions & answers
10 sample questions below — 239+ in the full bank inside.
Koi purani library aapko java.util.Date deti hai. Use LocalDate mein kaise badlenge, aur wapas?
Dono taraf ek-ek line. Purani se nayi: LocalDate d = legacy.toInstant().atZone(ZoneId.of("Asia/Kolkata")).toLocalDate(); Nayi se purani: java.util.Date back = java.util.Date.from(zdt.toInstant()); Maine 15:30 IST wale slot par poora round trip chalaya aur wapas 2026-08-24 mila. Isse chhota tareeka isliye nahi hai kyunki java.util.Date UTC timeline par ek point hai, calendar date nahi, to use calendar date banane ke liye ye batana padta hai ki kiska calendar -- aur atZone wahi deta hai. Conversion ek hi baar kijiye, us boundary par jahan purani library value deti hai, aur apne code ke andar har jagah java.time istemaal kijiye.
In simple terms: Syntax se zyada mayne ye rakhta hai ki conversion kahan rakha jaaye. Purani API ko airport ke currency exchange counter jaisa samajhiye: paisa aate waqt ek baar badla, jaate waqt ek baar, aur poori trip mein do currencies leke nahi ghoome. Jo codebase business logic ke beech mein baar-baar aage-peechhe convert karta hai, wahan har method signature mein dono APIs aa jaati hain aur dono ka nuksaan milta hai. Ek baareek baat kehne laayak hai: atZone ko diya gaya zone ek asli faisla hai, boilerplate nahi. IST mein bhari gayi value se bani Date agar atZone(ZoneOffset.UTC) se padhi jaaye to raat ke waqt wali kisi bhi value ke liye ek din pehle ki nikal sakti hai, kyunki 2026-08-24T00:30 IST UTC mein 2026-08-23 hai. Wahi zone dijiye jo aapke data ka asli matlab hai -- Indian product ke liye Asia/Kolkata -- na ki system default, jo server badalte hi badal jaata hai.
collect(), Collector aur Collectors ka aapas mein rishta kya hai?
Ye teen alag cheezein hain jinke naam lagbhag ek jaise dikhte hain. collect() ek terminal operation hai -- Stream par ek method, jo pipeline ko sach mein chalata hai aur har bache element ko ek container mein daal deta hai. Collector java.util.stream ka ek interface hai jo batata hai ki wo container BANEGA kaise: supplier khaali container banata hai, accumulator ek element daalta hai, combiner do container jodta hai, aur finisher aakhri touch-up karta hai. Collectors ek final utility class hai jisme sirf static factory methods hain jo ready-made Collector object dete hain -- toList, toSet, toMap, counting, joining, groupingBy, partitioningBy. Isliye collect(Collectors.toList()) aise padha jaata hai: pipeline chalao, aur natije ko toList recipe se banao.
In simple terms: Kitchen wali misaal seedhi baith jaati hai: collect() cook hai, Collector batata hai ki recipe cheez kya hoti hai, aur Collectors shelf par rakhi recipe book hai. Plural s hi ishara hai, bilkul jaise Collections ka rishta Collection se hai. Thos misaal: paanch students ke batch par batch.stream().filter(s -> s.marks >= 50).map(s -> s.name).collect(Collectors.toList()) ne [Aarav, Ishaan, Rohan] chhapa. collect() se pehle kisi ne kaam kiya hi nahi tha -- filter aur map lazy hain, aur elements ko kheenchta terminal collect() hi hai. Fresher se custom Collector kabhi likhwaya nahi jaata; marks in teenon ko alag-alag pehchanne par milte hain.
LocalDate, LocalTime aur LocalDateTime ko ek-ek udaharan ke saath samjhaiye.
Har ek utni hi information rakhti hai jitni uske kaam ko chahiye, ek bhi field zyada nahi. LocalDate sirf date hai -- saal, mahina, din -- to LocalDate.of(2026, 8, 24) chhapta hai 2026-08-24, aur ye date of birth, joining date ya EMI due date ke liye sahi hai. LocalTime sirf time hai -- ghanta, minute, second -- to LocalTime.of(9, 30) chhapta hai 09:30, aur ye shift start ya lunch break ke liye sahi hai. LocalDateTime dono saath mein hai par bina kisi timezone ke: LocalDateTime.of(2026, 8, 24, 15, 30) chhapta hai 2026-08-24T15:30, yaani interview slot bilkul waisa jaisa letter par likha hai. Teenon constructor ke bajaye static of(...) factory methods se bante hain, teenon immutable hain, aur teenon ke paas ek now() hai jo system clock padhta hai. Asli chaabi shabd Local hai -- iska matlab hai ki koi timezone information saath nahi hai.
In simple terms: Naam hi logon ko phansa deta hai, kyunki Local sunne mein lagta hai aapka local timezone, jabki matlab ulta hai: koi zone hai hi nahi. LocalDate wo date hai jo deewar par tanga calendar dikhata hai. Date of birth ke taur par 15 March 2004 Pune mein bhi wahi value hai aur London mein bhi -- uspar zone chipkana matlab aisi information gadhna jo aapke paas hai hi nahi, aur yahi wajah hai ki server UTC par chale aur users IST par hon to birthday ek din khisak jaata hai. Chunne ka practical tareeka ye hai ki poochhiye field asal mein hai kya. Kya usme time chahiye? Date of birth mein nahi -- LocalDate. Kya usme date chahiye? Dukaan ke opening time mein nahi -- LocalTime. Kya dono chahiye par zone context se saaf hai aur value aapke system se bahar jaati hi nahi? LocalDateTime. Jis lamhe do alag jagah ke log ek hi waqt par raazi hone chahiye, in teenon mein se koi kaafi nahi aur ZonedDateTime chahiye.
Supplier aur Consumer kya hain?
Ye ek dusre ke aaine jaise do shapes hain. Consumer<T> ek object leta hai aur kuch return nahi karta -- iska ek abstract method accept(T) hai jo void declare hua hai, isliye ye sirf side effect ke liye hota hai jaise print karna, log karna, ya ek row save karna. Supplier<T> ulta hai: ye koi argument leta hi nahi aur get() se ek object bana kar deta hai. To Consumer<Student> audit = s -> System.out.println("AUDIT " + s.name) aur Supplier<List<String>> batch = ArrayList::new ek hi axis ke do sire hain. Consumer ke paas ek default method andThen bhi hai, jo ek hi input pe do consumers ko order mein chalata hai; Supplier ke paas kuch bhi nahi -- JDK 17 pe reflection sirf abstract get dikhati hai.
In simple terms: Chaaron core interfaces ko yaad rakhne ka saaf tareeka data ke behne ki disha hai. Consumer matlab data andar aaya aur wahin ruk gaya -- ek letterbox. Supplier matlab data kahin se nahi aaya aur bahar chala gaya -- ek ticket machine jise aap bina kuch diye dabate hain. Predicate aur Function dono kuch lete hain aur kuch wapas dete hain; fark sirf itna hai ki kya dete hain. Kyunki Consumer.accept void hai, compiler ye shape khud enforce karta hai: Consumer<String> c = name -> { return name.length(); }; likhne pe JDK 17 pe error aata hai -- incompatible types: bad return type in lambda expression aur uske neeche unexpected return value -- yaani compiler bata raha hai ki aapko Function<String, Integer> chahiye tha.
Predicate kya hai aur aap ise kab use karenge?
Predicate<T> haan/naa wala shape hai: ye T type ka ek object leta hai aur boolean deta hai, aur iska ek abstract method test(T) hai. Ise wahan use karte hain jahan aapke purane code mein isValid, isEligible ya shouldSkip naam ka boolean lautane wala helper hota tha -- Student pe scholarship ka check, parcel pe pincode ka check, form field pe email format ka check. Ise private method ke bajaye Predicate likhne ki wajah ye hai ki Predicate ek value hai: aap use variable mein rakh sakte hain, kisi aur method mein pass kar sakte hain, unki List bana sakte hain, aur and, or, negate se jod sakte hain.
In simple terms: Boolean method aur Predicate hisaab wahi karte hain, par idhar-udhar sirf ek hi bheja jaa sakta hai. boolean isEligible(Student s) ek class se chipka hua verb hai; Predicate<Student> eligible = s -> s.marks >= 75 ek noun hai jise aap Map<String, Predicate<Student>> mein daal kar user ko dropdown se chunne de sakte hain. Interface ke hone ki poori wajah yahi hai. Predicate teen combinators bhi default methods ki tarah rakhta hai, aur JDK 17 pe reflection ye batwara saaf dikhati hai: test ABSTRACT hai, and, or aur negate default hain, aur isEqual aur not static hain. Yaani iske paas ab bhi theek ek abstract method hai aur ye ek bilkul aam functional interface hi rehta hai.
Collectors class ke paanch methods ke naam batayiye aur ye ki har ek kya lautata hai.
toList() ek List deta hai -- practically ArrayList, aur wo mutable hai. toSet() ek Set deta hai -- HashSet, mutable aur bina order ke, jisse duplicates hatte hain. toMap(keyFn, valueFn) ek HashMap deta hai, yaani list ko lookup table bana deta hai. counting() Long deta hai, Integer nahi. joining(separator, prefix, suffix) ek chhapne laayak String deta hai. In paanch ke alawa summingInt(f) Integer deta hai, averagingInt(f) Double deta hai, aur groupingBy tatha partitioningBy buckets ki Map dete hain -- interview ke zyadatar coding sawaal wahi par khade hote hain.
In simple terms: Inhe yaad rakhne ka sabse kaam ka tareeka return type se hai, kyunki aapke code ki agli line ko wahi cheez lena hoti hai. Aarav/Maths/82, Diya/Physics/47, Ishaan/Maths/91, Neha/Physics/38, Rohan/Chemistry/65 wale batch par asli output ye nikla: counting() = 5, summingInt(s -> s.marks) = 323, averagingInt(s -> s.marks) = 64.6, aur naamon par joining(', ', '[', ']') = [Aarav, Diya, Ishaan, Neha, Rohan]. Dhyaan dijiye ki shapes bilkul alag hain -- ek number, ek number, ek decimal, ek string -- wahi paanch objects se. Collector ek report format hai, aur sahi collector chunna yahi tay karna hai ki report dikhegi kaisi.
Java 8 ke saath pehle se bane hue functional interfaces aaye. Wo kis package mein hain, aur unki categories kya hain?
Ye java.util.function package mein hain, aur inhe naam se nahi balki shape se organise kiya gaya hai -- kya andar jaata hai aur kya bahar aata hai. Chaar core shapes hain: Predicate<T> ek object leta hai aur boolean deta hai (test), Function<T,R> ek object leta hai aur dusra object deta hai (apply), Consumer<T> ek object leta hai aur kuch nahi deta (accept), aur Supplier<T> kuch nahi leta aur ek object deta hai (get). Package ka baaki sab inhi chaar ka variation hai: do-argument wale Bi* roop, same-type shortcuts UnaryOperator aur BinaryOperator, aur IntPredicate ya ToIntFunction jaisi primitive specialisations. JDK 17 pe maine package list karke dekha -- usmein 43 interfaces hain, jo tab tak darata hai jab tak samajh na aaye ki ye chaar shapes ke kuch variations hain.
In simple terms: Pune ka ek chhota courier office sochiye. Poore din mez pe sirf chaar kism ki request aati hai: koi parcel ke baare mein haan/naa poochta hai, koi parcel ko receipt mein badalne ko kehta hai, koi parcel pe mohar lagwa kar wapas kuch nahi maangta, aur koi bina kuch diye ek naya khaali form maangta hai. Andar ka saamaan din bhar mein hazaar baar badalta hai; ye chaar shapes nahi badalte. Theek yahi cheez java.util.function mein likhi hui hai. Kaam ka tareeka ye hai ki ise list ki jagah grid ki tarah yaad rakhiye: poochiye 'argument leta hai kya?' aur 'kuch return karta hai kya?' -- interface seconds mein nikal aayega. Argument nahi + return haan = Supplier, argument haan + return nahi = Consumer, argument haan + boolean = Predicate, argument haan + koi aur cheez = Function.
Java 8 ki Date/Time API kaun se packages mein hai, aur uski teen sabse important classes kaun si hain?
Asli package java.time hai -- wahin LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, ZoneId aur Year rehte hain. Uske saath do sub-packages mayne rakhte hain: java.time.format, jisme DateTimeFormatter aur DateTimeParseException hain, aur java.time.temporal, jisme units aur fields hain -- sabse kaam ka ChronoUnit. Do aur hain jinhe aap shaayad hi chhuein -- java.time.zone timezone ke rules ke data ke liye, aur java.time.chrono non-ISO calendar systems ke liye jaise Hijrah ya Japanese calendar. Agar teen classes ka naam lena ho: plain calendar date ke liye LocalDate, time ke saath par bina zone ke LocalDateTime, aur aisa lamha jise timezone saaf kar deta hai uske liye ZonedDateTime. Rozmarra ke code mein Instant aur DateTimeFormatter bhi utni hi baar aate hain.
In simple terms: Package ka batwara sirf sajaawat nahi hai, wo batata hai ki har cheez hai kya. java.time mein values hain -- aise objects jo khud ek date ya ek lambai hain. java.time.format mein wo machinery hai jo un values ko text mein aur text se wapas badalti hai, jo bilkul alag kaam hai aur yahi wajah hai ki formatter ek alag object hai jise aap configure aur share kar sakte hain. java.time.temporal mein vocabulary hai -- ChronoUnit.DAYS, ChronoUnit.MONTHS -- taaki between(start, end) kisi bhi unit mein poochha ja sake aur har class ko apna alag daysBetween method na rakhna pade. Practically ek hi import logon ko chaunkata hai: ChronoUnit java.time mein nahi hai, isliye sirf import java.time.* likhne se wo nahi milta aur import java.time.temporal.ChronoUnit chahiye hota hai. Class kis package mein hai ye chhoti baat hai, par interviewer ise hi istemaal karta hai ye pehchanne ke liye ki aapne padha bhar hai ya istemaal bhi kiya hai.
Aapke paas List<Student> hai jisme name, subject aur marks hain. Ise subject-wise group kaise karenge?
batch.stream().collect(Collectors.groupingBy(s -> s.subject)). Us lambda ko classifier kehte hain -- wo jo lautata hai wahi map ki key ban jaati hai -- aur groupingBy ek Map deta hai jiski keys classifier ke alag-alag natije hain aur values har bucket mein gire elements ki List. Yahan type Map<String, List<Student>> hai aur output aaya {Maths=[Aarav(Maths,82), Ishaan(Maths,91)], Chemistry=[Rohan(Chemistry,65)], Physics=[Diya(Physics,47), Neha(Physics,38)]}. Ye Stream API ka SQL GROUP BY hai, aur nested loop plus map.computeIfAbsent ka poora tamasha ek line mein badal deta hai.
In simple terms: Tasveer ye hai: ek clerk ke paas mark sheets ka dher hai aur saamne khaali trays ki qataar. Wo har sheet par subject padhkar use sahi tray mein daal deta hai, aur naya subject pehli baar dikhne par nayi tray rakh leta hai. Yahi aakhri baat aage ke sawaal mein wapas aati hai: groupingBy bucket tabhi banata hai jab usme sach mein kuch gire, isliye jo subject kisi ne liya hi nahi uski key hoti hi nahi. Ye bhi kaam ka hai: value wali lists java.util.ArrayList nikleen, yaani mutable, aur map khud java.util.HashMap thi.
Ye kya chhapega, aur isme galti kya hai? LocalDate emi = LocalDate.of(2026, 1, 31); emi.plusDays(1); System.out.println(emi);
Ye chhapega 2026-01-31 -- bilkul waisa hi, badla hua nahi. java.time ki har class immutable hai, isliye plusDays ek NAYA LocalDate lautata hai aur original ko chhoota tak nahi; lauta hua object phenk diya gaya, isliye us line ne kuch kiya hi nahi. Ye bina kisi warning ke compile hota hai kyunki emi.plusDays(1); ek bilkul valid expression statement hai, theek waise jaise apni line par "abc".toUpperCase();. Fix ek character ka hai: emi = emi.plusDays(1);, phir ye 2026-02-01 chhapega. Yahi baat un sabhi methods par laagu hai jo mutator jaise dikhte hain -- minusMonths, withDayOfMonth, plusYears. Maine emi.withDayOfMonth(5) chalaya aur emi phir bhi 2026-01-31 tha jabki lauti hui value 2026-01-05 thi.
In simple terms: Yahan immutability koi bahes karne wali design ki raay nahi hai, wo in classes ka gun hai, aur uske do chehre hain. Pehle hi din kaatne wala chehra yahi bug hai: lauti hui value HI jawab hai, to use phenkna poora operation phenk dena hai. Aise sochiye jaise aapne kisi se poochha ki 31 January mein ek din jodo to kya hoga -- wo aapko jawab bata dega, aapka calendar ja kar nahi badlega. Doosra chehra faayda hai, aur yahi wajah hai ki API aise banayi gayi. Kyunki LocalDate kabhi badal hi nahi sakti, aap use static final constant bana sakte hain, Map ki key bana sakte hain bina map ke chupchaap toote, threads mein bina lock ke share kar sakte hain, aur kisi bhi method ko de sakte hain ye jaante hue ki koi use bigaad nahi sakta. Yahi java.util.Date ka bug -- jisme setTime() tha -- jad se theek kiya gaya hai, defensive copies se patch nahi kiya gaya.
229+ more Java 8 aur Functional Programming questions inside
Create a free account to read the full question bank, learn every topic, and practise with an AI mock interview.
Unlock all questions — freeReady to practise Java 8 aur Functional Programming?
Unlock every topic free, then face an AI interviewer that asks follow-ups and grades your answers.