ఈ వ్యాసం ఎవరి కోసం?
మెటీరియల్ ఏ విద్యాసంబంధమైన విలువను కలిగి ఉండదు, కొత్తదనాన్ని విడనాడదు. చాలా విరుద్ధంగా: నేను సంక్లిష్టమైన (కొంతమంది వ్యక్తులకు) వీలైనంత సరళంగా వివరించడానికి ప్రయత్నిస్తాను. స్ట్రీమ్ APIని వివరించమని చేసిన అభ్యర్థన దీన్ని వ్రాయడానికి నన్ను ప్రేరేపించింది. నేను దాని గురించి ఆలోచించాను మరియు లాంబ్డా వ్యక్తీకరణల గురించి అవగాహన లేకుండా నా స్ట్రీమ్ ఉదాహరణలు కొన్ని అర్థం చేసుకోలేవని నిర్ణయించుకున్నాను. కాబట్టి మేము లాంబ్డా వ్యక్తీకరణలతో ప్రారంభిస్తాము.
- ఇది ఈ వ్యాసం యొక్క మొదటి భాగాన్ని చదివిన వ్యక్తుల కోసం ;
- ఇది ఇప్పటికే జావా కోర్ గురించి బాగా తెలుసని భావించే వ్యక్తుల కోసం, కానీ జావాలో లాంబ్డా ఎక్స్ప్రెషన్ల గురించి ఎటువంటి క్లూ లేదు. లేదా లాంబ్డా వ్యక్తీకరణల గురించి వారు ఏదైనా విన్నారు, కానీ వివరాలు లేవు.
- లాంబ్డా ఎక్స్ప్రెషన్ల గురించి కొంత అవగాహన ఉన్న, కానీ ఇప్పటికీ వాటిని చూసి భయపడి, వాటిని ఉపయోగించడం అలవాటు లేని వ్యక్తుల కోసం ఇది.

బాహ్య వేరియబుల్స్ యాక్సెస్
ఈ కోడ్ అనామక తరగతితో కంపైల్ చేస్తుందా?
int counter = 0;
Runnable r = new Runnable() {
@Override
public void run() {
counter++;
}
};
సంఖ్య. counter
వేరియబుల్ తప్పనిసరిగా ఉండాలి final
. లేదా కాకపోతే final
, కనీసం దాని విలువను మార్చలేరు. అదే సూత్రం లాంబ్డా వ్యక్తీకరణలకు వర్తిస్తుంది. వారు ప్రకటించబడిన స్థలం నుండి వారు "చూడగల" అన్ని వేరియబుల్స్ను యాక్సెస్ చేయగలరు. కానీ లాంబ్డా వాటిని మార్చకూడదు (వాటికి కొత్త విలువను కేటాయించండి). అయితే, అనామక తరగతుల్లో ఈ పరిమితిని దాటవేయడానికి ఒక మార్గం ఉంది. రిఫరెన్స్ వేరియబుల్ని సృష్టించండి మరియు వస్తువు యొక్క అంతర్గత స్థితిని మార్చండి. అలా చేయడం వలన, వేరియబుల్ కూడా మారదు (ఒకే వస్తువుకు పాయింట్లు) మరియు సురక్షితంగా final
.
final AtomicInteger counter = new AtomicInteger(0);
Runnable r = new Runnable() {
@Override
public void run() {
counter.incrementAndGet();
}
};
ఇక్కడ మన counter
వేరియబుల్ ఒక వస్తువుకు సూచన AtomicInteger
. మరియు incrementAndGet()
ఈ వస్తువు యొక్క స్థితిని మార్చడానికి పద్ధతి ఉపయోగించబడుతుంది. ప్రోగ్రామ్ నడుస్తున్నప్పుడు వేరియబుల్ విలువ మారదు. ఇది ఎల్లప్పుడూ ఒకే వస్తువును సూచిస్తుంది, ఇది చివరి కీవర్డ్తో వేరియబుల్ను ప్రకటించడానికి అనుమతిస్తుంది. ఇక్కడ అదే ఉదాహరణలు ఉన్నాయి, కానీ లాంబ్డా వ్యక్తీకరణలతో:
int counter = 0;
Runnable r = () -> counter++;
ఇది అనామక తరగతితో ఉన్న సంస్కరణ వలె అదే కారణంతో కంపైల్ చేయబడదు: counter
ప్రోగ్రామ్ నడుస్తున్నప్పుడు మార్చకూడదు. కానీ మనం ఇలా చేస్తే అంతా బాగుంటుంది:
final AtomicInteger counter = new AtomicInteger(0);
Runnable r = () -> counter.incrementAndGet();
ఇది కాలింగ్ పద్ధతులకు కూడా వర్తిస్తుంది. లాంబ్డా ఎక్స్ప్రెషన్లలో, మీరు అన్ని "కనిపించే" వేరియబుల్స్ను యాక్సెస్ చేయడమే కాకుండా, ఏవైనా యాక్సెస్ చేయగల పద్ధతులను కూడా కాల్ చేయవచ్చు.
public class Main {
public static void main(String[] args) {
Runnable runnable = () -> staticMethod();
new Thread(runnable).start();
}
private static void staticMethod() {
System.out.println("I'm staticMethod(), and someone just called me!");
}
}
ప్రైవేట్ అయినప్పటికీ staticMethod()
, ఇది main()
పద్ధతి లోపల అందుబాటులో ఉంటుంది, కాబట్టి దీనిని పద్ధతిలో సృష్టించబడిన లాంబ్డా లోపల నుండి కూడా పిలుస్తారు main
.
లాంబ్డా వ్యక్తీకరణ ఎప్పుడు అమలు చేయబడుతుంది?
మీరు ఈ క్రింది ప్రశ్న చాలా సరళంగా ఉండవచ్చు, కానీ మీరు దానిని అదే విధంగా అడగాలి: లాంబ్డా వ్యక్తీకరణ లోపల కోడ్ ఎప్పుడు అమలు చేయబడుతుంది? ఇది ఎప్పుడు సృష్టించబడుతుంది? లేదా దీనిని పిలిచినప్పుడు (ఇది ఇంకా తెలియదు)? దీన్ని తనిఖీ చేయడం చాలా సులభం.
System.out.println("Program start");
// All sorts of code here
// ...
System.out.println("Before lambda declaration");
Runnable runnable = () -> System.out.println("I'm a lambda!");
System.out.println("After lambda declaration");
// All sorts of other code here
// ...
System.out.println("Before passing the lambda to the thread");
new Thread(runnable).start();
స్క్రీన్ అవుట్పుట్:
Program start
Before lambda declaration
After lambda declaration
Before passing the lambda to the thread
I'm a lambda!
థ్రెడ్ సృష్టించబడిన తర్వాత మరియు ప్రోగ్రామ్ యొక్క అమలు పద్ధతికి చేరుకున్నప్పుడు మాత్రమే లాంబ్డా వ్యక్తీకరణ చివరిలో అమలు చేయబడిందని మీరు చూడవచ్చు run()
. ఇది ప్రకటించబడినప్పుడు ఖచ్చితంగా కాదు. Runnable
లాంబ్డా వ్యక్తీకరణను ప్రకటించడం ద్వారా, మేము ఒక వస్తువును మాత్రమే సృష్టించాము మరియు దాని run()
పద్ధతి ఎలా ప్రవర్తిస్తుందో వివరించాము. పద్ధతి చాలా తరువాత అమలు చేయబడుతుంది.
పద్ధతి సూచనలు?
మెథడ్ రిఫరెన్స్లు లాంబ్డాస్తో నేరుగా సంబంధం కలిగి ఉండవు, కానీ ఈ వ్యాసంలో వాటి గురించి కొన్ని మాటలు చెప్పడం సమంజసమని నేను భావిస్తున్నాను. మన దగ్గర లాంబ్డా ఎక్స్ప్రెషన్ ఉందని అనుకుందాం, అది ప్రత్యేకంగా ఏమీ చేయదు, కానీ ఒక పద్ధతిని పిలుస్తుంది.
x -> System.out.println(x)
ఇది కొన్ని స్వీకరించింది x
మరియు కేవలం కాల్స్ System.out.println()
, పాస్ x
. ఈ సందర్భంలో, మేము దానిని కావలసిన పద్ధతికి సూచనతో భర్తీ చేయవచ్చు. ఇలా:
System.out::println
అది నిజం — చివరికి కుండలీకరణాలు లేవు! ఇక్కడ మరింత పూర్తి ఉదాహరణ:
List<String> strings = new LinkedList<>();
strings.add("Dota");
strings.add("GTA5");
strings.add("Halo");
strings.forEach(x -> System.out.println(x));
చివరి పంక్తిలో, మేము forEach()
పద్ధతిని ఉపయోగిస్తాము, ఇది ఇంటర్ఫేస్ను అమలు చేసే వస్తువును తీసుకుంటుంది Consumer
. మళ్ళీ, ఇది ఒక ఫంక్షనల్ ఇంటర్ఫేస్, కేవలం ఒక void accept(T t)
పద్ధతిని కలిగి ఉంటుంది. దీని ప్రకారం, మేము ఒక పరామితిని కలిగి ఉన్న లాంబ్డా వ్యక్తీకరణను వ్రాస్తాము (ఇది ఇంటర్ఫేస్లోనే టైప్ చేయబడినందున, మేము పారామితి రకాన్ని పేర్కొనము; మేము దానిని పిలుస్తాము అని మాత్రమే సూచిస్తాము ) x
. లాంబ్డా వ్యక్తీకరణ యొక్క శరీరంలో, మేము పద్ధతిని accept()
పిలిచినప్పుడు అమలు చేయబడే కోడ్ను వ్రాస్తాము. ఇక్కడ మనం వేరియబుల్లో ముగిసిన వాటిని ప్రదర్శిస్తాము x
. ఇదే forEach()
పద్ధతి సేకరణలోని అన్ని అంశాల ద్వారా పునరావృతమవుతుంది మరియు accept()
అమలుపై పద్ధతిని పిలుస్తుందిConsumer
ఇంటర్ఫేస్ (మా లాంబ్డా), సేకరణలోని ప్రతి అంశంలో ప్రయాణిస్తుంది. నేను చెప్పినట్లుగా, మేము అటువంటి లాంబ్డా వ్యక్తీకరణను (వేరే పద్ధతిని వర్గీకరించేది) కావలసిన పద్ధతికి సూచనతో భర్తీ చేయవచ్చు. అప్పుడు మా కోడ్ ఇలా కనిపిస్తుంది:
List<String> strings = new LinkedList<>();
strings.add("Dota");
strings.add("GTA5");
strings.add("Halo");
strings.forEach(System.out::println);
ప్రధాన విషయం ఏమిటంటే println()
మరియు accept()
పద్ధతుల యొక్క పారామితులు సరిపోలడం. లాంబ్డా ఎక్స్ప్రెషన్లకు బదులుగా ఈ println()
పద్ధతి ఏదైనా (ఇది అన్ని ఆదిమ రకాలు మరియు అన్ని వస్తువులకు ఓవర్లోడ్ చేయబడింది) అంగీకరించవచ్చు కాబట్టి, మేము పద్ధతికి సూచనను println()
పంపవచ్చు forEach()
. అప్పుడు forEach()
సేకరణలోని ప్రతి మూలకాన్ని తీసుకొని నేరుగా పద్ధతికి పంపుతుంది println()
. దీన్ని మొదటిసారిగా ఎదుర్కొన్న ఎవరికైనా, మేము కాల్ చేయడం లేదని దయచేసి గమనించండి System.out.println()
(పదాల మధ్య చుక్కలతో మరియు చివర కుండలీకరణాలతో). బదులుగా, మేము ఈ పద్ధతికి సూచనను పంపుతున్నాము. మనం ఇలా వ్రాస్తే
strings.forEach(System.out.println());
మాకు సంకలన లోపం ఉంటుంది. కు కాల్ చేయడానికి ముందు forEach()
, జావా అది System.out.println()
కాల్ చేయబడిందని చూస్తుంది, కాబట్టి అది రిటర్న్ విలువ అని అర్థం చేసుకుంటుంది మరియు ఆబ్జెక్ట్ను ఆశించే దానికి బదులుగా పాస్ void
చేయడానికి ప్రయత్నిస్తుంది . void
forEach()
Consumer
పద్ధతి సూచనల కోసం సింటాక్స్
ఇది చాలా సులభం:-
మేము ఇలాంటి స్టాటిక్ పద్ధతికి సూచనను పంపుతాము:
ClassName::staticMethodName
public class Main { public static void main(String[] args) { List<String> strings = new LinkedList<>(); strings.add("Dota"); strings.add("GTA5"); strings.add("Halo"); strings.forEach(Main::staticMethod); } private static void staticMethod(String s) { // Do something } }
-
మేము ఇప్పటికే ఉన్న ఆబ్జెక్ట్ని ఉపయోగించి నాన్-స్టాటిక్ పద్ధతికి సూచనను పంపుతాము, ఇలా:
objectName::instanceMethodName
public class Main { public static void main(String[] args) { List<String> strings = new LinkedList<>(); strings.add("Dota"); strings.add("GTA5"); strings.add("Halo"); Main instance = new Main(); strings.forEach(instance::nonStaticMethod); } private void nonStaticMethod(String s) { // Do something } }
-
మేము ఈ క్రింది విధంగా అమలు చేసే తరగతిని ఉపయోగించి నాన్-స్టాటిక్ పద్ధతికి సూచనను పంపుతాము:
ClassName::methodName
public class Main { public static void main(String[] args) { List<User> users = new LinkedList<>(); users.add (new User("John")); users.add(new User("Paul")); users.add(new User("George")); users.forEach(User::print); } private static class User { private String name; private User(String name) { this.name = name; } private void print() { System.out.println(name); } } }
-
మేము ఇలాంటి కన్స్ట్రక్టర్కు సూచనను పంపుతాము:
ClassName::new
మీరు ఇప్పటికే ఒక కాల్బ్యాక్గా పని చేసే పద్ధతిని కలిగి ఉన్నప్పుడు పద్ధతి సూచనలు చాలా సౌకర్యవంతంగా ఉంటాయి. ఈ సందర్భంలో, పద్ధతి యొక్క కోడ్ను కలిగి ఉన్న లాంబ్డా వ్యక్తీకరణను వ్రాయడానికి లేదా పద్ధతిని పిలిచే లాంబ్డా వ్యక్తీకరణను వ్రాయడానికి బదులుగా, మేము దానికి సూచనను పంపుతాము. అంతే.
అనామక తరగతులు మరియు లాంబ్డా వ్యక్తీకరణల మధ్య ఆసక్తికరమైన వ్యత్యాసం
అనామక తరగతిలో,this
కీవర్డ్ అనామక తరగతి యొక్క వస్తువును సూచిస్తుంది. కానీ మనం దీనిని లాంబ్డా లోపల ఉపయోగిస్తే, మేము కలిగి ఉన్న తరగతి యొక్క వస్తువుకు ప్రాప్యతను పొందుతాము. మేము నిజానికి లాంబ్డా వ్యక్తీకరణను వ్రాసినది. లాంబ్డా వ్యక్తీకరణలు అవి వ్రాసిన తరగతి యొక్క ప్రైవేట్ పద్ధతిలో సంకలనం చేయబడినందున ఇది జరుగుతుంది. నేను ఈ "లక్షణాన్ని" ఉపయోగించమని సిఫార్సు చేయను, ఎందుకంటే ఇది ఒక దుష్ప్రభావం కలిగి ఉంటుంది మరియు ఇది ఫంక్షనల్ ప్రోగ్రామింగ్ సూత్రాలకు విరుద్ధంగా ఉంటుంది. ఈ విధానం OOPకి పూర్తిగా అనుగుణంగా ఉంటుందని పేర్కొంది. ;)
నేను నా సమాచారాన్ని ఎక్కడ పొందాను మరియు మీరు ఇంకా ఏమి చదవాలి?
- ఒరాకిల్ యొక్క అధికారిక వెబ్సైట్లో ట్యుటోరియల్. ఉదాహరణలతో సహా చాలా వివరణాత్మక సమాచారం.
- అదే ఒరాకిల్ ట్యుటోరియల్లో మెథడ్ రిఫరెన్స్ల గురించిన అధ్యాయం .
- మీకు నిజంగా ఆసక్తి ఉంటే వికీపీడియాలోకి ప్రవేశించండి .
GO TO FULL VERSION