“Effective Java (3rd Edition)” నుండి Best Practices
Joshua Bloch రాసిన “Effective Java (3rd Edition) ” నుండి కొన్ని భాగాలు
1. null కాదు, ఖాళీ collection లేదా arrayను return చేయండి
Method ఒక Setను return చేస్తే, ఖాళీ ఫలితానికి return null; వద్దు – దానికి బదులు return Set.of();.
2. Constructorలకు బదులు static factory methodలను పరిశీలించండి
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
ఎప్పుడూ మెరుగైనవి కాకపోవచ్చు, కానీ కొన్ని సందర్భాల్లో ఇవి చాలా ప్రయోజనాలు ఇస్తాయి:
- Static factory methodల ఒక ప్రయోజనం: constructorలలా కాకుండా, వీటికి పేర్లు ఉంటాయి.
- పిలిచిన ప్రతిసారీ ఇవి కొత్త objectను సృష్టించాల్సిన అవసరం లేదు.
- ఇవి తమ return type యొక్క ఏ subtype objectనైనా return చేయగలవు.
- Input parameterలను బట్టి, return చేసే object class ఒక్కో callకు మారవచ్చు.
- Methodను కలిగి ఉన్న class రాసే సమయానికి, return చేసే object class ఉనికిలో ఉండాల్సిన అవసరం కూడా లేదు.
లోపాలు:
- కేవలం static factory methodలను మాత్రమే అందించడంలో ప్రధాన పరిమితి: public లేదా protected constructorలు లేని classలను subclass చేయలేం.
- Static factory methodల రెండో లోపం: programmerలకు వీటిని కనుగొనడం కష్టం.
3. Constructor parameterలు ఎక్కువగా ఉన్నప్పుడు builderను పరిశీలించండి
Static factoryలు, constructorలు రెండింటికీ ఒక పరిమితి ఉంది: ఎక్కువ సంఖ్యలో optional parameterలు ఉన్నప్పుడు అవి సరిగ్గా ఇమడవు. నేను పనిచేసిన కొన్ని ప్రాజెక్ట్లను ఇది చాలా తీవ్రంగా దెబ్బతీసింది.
4. Private constructor లేదా enum type ద్వారా singleton లక్షణాన్ని నిర్ధారించండి
అనేక instanceలు అవసరం లేనిది ఏదైనా ఒక్కసారి మాత్రమే instantiate చేయాలి – @ApplicationScopedతో అయినా, మరో singleton patternతో అయినా.
5. Private constructor ద్వారా instantiationను నిరోధించండి
కొన్నిసార్లు మీరు కేవలం static methodలు, static fieldల సమూహం అయిన ఒక classను రాయాలనుకుంటారు. Objectల పరంగా ఆలోచించడాన్ని తప్పించుకోవడానికి కొందరు వీటిని దుర్వినియోగం చేయడం వల్ల ఇలాంటి classలకు చెడ్డపేరు వచ్చింది, కానీ వీటికి సరైన ఉపయోగాలు కూడా ఉన్నాయి.
private MyStaticClass() {
// private constructor to prevent instantiation
}
6. అనవసరమైన objectలను సృష్టించడం మానుకోండి
String s = new String("bikini"); // DON'T DO THIS!
లేదా:
// Hideously slow! Can you spot the object creation?
private static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}
పరిష్కారం: ఈ program సరైన సమాధానం ఇస్తుంది, కానీ ఒకే ఒక్క అక్షర దోషం వల్ల ఉండాల్సిన దానికంటే చాలా నెమ్మదిగా నడుస్తుంది. sum అనే variableను long బదులు Longగా ప్రకటించారు; దీనివల్ల program సుమారు 2^31 అనవసరమైన Long instanceలను సృష్టిస్తుంది (దాదాపు long iను Long sumకు కలిపిన ప్రతిసారీ ఒకటి).
7. Finalizerలు, cleanerలను నివారించండి
Finalizerలు ఊహించలేనివి, చాలాసార్లు ప్రమాదకరమైనవి, సాధారణంగా అనవసరమైనవి. వాటిని వాడటం వల్ల అస్థిర ప్రవర్తన, బలహీనమైన performance, portability సమస్యలు రావచ్చు.
8. try-finally కంటే try-with-resourcesకే ప్రాధాన్యం ఇవ్వండి
// try-with-resources - the best way to close resources!
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
9. Comparableను implement చేయడాన్ని పరిశీలించండి
Comparableను implement చేయడం ద్వారా, ఈ interfaceపై ఆధారపడే అనేక generic algorithmలు, collection implementationలతో మీ class కలిసి పనిచేయగలుగుతుంది.
10. Classలు, memberల యాక్సెసిబిలిటీని వీలైనంత తగ్గించండి
బాగా డిజైన్ చేసిన componentను పేలవంగా డిజైన్ చేసినదాని నుండి వేరుచేసే అతి ముఖ్యమైన అంశం, ఆ component తన అంతర్గత dataను, ఇతర implementation వివరాలను ఇతర componentల నుండి ఎంతవరకు దాచిపెడుతుంది అనేదే. బాగా డిజైన్ చేసిన component తన implementation వివరాలన్నింటినీ దాచిపెట్టి, తన APIని implementation నుండి స్పష్టంగా వేరుచేస్తుంది. అప్పుడు componentలు తమ APIల ద్వారా మాత్రమే సంభాషిస్తాయి; ఒకదాని అంతర్గత పనితీరు గురించి మరొకదానికి ఏమీ తెలియదు. Information hiding లేదా encapsulation అని పిలిచే ఈ భావన సాఫ్ట్వేర్ డిజైన్కు ఒక మౌలిక సూత్రం.
11. Public classలలో public fieldలు కాదు, accessor methodలు వాడండి
కొన్నిసార్లు, instance fieldలను ఒకచోట చేర్చడం తప్ప మరే ప్రయోజనమూ లేని, దిగజారిన (degenerate) classలను రాయాలనే ప్రలోభం కలగవచ్చు:
// Degenerate classes like this should not be public!
class Point {
public double x;
public double y;
}
ఇలాంటి classల data fieldలను నేరుగా యాక్సెస్ చేస్తారు కాబట్టి, ఇవి encapsulation ప్రయోజనాలను ఇవ్వవు. APIని మార్చకుండా representationను మార్చలేరు, invariantలను అమలుచేయలేరు, ఒక field యాక్సెస్ అయినప్పుడు అదనపు చర్య తీసుకోలేరు. కఠిన వైఖరి గల object-oriented programmerలు ఇలాంటి classలు పూర్తిగా నిషిద్ధమని, వాటిని ఎప్పుడూ private fieldలు, public accessor methodలు (getterలు), mutable classలకైతే mutatorలు (setterలు) ఉన్న classలతో భర్తీ చేయాలని భావిస్తారు:
// Encapsulation of data by accessor methods and mutators
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
public void setX(double x) { this.x = x; }
public void setY(double y) { this.y = y; }
}
Public classల విషయంలో కఠిన వైఖరి గలవారు చెప్పేది నిస్సందేహంగా సరైనదే: ఒక class దాని package బయటి నుండి యాక్సెస్ చేయగలిగితే, class అంతర్గత representationను మార్చే వెసులుబాటును కాపాడుకోవడానికి accessor methodలను అందించండి. ఒక public class తన data fieldలను బహిర్గతం చేస్తే, client code ఎక్కడెక్కడికో వ్యాపించి ఉండవచ్చు కాబట్టి, దాని representationను మార్చే ఆశలన్నీ ఆవిరైపోతాయి.
అయితే, ఒక class package-private అయినా లేదా private nested class అయినా, దాని data fieldలను బహిర్గతం చేయడంలో మౌలికంగా తప్పేమీ లేదు – ఆ fieldలు class అందించే abstractionను తగినంతగా వివరిస్తున్నంత వరకు.
12. Mutabilityని వీలైనంత తగ్గించండి
Immutable class అంటే, దాని instanceలను మార్చలేని class. ప్రతి instanceలో ఉన్న సమాచారమంతా object జీవితకాలం మొత్తం స్థిరంగా ఉంటుంది; కాబట్టి ఏ మార్పూ ఎప్పటికీ కనిపించదు. Java platform libraryలలో చాలా immutable classలు ఉన్నాయి: String, boxed primitive classలు, BigInteger, BigDecimal వంటివి. దీనికి చాలా మంచి కారణాలు ఉన్నాయి: immutable classలను mutable classల కంటే డిజైన్ చేయడం, implement చేయడం, వాడటం సులభం. వాటిలో పొరపాట్లకు అవకాశం తక్కువ, అవి మరింత సురక్షితమైనవి. ఒక classను immutable చేయడానికి ఈ ఐదు నియమాలు పాటించండి:
- Object stateను మార్చే methodలను అందించకండి (వీటిని mutatorలు అంటారు).
-
Classను extend చేయలేకుండా చూసుకోండి. Object state మారినట్టు ప్రవర్తిస్తూ, అజాగ్రత్తగా లేదా దురుద్దేశంతో రాసిన subclassలు class immutable ప్రవర్తనను
దెబ్బతీయకుండా ఇది నిరోధిస్తుంది. Subclassing నిరోధించడం సాధారణంగా, ఉదాహరణకు, classను
finalచేయడం ద్వారా జరుగుతుంది. - అన్ని fieldలను final చేయండి. System స్వయంగా అమలుచేసే విధంగా ఇది మీ ఉద్దేశాన్ని స్పష్టంగా వ్యక్తపరుస్తుంది. అంతేకాక, memory modelలో వివరించినట్లు, కొత్తగా సృష్టించిన instance reference ఒక thread నుండి మరో threadకు synchronization లేకుండా పంపబడితే సరైన ప్రవర్తనను నిర్ధారించడానికి కూడా ఇది అవసరం.
- అన్ని fieldలను private చేయండి. Fieldలు సూచించే mutable objectలను clientలు యాక్సెస్ చేసి నేరుగా మార్చకుండా ఇది నిరోధిస్తుంది. Primitive విలువలు లేదా immutable objectల referenceలు ఉన్న public final fieldలను immutable classలు కలిగి ఉండటం సాంకేతికంగా అనుమతించబడినా, అది సిఫార్సు చేయబడదు; ఎందుకంటే తర్వాతి releaseలో అంతర్గత representationను మార్చడానికి అది అడ్డుపడుతుంది.
-
ఏ mutable componentకైనా ప్రత్యేక యాక్సెస్ను నిర్ధారించండి. మీ classలో mutable objectలను సూచించే fieldలు ఉంటే, class clientలు ఆ objectల referenceలను
పొందలేకుండా చూసుకోండి. అలాంటి fieldను client ఇచ్చిన object referenceతో ఎప్పుడూ initialize చేయకండి, accessor నుండి ఆ fieldను return చేయకండి. Constructorలు, accessorలు,
readObjectmethodలలో defensive copyలను సృష్టించండి.
13. Inheritance కంటే compositionకే ప్రాధాన్యం ఇవ్వండి
కోడ్ పునర్వినియోగానికి inheritance ఒక శక్తివంతమైన మార్గం, కానీ అది ఎప్పుడూ ఆ పనికి ఉత్తమ సాధనం కాదు. సరిగ్గా వాడకపోతే, అది పెళుసైన సాఫ్ట్వేర్ను సృష్టిస్తుంది. Subclass, superclass implementationలు ఒకే programmerల నియంత్రణలో ఉండే ఒక package లోపల inheritance వాడటం సురక్షితం. Extend చేయడం కోసమే ప్రత్యేకంగా డిజైన్ చేసి డాక్యుమెంట్ చేసిన classలను extend చేసేటప్పుడు కూడా inheritance సురక్షితమే. కానీ package సరిహద్దులు దాటి సాధారణ concrete classల నుండి inherit చేయడం ప్రమాదకరం.
Method callకు భిన్నంగా, inheritance encapsulationను ఉల్లంఘిస్తుంది. కొత్త methodలను మాత్రమే జోడించి, ఉన్న methodలను override చేయకుండా ఉంటే, ఒక classను extend చేయడం సురక్షితమని మీరు అనుకోవచ్చు. ఇలాంటి extension చాలా సురక్షితమైనదే అయినా, ప్రమాదరహితం కాదు. తర్వాతి releaseలో superclassకు ఒక కొత్త method వచ్చి, దురదృష్టవశాత్తూ మీరు subclassలో అదే signature, వేరే return type ఉన్న methodను పెట్టి ఉంటే, మీ subclass ఇక compile అవ్వదు. కొత్త superclass method ఉన్న అదే signature, return type గల methodను subclassలో పెట్టి ఉంటే, ఇప్పుడు మీరు దాన్ని override చేస్తున్నారు; కాబట్టి ఇంతకుముందు వివరించిన సమస్యలకు గురవుతారు. పైగా, మీ method కొత్త superclass method contractను నెరవేరుస్తుందా అనేది సందేహమే; ఎందుకంటే మీరు subclass method రాసినప్పుడు ఆ contract ఇంకా రాయబడలేదు.
అదృష్టవశాత్తూ, పైన వివరించిన సమస్యలన్నింటినీ నివారించడానికి ఒక మార్గం ఉంది. ఉన్న classను extend చేసే బదులు, మీ కొత్త classకు ఆ class instanceను సూచించే ఒక private fieldను ఇవ్వండి. ఉన్న class కొత్త classలో ఒక component అవుతుంది కాబట్టి, ఈ డిజైన్ను composition అంటారు. కొత్త classలోని ప్రతి instance method, లోపల ఉన్న పాత class instanceపై సంబంధిత methodను పిలిచి, ఫలితాలను return చేస్తుంది. దీన్ని forwarding అంటారు; కొత్త classలోని methodలను forwarding methodలు అంటారు. ఫలితంగా వచ్చే class రాతిలా దృఢంగా ఉంటుంది; పాత class implementation వివరాలపై దానికి ఎలాంటి ఆధారమూ ఉండదు. పాత classకు కొత్త methodలు జోడించినా కూడా కొత్త classపై ఏ ప్రభావమూ ఉండదు.
14. Abstract classల కంటే interfaceలకే ప్రాధాన్యం ఇవ్వండి
అనేక implementationలను అనుమతించే typeను నిర్వచించడానికి Javaలో రెండు యంత్రాంగాలు ఉన్నాయి: interfaceలు, abstract classలు. Java 8లో interfaceలకు default methodలు వచ్చినప్పటి నుండి, రెండు యంత్రాంగాలలోనూ కొన్ని instance methodలకు implementation అందించవచ్చు.
ఒక ప్రధాన తేడా: abstract class నిర్వచించిన typeను implement చేయడానికి, ఒక class ఆ abstract classకు subclass అయి ఉండాలి. Java single inheritanceను మాత్రమే అనుమతిస్తుంది కాబట్టి, abstract classలపై ఉన్న ఈ పరిమితి type నిర్వచనాలుగా వాటి వాడకాన్ని తీవ్రంగా కట్టడి చేస్తుంది. అవసరమైన అన్ని methodలను నిర్వచించి general contractను పాటించే ఏ classఅయినా, class hierarchyలో ఎక్కడ ఉన్నా, ఒక interfaceను implement చేయవచ్చు. ఇప్పటికే ఉన్న classలకు ఒక కొత్త interfaceను సులభంగా అమర్చి implement చేయించవచ్చు.
- Mixinలను నిర్వచించడానికి interfaceలు ఆదర్శవంతమైనవి.
- Interfaceలు శ్రేణీరహిత (nonhierarchical) type frameworkల నిర్మాణానికి వీలు కల్పిస్తాయి.
- Interfaceలు సురక్షితమైన, శక్తివంతమైన functionality మెరుగుదలలను సాధ్యం చేస్తాయి – wrapper class idiom ద్వారా. Typeలను నిర్వచించడానికి abstract classలు వాడితే, functionality జోడించాలనుకునే programmerకు inheritance తప్ప మరో దారి ఉండదు.
15. Generics: raw typeలను వాడకండి
పొరపాటు జరిగిన చాలా కాలం తర్వాత, runtimeలోనే దాన్ని కనుగొంటారు – అది కూడా పొరపాటు ఉన్న కోడ్కు చాలా దూరంగా ఉండే కోడ్లో. ClassCastException చూసిన తర్వాత, stampల సేకరణలో నాణేన్ని వేసిన ఆ method call కోసం codebase మొత్తం వెతకాల్సి వస్తుంది. Compiler మీకు సహాయం చేయలేదు.
16. Generics: unchecked warningలను తొలగించండి
Genericsతో program రాసేటప్పుడు, మీకు చాలా compiler warningలు కనిపిస్తాయి:
- unchecked cast warningలు
- unchecked method invocation warningలు
- unchecked parameterized vararg type warningలు
- unchecked conversion warningలు.
Genericsతో మీ అనుభవం పెరిగేకొద్దీ warningలు తగ్గుతాయి, కానీ కొత్తగా రాసిన కోడ్ శుభ్రంగా compile అవుతుందని ఆశించకండి. చాలా unchecked warningలను సులభంగా తొలగించవచ్చు. ఉదాహరణకు, మీరు పొరపాటున ఈ declaration రాశారనుకోండి:
Set<Lark> exaltation = new HashSet();
దీన్ని ఇలా మార్చండి:
Set<Lark> exaltation = new HashSet<>();
కొన్ని warningలను తొలగించడం చాలా కష్టం. కొంచెం ఆలోచించాల్సిన warningలు వచ్చినప్పుడు, పట్టు వదలకండి! మీరు తొలగించగలిగిన ప్రతి unchecked warningనూ తొలగించండి.
అన్ని warningలను తొలగిస్తే, మీ కోడ్ typesafe అని నిశ్చింతగా ఉండవచ్చు – ఇది చాలా మంచి విషయం. Runtimeలో ClassCastException రాదని దీని అర్థం; మీ program మీరు అనుకున్నట్టే
ప్రవర్తిస్తుందనే నమ్మకాన్నీ ఇది పెంచుతుంది. ఒక warningను తొలగించలేకపోయినా, దాన్ని కలిగించిన కోడ్ typesafe అని నిరూపించగలిగితే, అప్పుడు (అప్పుడు మాత్రమే)
@SuppressWarnings("unchecked") annotationతో ఆ warningను అణచివేయండి. కోడ్ typesafe అని ముందుగా నిరూపించకుండా warningలను అణచివేస్తే, మీకు మీరే
ఒక తప్పుడు భద్రతా భావాన్ని ఇచ్చుకుంటున్నారు.
కోడ్ ఏ warning లేకుండా compile కావచ్చు, అయినా runtimeలో ClassCastExceptionను throw చేయవచ్చు.
ప్రతిసారీ @SuppressWarnings("unchecked") annotation వాడినప్పుడు, అది ఎందుకు సురక్షితమో చెప్పే ఒక commentను జోడించండి.
17. Generics: ఎప్పుడు అర్థవంతం
అయ్యో – genericsతో అత్యవసరంగా పని ఉన్న ఒక class:
ఇలాంటిది ఆలస్యంగానైనా, merge requestలోనే పట్టుకోవాలి!
18. Generics: ఇలా చేయకూడదు
క్షమించండి, ఇంకేమీ చెప్పనక్కర్లేదు. దయచేసి దీన్ని ఎప్పుడూ merge చేయకండి:
public abstract class JpaLearningCardBaseContentService<LC extends LearningCardBaseContent<L, LC, AC>, J extends JpaLearningCardBaseContent<L, LC, AC>, L extends
LearningCardBase<LC, A>, A extends AnswerOptionBase<L, AC>, AC extends AnswerOptionBaseContent<LC, AC, A>, AS extends AnswerOptionBaseService<A, AC, L, LC>, ACS extends
AnswerOptionBaseContentService<AC, A, L, LC>, LS extends LearningCardBaseService<L>>
extends JpaLightPersistenceService<LC, J, Long> implements LearningCardBaseContentService<LC, L, A, AC> {
// ...
}
కేవలం ఒక class declarationను అర్థం చేసుకోవడానికి ఎప్పుడూ 5 నిమిషాలు పట్టకూడదు.
19. Arrayల కంటే listలకే ప్రాధాన్యం ఇవ్వండి
Arrayలు రెండు ముఖ్యమైన విధాలుగా generic typeల నుండి భిన్నంగా ఉంటాయి. మొదటిది, arrayలు covariant. భయపెట్టేలా వినిపించే ఈ పదం అర్థం సరళమైనది: Sub అనేది Superకు subtype అయితే,
array type Sub[] కూడా array type Super[]కు subtype. దీనికి భిన్నంగా generics invariant: ఏ రెండు వేర్వేరు typeలు Type1, Type2కైనా,
List<Type1> అనేది List<Type2>కు subtype కాదు, supertype కూడా కాదు.
20. Anonymous classల కంటే lambdaలకే ప్రాధాన్యం ఇవ్వండి
// Anonymous class instance as a function object - obsolete!
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
దానికి బదులు ఇలా చేయండి:
// Lambda expression as function object (replaces anonymous class)
Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
21. Local variableల scopeను వీలైనంత తగ్గించండి
ఒక local variable scopeను తగ్గించడానికి అత్యంత శక్తివంతమైన పద్ధతి, అది మొదట ఉపయోగించే చోటే దాన్ని ప్రకటించడం...
22. సంప్రదాయ for loopల కంటే for-each loopలకే ప్రాధాన్యం ఇవ్వండి
// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
... // Do something with e
}
23. Libraryలను తెలుసుకోండి, వాడండి
సున్నా నుండి ఒక ఎగువ పరిమితి మధ్య random integerలను సృష్టించాలనుకుంటున్నారనుకోండి. ఈ సాధారణ పనిని ఎదుర్కొన్న చాలా మంది programmerలు దాదాపు ఇలాంటి ఒక చిన్న methodను రాస్తారు:
// Common but deeply flawed!
static Random rnd = new Random();
static int random(int n) {
return Math.abs(rnd.nextInt()) % n;
}
ఈ method బాగానే కనిపించవచ్చు, కానీ దీనిలో మూడు లోపాలు ఉన్నాయి. మొదటిది: n రెండు యొక్క చిన్న ఘాతం (power of two) అయితే, random సంఖ్యల క్రమం చాలా తక్కువ వ్యవధిలోనే పునరావృతమవుతుంది. రెండో లోపం: n రెండు యొక్క ఘాతం కాకపోతే, సగటున కొన్ని సంఖ్యలు ఇతరుల కంటే ఎక్కువసార్లు return అవుతాయి. n పెద్దదైతే, ఈ ప్రభావం చాలా స్పష్టంగా కనిపించవచ్చు.
random method మూడో లోపం: అరుదైన సందర్భాల్లో అది ఘోరంగా విఫలమై, నిర్దేశించిన పరిధి బయటి సంఖ్యను return చేయవచ్చు. ఎందుకంటే, method
rnd.nextInt() return చేసిన విలువను Math.absను పిలిచి రుణాత్మకం కాని intగా మార్చడానికి ప్రయత్నిస్తుంది. nextInt()
Integer.MIN_VALUEను return చేస్తే, Math.abs కూడా Integer.MIN_VALUEనే return చేస్తుంది; n రెండు యొక్క ఘాతం కాదనుకుంటే, శేష operator
(%) ఒక రుణాత్మక సంఖ్యను return చేస్తుంది. ఇది దాదాపు ఖచ్చితంగా మీ programను విఫలం చేస్తుంది; ఆ వైఫల్యాన్ని మళ్లీ సృష్టించడం కూడా కష్టం కావచ్చు.
24. కచ్చితమైన సమాధానాలు కావాలంటే float, doubleలను నివారించండి
డబ్బు మొత్తాల కోసం BigDecimal వాడండి. float, double rounding లోపాలను కలిగిస్తాయి.
ఉదాహరణకు, మీ జేబులో $1.03 ఉంది, మీరు 42¢ ఖర్చు చేశారనుకోండి. మీ దగ్గర ఎంత డబ్బు మిగిలింది? ఈ ప్రశ్నకు సమాధానం ఇవ్వడానికి ప్రయత్నించే ఒక అమాయకమైన program భాగం ఇదిగో:
System.out.println(1.03 - 0.42);
దురదృష్టవశాత్తూ, ఇది 0.6100000000000001ను print చేస్తుంది. ఇది ఒంటరి సంఘటన కాదు. మీ జేబులో ఒక డాలర్ ఉంది, ఒక్కోటి పది సెంట్ల ధర గల తొమ్మిది washerలను కొన్నారనుకోండి.
మీకు ఎంత చిల్లర తిరిగి వస్తుంది?
System.out.println(1.00 - 9 * 0.10);
ఈ program భాగం ప్రకారం, మీకు వచ్చేది $0.09999999999999998.
Print చేసే ముందు ఫలితాలను round చేస్తే సమస్య పరిష్కారమవుతుందని మీరు అనుకోవచ్చు; కానీ దురదృష్టవశాత్తూ, అది ఎప్పుడూ పనిచేయదు. ఉదాహరణకు, మీ జేబులో ఒక డాలర్ ఉంది; ఒక అరలో 10¢, 20¢, 30¢ ఇలా ఒక డాలర్ వరకు ధర గల రుచికరమైన మిఠాయిలు వరుసగా ఉన్నాయి. 10¢ మిఠాయితో మొదలుపెట్టి, అరలోని తర్వాతి మిఠాయిని కొనలేనంత వరకు, ఒక్కో రకం నుండి ఒక్కొక్కటి కొంటారు.
25. Boxed primitiveల కంటే primitive typeలకే ప్రాధాన్యం ఇవ్వండి
// Broken comparator - can you spot the flaw?
Comparator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);
26. Objectలను వాటి interfaceల ద్వారా సూచించండి
మంచి ఉదాహరణ:
Set<Son> sonSet = new LinkedHashSet<>();
చెడ్డ ఉదాహరణ:
LinkedHashSet<Son> sonSet = new LinkedHashSet<>();
27. Reflection కంటే interfaceలకే ప్రాధాన్యం ఇవ్వండి
లేకపోతే:
- Compile-time type checking ప్రయోజనాలన్నింటినీ కోల్పోతారు, exception checkingతో సహా. ఉనికిలో లేని లేదా యాక్సెస్ చేయలేని methodను ఒక program reflection ద్వారా పిలవడానికి ప్రయత్నిస్తే, మీరు ప్రత్యేక జాగ్రత్తలు తీసుకోకపోతే అది runtimeలో విఫలమవుతుంది.
- Reflection ద్వారా యాక్సెస్ చేయడానికి అవసరమైన కోడ్ గజిబిజిగా, పొడవుగా ఉంటుంది. రాయడం విసుగు, చదవడం కష్టం.
- Performance దెబ్బతింటుంది. Reflection ద్వారా method call సాధారణ method call కంటే చాలా నెమ్మదిగా ఉంటుంది.
28. సాధారణంగా ఆమోదించిన naming conventionలను పాటించండి
Java platformకు బాగా స్థిరపడిన naming conventionల సమితి ఉంది; వాటిలో చాలావరకు The Java Language Specification [JLS, 6.1]లో ఉన్నాయి.
29. Exceptionలను అసాధారణ పరిస్థితులకు మాత్రమే వాడండి
// Horrible abuse of exceptions. Don't ever do this!
try {
int i = 0;
while (true) {
range[i++].climb();
}
} catch (ArrayIndexOutOfBoundsException e) {
// catch it
}
ఈ కోడ్ ఏమి చేస్తుంది? చూడగానే అస్సలు స్పష్టంగా తెలియదు; దాన్ని వాడకుండా ఉండటానికి అదే తగిన కారణం. నిజానికి ఇది ఒక array అంశాలపై loop చేయడానికి, అత్యంత పేలవంగా ఆలోచించిన
idiom. Array హద్దుల బయట ఉన్న మొదటి అంశాన్ని యాక్సెస్ చేయడానికి ప్రయత్నించినప్పుడు ఒక ArrayIndexOutOfBoundsExceptionను throw చేసి, పట్టుకుని, పట్టించుకోకుండా వదిలేయడం ద్వారా
ఈ అంతులేని loop ముగుస్తుంది. Array మీద loop చేయడానికి ఉన్న standard idiomకు ఇది సమానంగా ఉండాలి; ఆ idiomను ఏ Java programmerఅయినా వెంటనే గుర్తుపడతారు:
for (Mountain m : range) {
m.climb();
}
పేరే సూచిస్తున్నట్టు, exceptionలు అసాధారణ పరిస్థితులకు మాత్రమే; సాధారణ control flow కోసం వాటిని ఎప్పుడూ వాడకూడదు.
30. కోలుకోగల పరిస్థితులకు checked exceptionలను, programming లోపాలకు runtime exceptionలను వాడండి
Caller సహేతుకంగా కోలుకోగలడని ఆశించగల పరిస్థితులకు checked exceptionలను వాడండి. Userను ఒక checked exceptionతో ఎదుర్కొనేలా చేయడం ద్వారా, API డిజైనర్ ఆ పరిస్థితి నుండి కోలుకోవాలనే ఆదేశాన్ని ఇస్తారు. Exceptionను పట్టుకుని పట్టించుకోకుండా వదిలేయడం ద్వారా user ఆ ఆదేశాన్ని ఉపేక్షించవచ్చు, కానీ అది సాధారణంగా చెడ్డ ఆలోచన.
Programming లోపాలను సూచించడానికి runtime exceptionలను వాడండి. చాలావరకు runtime exceptionలు precondition ఉల్లంఘనలను సూచిస్తాయి. Precondition ఉల్లంఘన అంటే, API
specification నిర్దేశించిన contractను ఒక API client పాటించకపోవడమే. ఉదాహరణకు, array యాక్సెస్ contract ప్రకారం array index సున్నా నుండి array పొడవు మైనస్ ఒకటి వరకు (రెండూ కలిపి)
ఉండాలి. ఈ precondition ఉల్లంఘించబడిందని ArrayIndexOutOfBoundsException సూచిస్తుంది.
31. Checked exceptionలను అనవసరంగా వాడటం మానుకోండి
సంక్షిప్తంగా, పొదుపుగా వాడితే checked exceptionలు programల విశ్వసనీయతను పెంచగలవు; అతిగా వాడితే, APIలను వాడటం బాధాకరంగా మారుతుంది.
Pair<Boolean, LearningCardGroup> answerLearningCard(@NotNull LearningCardGroup learningCardGroup,
LearningCardAssignment learningCardAssignment,
@NotNull Collection<AnswerOption> answers)
throws InvalidTrainingStateException, PersistenceException, LearningCardGroupAlreadyCompletedException,
ConsecutiveCorrectCountExceededException,
PreviousLearningCardGroupUncompletedException, LearningCardGroupCooldownException,
LearningCardGroupHasUncompletedLearningCardsException, InvalidParticipantException, TrainingNotSignedException; // but why ???
// this is a mistake seen a lot with junior devs
// exceptions are exceptionally slow and should be avoided for mere validation
// the performance gets even worse if a stacktrace is printed, since logging and printing is one of the slowest possible actions
32. Standard exceptionల వాడకానికే ప్రాధాన్యం ఇవ్వండి
నిపుణులైన programmerలను తక్కువ అనుభవం ఉన్నవారి నుండి వేరుచేసే ఒక లక్షణం: నిపుణులు అధిక స్థాయి కోడ్ పునర్వినియోగం కోసం ప్రయత్నిస్తారు, సాధారణంగా దాన్ని సాధిస్తారు.
కోడ్ పునర్వినియోగం మంచిదనే నియమానికి exceptionలు మినహాయింపు కాదు. చాలా APIల exception throw అవసరాల్లో చాలావరకు తీర్చే exceptionల సమితిని Java libraryలు అందిస్తాయి. Standard exceptionలను పునర్వినియోగించడంలో అనేక ప్రయోజనాలు ఉన్నాయి. వాటిలో ప్రధానమైనది: programmerలకు ఇప్పటికే పరిచయమైన, స్థిరపడిన సంప్రదాయాలకు సరిపోతుంది కాబట్టి, మీ APIని నేర్చుకోవడం, వాడటం సులభమవుతుంది. దాని తర్వాతి స్థానంలో: మీ APIని వాడే programలు అపరిచిత exceptionలతో నిండి ఉండవు కాబట్టి, వాటిని చదవడం సులభం. చివరగా (ప్రాముఖ్యతలోనూ చివరిది), తక్కువ exception classలు అంటే తక్కువ memory footprint, classలను load చేయడానికి తక్కువ సమయం.
అత్యధికంగా పునర్వినియోగించే exception type IllegalArgumentException. అనుచితమైన విలువ గల argumentను caller పంపినప్పుడు సాధారణంగా throw చేయాల్సిన exception ఇదే.
ఉదాహరణకు, ఒక చర్య ఎన్నిసార్లు పునరావృతం కావాలో సూచించే parameterలో caller రుణాత్మక సంఖ్యను పంపితే, throw చేయాల్సిన exception ఇదే. తరచూ పునర్వినియోగించే
మరో exception IllegalStateException. Call అందుకునే object state కారణంగా ఆ call చెల్లనిదైనప్పుడు సాధారణంగా throw చేయాల్సింది ఇదే.
ఉదాహరణకు, ఒక object సరిగ్గా initialize అవ్వకముందే caller దాన్ని వాడటానికి ప్రయత్నిస్తే, throw చేయాల్సిన exception ఇదే.
ప్రతి తప్పుడు method call చివరికి చెల్లని argument లేదా stateకే దారితీస్తుందని వాదించవచ్చు; కానీ కొన్ని నిర్దిష్ట రకాల చెల్లని argumentలు, stateలకు ఇతర exceptionలను
ప్రామాణికంగా వాడతారు. null విలువలు నిషిద్ధమైన parameterలో caller nullను పంపితే, సంప్రదాయం ప్రకారం IllegalArgumentExceptionకు బదులు NullPointerExceptionను throw చేయాలి.
అదే విధంగా, ఒక sequence indexను సూచించే parameterలో caller పరిధి దాటిన విలువను పంపితే, IllegalArgumentExceptionకు బదులు IndexOutOfBoundsExceptionను throw చేయాలి.
Exception, RuntimeException, Throwable, Errorలను నేరుగా పునర్వినియోగించకండి. ఈ classలను abstract అయినట్టే పరిగణించండి. అయినప్పటికీ, ఒక checked exceptionను runtime
exceptionగా మార్చాలనుకుంటే, మీరేం చేస్తున్నారో మీకు నిజంగా తెలిసి ఉంటే, RuntimeExceptionను వాడవచ్చు.
33. Exceptionలను నిర్లక్ష్యం చేయకండి
// Empty catch block ignores exception - Highly suspect!
try {
...
} catch (SomeException e) {
}
ఖాళీ catch block exceptionల ఉద్దేశాన్నే దెబ్బతీస్తుంది; అసాధారణ పరిస్థితులను నిర్వహించేలా మిమ్మల్ని బలవంతం చేయడమే ఆ ఉద్దేశం. ఒక exceptionను నిర్లక్ష్యం చేయడం ఫైర్ అలారంను నిర్లక్ష్యం చేయడం లాంటిది – అంతేకాదు, నిజంగా మంటలు చెలరేగాయో లేదో ఇంకెవరూ చూసే అవకాశం లేకుండా దాన్ని ఆపేయడం లాంటిది.