මග හැරීම! = ශූන්‍ය ප්‍රකාශ


4016

object != nullවළක්වා ගැනීමට මම බොහෝ දේ භාවිතා කරමි NullPointerException.

මේ සඳහා හොඳ විකල්පයක් තිබේද?

උදාහරණයක් ලෙස මම බොහෝ විට භාවිතා කරන්නේ:

if (someobject != null) {
    someobject.doCalc();
}

ඉහත ස්නිපටයේ NullPointerExceptionඇති someobjectවස්තුව සඳහා මෙය පරික්ෂා කරයි .

පිළිගත් පිළිතුර යල්පැන ඇති බව සලකන්න, වඩාත් මෑත ප්‍රවේශයක් සඳහා https://stackoverflow.com/a/2386013/12943 බලන්න .


120
Her ෂර්වින් ශුන්‍යය දිරිගැන්වීම මඟින් කේතය අඩු අවබෝධයක් සහ විශ්වාසනීයත්වයක් අඩු කරයි.
ටොම් හෝටින් -

44
එල්විස් ක්‍රියාකරුවන් යෝජනා කළ නමුත් එය ජාවා 7 හි නොමැති බව පෙනේ . ගොඩාක් නරකයි, ?. ?: සහ? [] ඇදහිය නොහැකි කාලය ඉතිරි කරන්නන් වේ.
ස්කොට්

72
මෙහි ඇති වෙනත් බොහෝ යෝජනා වලට වඩා ශුන්‍ය භාවිතා නොකිරීම. ව්‍යතිරේකයන් විසි කරන්න, ආපසු නොයන්න. BTW - පෙරනිමියෙන් අක්‍රිය කර ඇති නිසා 'තහවුරු කරන්න' යන පදය නිෂ් less ල ය. සෑම විටම සක්‍රීය අසාර්ථක යාන්ත්‍රණයක් භාවිතා කරන්න
ianpojman

13
මම දැන් ස්කලා භාවිතා කිරීමට මෙය එක් හේතුවකි. ස්කලා හි සෑම දෙයක්ම අහෝසි නොවේ. ඔබට "කිසිවක්" සමත් වීමට හෝ ආපසු යාමට ඉඩ දීමට අවශ්‍ය නම්, ඔබ හුදෙක් ටී අල්ස් තර්කය හෝ ආපසු වර්ගය වෙනුවට විකල්පය [ටී] භාවිතා කළ යුතුය.
තේක්වාස්ති

11
SthSoft ඇත්ත වශයෙන්ම, Optionපාලනය කිරීමට හෝ අවසර දීමට භාෂාවේ ඇති අකැමැත්ත නිසා ස්කලාගේ නියම වර්ගය විනාශ වී nullඇත. මම මෙය හැකර් නිවුස් හි සඳහන් කර පහත් කොට “ස්කලා හි කිසිවෙකු කෙසේ හෝ ශුන්‍ය ලෙස භාවිතා නොකරන” බව පැවසුවා. කුමක්දැයි අනුමාන කරන්න, මම දැනටමත් සහායකයන් විසින් ලියන ලද ස්කලා හි ශුන්‍යයන් සොයාගෙන ඇත. ඔව්, ඔවුන් "එය වැරදි කරන්නේ" වන අතර ඒ ගැන උගත් කළ යුතුය, නමුත් ඇත්ත භාෂාව ගණය පද්ධතිය මෙම සිට මා ආරක්ෂා කළ යුතු සිටින අතර එය කරන්නේ නැහැ :(
Andres එෆ්

Answers:


2645

මෙය මට කනිෂ් to සිට අතරමැදි සංවර්ධකයින් යම් අවස්ථාවක දී මුහුණ දෙන සාධාරණ පොදු ගැටළුවක් සේ පෙනේ: ඔවුන් එක්කෝ ඔවුන් සහභාගී වන කොන්ත්‍රාත්තු නොදැන හෝ විශ්වාස නොකරති. මීට අමතරව, තමන්ගේම කේතයක් ලිවීමේදී, ඔවුන් යමක් සඳහන් කිරීම සඳහා නැවත ශුන්‍යයන් මත යැපීමට නැඹුරු වන අතර එමඟින් ඇමතුම්කරුට ශුන්‍යයන් පරීක්ෂා කිරීමට අවශ්‍ය වේ.

මෙය වෙනත් ආකාරයකින් කිවහොත්, ශුන්‍ය පරීක්‍ෂණයක් සිදු වන අවස්ථා දෙකක් තිබේ:

  1. කොන්ත්රාත්තුව අනුව වලංගු ප්රතිචාරයක් ශුන්‍ය වන විට; හා

  2. එය වලංගු ප්‍රතිචාරයක් නොවන තැන.

(2) පහසුය. එක්කෝ assertප්‍රකාශ භාවිතා කරන්න (ප්‍රකාශ) හෝ අසාර්ථක වීමට ඉඩ දෙන්න (නිදසුනක් ලෙස, NullPointerException ). ප්‍රකාශයන් 1.4 හි එකතු කරන ලද ජාවා විශේෂාංගයකි. වාක්‍ය ඛණ්ඩය:

assert <condition>

හෝ

assert <condition> : <object>

කොහේද <condition>බූලියන් ප්‍රකාශනයක් වන අතර <object>එය toString()ක්‍රමයේ ප්‍රතිදානය දෝෂයට ඇතුළත් කරනු ඇත.

assertප්රකාශය ඉතා අවුලට Error( AssertionError) තත්ත්වය සත්යයක් නො වේ නම්. පෙරනිමියෙන්, ජාවා ප්‍රකාශයන් නොසලකා හරියි. විකල්පය -eaජේවීඑම් වෙත යොමු කිරීමෙන් ඔබට ප්‍රකාශයන් සක්‍රීය කළ හැකිය . ඔබට තනි පන්ති සහ පැකේජ සඳහා ප්‍රකාශ සක්‍රිය හා අක්‍රීය කළ හැකිය. මෙයින් අදහස් කරන්නේ, සංවර්ධනය කිරීමේදී සහ පරීක්‍ෂා කිරීමේදී ඔබට ප්‍රකාශයන් සමඟ කේතය වලංගු කළ හැකි අතර නිෂ්පාදන පරිසරයක් තුළ ඒවා අක්‍රීය කළ හැකි වුවද, මගේ පරීක්ෂණයෙන් ප්‍රකාශ කර ඇති කාර්ය සාධන බලපෑමක් නොමැති බව පෙන්නුම් කරයි.

මෙම අවස්ථාවෙහිදී ප්‍රකාශයන් භාවිතා නොකිරීම හරි, මන්ද කේතය අසාර්ථක වනු ඇත, ඔබ ප්‍රකාශ භාවිතා කරන්නේ නම් එය සිදුවනු ඇත. එකම වෙනස නම්, ප්‍රකාශයන් සමඟ එය ඉක්මණින්, වඩාත් අර්ථවත් ආකාරයකින් හා සමහර විට අමතර තොරතුරු සමඟ සිදුවිය හැකි අතර, එය ඔබ අපේක්ෂා නොකළේ නම් එය සිදු වූයේ මන්දැයි සොයා ගැනීමට ඔබට උපකාරී වනු ඇත.

(1) ටිකක් අමාරුයි. ඔබ අමතන කේතය පාලනය කිරීමට ඔබට හැකියාවක් නොමැති නම් ඔබ හිර වී ඇත. ශුන්‍යය වලංගු ප්‍රතිචාරයක් නම්, ඔබ එය පරීක්ෂා කළ යුතුය.

එය ඔබ පාලනය කරන කේතය නම්, කෙසේ වෙතත් (සහ බොහෝ විට මෙය එසේ වේ), එය වෙනස් කතාවකි. ප්‍රතිචාරයක් ලෙස ශුන්‍ය භාවිතා කිරීමෙන් වළකින්න. එකතු කිරීම් ආපසු ලබා දෙන ක්‍රම සමඟ, එය පහසු ය: සෑම විටම ශුන්‍ය වෙනුවට හිස් එකතු කිරීම් (හෝ අරා) ආපසු එවන්න.

එකතු නොකිරීම සමඟ එය වඩාත් අපහසු විය හැකිය. මෙය උදාහරණයක් ලෙස සලකන්න: ඔබට මෙම අතුරුමුහුණත් තිබේ නම්:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

එහිදී Parser අමු පරිශීලක ආදානය ගෙන යමක් කිරීමට සොයා ගනී, සමහර විට ඔබ යම් දෙයක් සඳහා විධාන රේඛා අතුරු මුහුණතක් ක්‍රියාත්මක කරන්නේ නම්. සුදුසු ක්‍රියාමාර්ගයක් නොමැති නම් එය නැවත ලබා දෙන කොන්ත්‍රාත්තුව දැන් ඔබට කළ හැකිය. එය ඔබ කතා කරන ශූන්‍ය පරීක්ෂාවට මග පාදයි.

විකල්ප විසඳුමක් නම් කිසි විටෙකත් ශුන්‍ය නොවන අතර ඒ වෙනුවට ශුන්‍ය වස්තු රටාව භාවිතා කරන්න :

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

සසඳන්න:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

වෙත

ParserFactory.getParser().findAction(someInput).doSomething();

එය වඩා සංක්ෂිප්ත කේතයකට මඟ පෙන්වන නිසා එය වඩා හොඳ නිර්මාණයකි.

අර්ථවත් දෝෂ පණිවිඩයක් සහිත ව්‍යතිරේකයක් විසි කිරීම findAction () ක්‍රමයට සම්පූර්ණයෙන්ම සුදුසු යැයි එයින් කියැවේ - විශේෂයෙන් ඔබ පරිශීලක ආදානය මත විශ්වාසය තබන මේ අවස්ථාවේ දී. පැහැදිලි කිරීමක් නොමැතිව සරල NullPointerException සමඟ පුපුරා යාම සඳහා ඇමතුම් ක්‍රමයට වඩා ව්‍යතිරේකයක් විසි කිරීම FindAction ක්‍රමයට වඩා හොඳය.

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

කිසිවක් නොකරන්න වෙනුවට උත්සාහ කිරීමේ / අල්ලා ගැනීමේ යාන්ත්‍රණය ඉතා අවලස්සන යැයි ඔබ සිතන්නේ නම්, ඔබේ පෙරනිමි ක්‍රියාව පරිශීලකයාට ප්‍රතිපෝෂණය ලබා දිය යුතුය.

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

631
DO_NOTHING ක්‍රියාව සඳහා ඔබගේ ප්‍රකාශ සමඟ මම එකඟ නොවෙමි. සෙවීමේ ක්‍රියා ක්‍රමයට ක්‍රියාවක් සොයාගත නොහැකි නම්, ශුන්‍යව ආපසු යාම නිවැරදි දෙයයි. භාවිතා කළ හැකි ක්‍රියාවක් සොයා ගැනීම සඳහා ක්‍රමයේ මූලධර්මය උල්ලං which නය කරන, ඇත්ත වශයෙන්ම සොයාගත නොහැකි, ඔබේ කේතයේ ක්‍රියාවක් ඔබ සොයාගෙන ඇත.
MetroidFan2002

266
ජාවා හි විශේෂයෙන් ලැයිස්තු සමඟ ශුන්‍යය අධික ලෙස භාවිතා වන බව මම එකඟ වෙමි. බොහෝ ඇපිස් ශුන්‍ය වෙනුවට හිස් ලැයිස්තුවක් / අරා / එකතුවක් ආපසු ලබා දෙන්නේ නම් වඩා හොඳය. බොහෝ විට, ශුන්‍යය භාවිතා කරනුයේ ව්‍යතිරේකයක් විසි කළ යුතු තැනකය. විග්‍රහ කරන්නාට විග්‍රහ කළ නොහැකි නම් ව්‍යතිරේකයක් විසි කළ යුතුය.
ලැප්ලි ඇන්ඩර්සන්

92
මෙහි දෙවන උදාහරණය නම්, IIRC, ශුන්‍ය වස්තු සැලසුම් රටාවයි.
ස්ටීවන් එවර්ස්

62
@ චා (සහ මෙට්‍රොයිඩ් ෆෑන් 2002). සරලයි, එය කොන්ත්රාත්තුවට ඇතුළත් කරන්න, එවිට සොයාගත නොහැකි ආපසු ක්රියාමාර්ගයක් කිසිවක් නොකරන බව පැහැදිලිය. මෙය අමතන්නාට වැදගත් තොරතුරු නම්, එය සොයාගත නොහැකි ක්‍රියාවක් බව සොයා ගැනීමට ක්‍රමයක් සපයන්න (එනම් ප්‍රති result ලය DO_NOTHING වස්තුව දැයි පරීක්ෂා කිරීමට ක්‍රමයක් සපයන්න). විකල්පයක් ලෙස, ක්‍රියාව සාමාන්‍යයෙන් සොයාගත හැකි නම්, ඔබ තවමත් ශුන්‍ය නොවිය යුතු අතර ඒ වෙනුවට නිශ්චිතවම එම තත්වය දැක්වෙන ව්‍යතිරේකයක් විසි කරන්න - මෙය තවමත් වඩා හොඳ කේතයක් ලබා දෙයි. අවශ්‍ය නම්, ක්‍රියාවක් තිබේදැයි පරීක්ෂා කිරීම සඳහා වෙනම ක්‍රමයක් බූලියන් වෙත ආපසු ලබා දෙන්න.
කෙවින් බ්‍රොක්

35
සංක්ෂිප්ත තත්ත්ව කේතයට සමාන නොවේ. මට කණගාටුයි ඔබ එසේ සිතීම. ඔබේ කේතය මඟින් දෝෂයක් වාසිදායක වන අවස්ථා සඟවයි.
gshauger

636

ඔබ ජෙට් බ්‍රේන්ස් ඉන්ටෙලිජ් අයිඩීඒ , සූර්යග්‍රහණය වැනි ජාවා IDE එකක් භාවිතා කරන්නේ නම් (හෝ භාවිතා කිරීමට සැලසුම් කරන්නේ නම්) හෝ Netbeans හෝ findbugs වැනි මෙවලමක් එවිට මෙම ප්රශ්නය විසඳීම සඳහා විවරණයන් ඉදිරිපත් භාවිතා කළ හැකිය.

කොටින්ම, ඔබට තිබේ @Nullable සහ @NotNull.

ඔබට මේ ආකාරයට ක්‍රම සහ පරාමිතීන් භාවිතා කළ හැකිය:

@NotNull public static String helloWorld() {
    return "Hello World";
}

හෝ

@Nullable public static String helloWorld() {
    return "Hello World";
}

දෙවන උදාහරණය සම්පාදනය නොකරනු ඇත (IntelliJ IDEA හි).

ඔබ පළමු helloWorld()ශ්‍රිතය වෙනත් කේත කැබැල්ලක භාවිතා කරන විට :

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

දැන් IntelliJ IDEA සම්පාදකයා ඔබට කියනු ඇත්තේ චෙක්පත නිෂ් less ල බවය helloWorld() ශ්‍රිතය නැවත නොපැමිණෙන nullබැවිනි.

පරාමිතිය භාවිතා කිරීම

void someMethod(@NotNull someParameter) { }

ඔබ එවැනි දෙයක් ලියන්නේ නම්:

someMethod(null);

මෙය සම්පාදනය නොකරයි.

භාවිතා කරන අවසාන උදාහරණය @Nullable

@Nullable iWantToDestroyEverything() { return null; }

මෙය කිරීම

iWantToDestroyEverything().something();

මෙය සිදු නොවන බවට ඔබට සහතික විය හැකිය. :)

සම්පාදකයාට සාමාන්‍යයෙන් කරනවාට වඩා යමක් පරීක්ෂා කිරීමට ඉඩ දීම සහ ඔබේ කොන්ත්‍රාත්තු ශක්තිමත් වීමට බලාත්මක කිරීම හොඳ ක්‍රමයකි. අවාසනාවට, එය සියලු සම්පාදකයින්ගේ සහාය නොලැබේ.

IntelliJ IDEA 10.5 සහ ඊට පසුව ඔවුන් වෙනත් ඕනෑම @Nullable @NotNullක්‍රියාත්මක කිරීමක් සඳහා සහය එක් කළහ .

බ්ලොග් සටහන බලන්න වඩාත් නම්‍යශීලී සහ වින්‍යාසගත කළ හැකි @ අහෝසි කළ හැකි / @ නොට්ල් විවරණ .


120
@NotNull, @Nullableසහ වෙනත් ශුන්‍ය විවරණ JSR 305 හි කොටසකි . FindBugs වැනි මෙවලම් සමඟ ඇති විය හැකි ගැටළු හඳුනා ගැනීමට ඔබට ඒවා භාවිතා කළ හැකිය .
ජාසෙක් එස්

32
@NotNull& @Nullableඅතුරුමුහුණත් පැකේජයේ ජීවත්වීම මට පුදුම සහගතය com.sun.istack.internal. (මම හිතන්නේ මම com.sun හිමිකාර API භාවිතා කිරීම පිළිබඳ අනතුරු ඇඟවීම් සමඟ සම්බන්ධ කරමි.)
ජොනික්

20
කේත අතේ ගෙන යා හැකි හැකියාව ජෙට්බ්‍රේන් සමඟ අහෝසි වේ. අයිඩියල් මට්ටමට බැඳීමට පෙර මම දෙවරක් (හතරැස්) සිතමි. ලයික් ජේසෙක් එස් පැවසුවේ ඔවුන් ජේඑස්ආර් හි කොටසක් බවයි.
ජාවා කා බේබි

10
අභිරුචි සම්පාදකයක් භාවිතා කිරීම මෙම ගැටලුවට ශක්‍ය විසඳුමක් යැයි මම නොසිතමි.
ශිවන් ඩ්‍රැගන්

64
විවරණයන් ඉදිරිපත් ගැන හොඳ දෙයක්, වන @NotNullහා @Nullableප්රභව කේත ඔවුන් වටහා ගැනීමට නොහැකි බව පද්ධතිය විසින් ඉදි කරන විට ඔවුන් අවසරයෙන් හායනය බව ය වේ. එබැවින්, ඇත්ත වශයෙන්ම, කේතය අතේ ගෙන යා නොහැකි බවට වන තර්කය අවලංගු විය හැකිය - ඔබ මෙම ව්‍යාඛ්‍යාවන්ට සහාය දක්වන සහ තේරුම් ගන්නා පද්ධතියක් භාවිතා කරන්නේ නම්, ඔබට දැඩි දෝෂ පරීක්ෂා කිරීමේ අමතර ප්‍රතිලාභයක් ලැබේ, එසේ නොමැතිනම් ඔබට එයින් අඩුවෙන් ලැබෙනු ඇත, නමුත් ඔබේ කේතය තවමත් තිබිය යුතුය දඩය ගොඩනඟා ගන්න, ඔබේ ධාවන වැඩසටහනේ ගුණාත්මකභාවය එකම වේ, මන්ද මෙම විවරණ කෙසේ වෙතත් ධාවන වේලාවේදී බලාත්මක නොවූ බැවිනි. ඊට අමතරව, සියලුම සම්පාදකයින් අභිරුචි ය ;-)
amn

322

ශුන්‍ය අගයන්ට ඉඩ නොදෙන්නේ නම්

ඔබේ ක්‍රමය බාහිරව හැඳින්වුවහොත්, මේ වගේ දෙයක් සමඟ ආරම්භ කරන්න:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

එවිට, එම ක්‍රමයේ ඉතිරි කොටසෙහි, objectඑය ශුන්‍ය නොවන බව ඔබ දැන ගනු ඇත.

එය අභ්‍යන්තර ක්‍රමයක් නම් (API එකක කොටසක් නොවේ), එය අහෝසි කළ නොහැකි බව ලේඛනගත කරන්න, එය එයයි.

උදාහරණයක්:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

කෙසේ වෙතත්, ඔබේ ක්‍රමය මඟින් අගය ඉක්මවා ගියහොත් සහ ඊළඟ ක්‍රමය එය සම්මත කළහොත් එය ගැටළු සහගත විය හැකිය. එවැනි අවස්ථාවකදී ඉහත තර්කය පරීක්ෂා කිරීමට ඔබට අවශ්‍ය විය හැකිය.

ශුන්‍ය වීමට අවසර තිබේ නම්

මෙය සැබවින්ම රඳා පවතී. මම බොහෝ විට මෙවැනි දෙයක් කරන බව සොයා ගන්නේ නම්:

if (object == null) {
  // something
} else {
  // something else
}

ඒ නිසා මම අතු බෙදී සම්පූර්ණයෙන්ම වෙනස් දේවල් දෙකක් කරනවා. අවලස්සන කේත ස්නිපටයක් නොමැත, මන්ද මට දත්ත අනුව වෙනස් දේවල් දෙකක් කළ යුතු බැවිනි. උදාහරණයක් ලෙස, මම ආදානය මත වැඩ කළ යුතුද, නැතහොත් හොඳ පෙරනිමි අගයක් ගණනය කළ යුතුද?


මෝඩකම භාවිතා කිරීම ඇත්තෙන්ම දුර්ලභ ය if (object != null && ....

ඔබ සාමාන්‍යයෙන් මෝඩකම භාවිතා කරන ස්ථානය පිළිබඳ උදාහරණ පෙන්වන්නේ නම් ඔබට උදාහරණ ලබා දීම පහසු වනු ඇත.


94
නීතිවිරෝධී විග්‍රහය විසි කිරීමේ තේරුම කුමක්ද? මම හිතන්නේ NullPointerException වඩාත් පැහැදිලි වනු ඇති අතර ඔබ විසින්ම ඔබ විසින්ම ශුන්‍ය පරීක්‍ෂණයක් නොකරන්නේ නම් එයද විසි කරනු ඇත. එක්කෝ මම තරයේ කියා සිටිමි.
ඇක්සෙල්

23
ශුන්‍ය හැර අනෙක් සෑම අගයක්ම පිළිගත හැකි යැයි සිතිය නොහැක. ඔබට නීතිවිරෝධී ආරෝපණ එක්සෙප්ෂන්, OutOfRageException යනාදිය තිබිය හැකිය. සමහර විට මෙය අර්ථවත් කරයි. වෙනත් වේලාවක ඔබ කිසිදු වටිනාකමක් එක් නොකරන ව්‍යතිරේක පංති රාශියක් නිර්මාණය කිරීමෙන් පසුව ඔබ භාවිතා කරන්නේ නීති විරෝධී ආරෝපණ එක්සෙප්ෂන් ය. ශුන්‍ය ආදානය සඳහා එක් ව්‍යතිරේකයක් සහ අනෙක් සියල්ල සඳහා තවත් එකක් තිබීම අර්ථවත් නොවේ.
myplacedk

7
ඔව්, මම අසමත්-වේගවත්-මූලධර්මයට එකඟ වෙමි, නමුත් ඉහත උදාහරණයේ දී, අගය සම්මත නොකෙරේ, නමුත් ක්‍රමයක් ලෙස හැඳින්විය යුතු වස්තුව එයයි. එබැවින් එය වේගයෙන් සමානව අසමත් වන අතර, එකවර හා ස්ථානයෙන් කෙසේ හෝ විසි කළ හැකි ව්‍යතිරේකයක් විසි කිරීම සඳහා ශුන්‍ය චෙක්පතක් එක් කිරීමෙන් නිදොස් කිරීම පහසු නොවන බවක් නොපෙනේ.
ඇක්සෙල්

8
ආරක්ෂක වළක්? JDK මේ වගේ කේත වලින් පිරී ඇත. පරිශීලකයාට සිරස් තල දැකීමට අවශ්‍ය නැතිනම් ඒවා අක්‍රීය කරන්න. හැසිරීම ලේඛනගත කර නොමැති බව කිසිවෙකු ඇඟවූයේ නැත. MySQL ලියා ඇත්තේ C හි වන අතර එහිදී ශුන්‍ය දර්ශක අවලංගු කිරීම නිර්වචනය නොකළ හැසිරීමකි, ව්‍යතිරේකයක් විසි කිරීම වැනි කිසිවක් නැත.
fgb

8
throw new IllegalArgumentException("object==null")
Thorbj Rrn Ravn Andersen

238

ඇවැත්නි, අපට නිර්දේශ කිරීමට විවිධ ක්‍රම 57 ක් ඇති විට තවත් පිළිතුරක් එක් කිරීමට මම බොහෝ දුරට අකමැතියි NullObject pattern, නමුත් මෙම ප්‍රශ්නය ගැන උනන්දුවක් දක්වන සමහර අය ජාවා 7 සඳහා “ශුන්‍ය-ආරක්ෂිත” එකතු කිරීම සඳහා මේසයේ යෝජනාවක් ඇති බව දැන ගැනීමට කැමති යැයි මම සිතමි. හැසිරවීම " if-සමාන-ශුන්‍ය නොවන තර්කනය සඳහා විධිමත් වාක්‍ය ඛණ්ඩයකි.

ඇලෙක්ස් මිලර් දුන් උදාහරණය මෙයයි:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

මෙම ?.මාර්ගයෙන් පමණක් ද-යොමු වම් හඳුනාගැනීමේ එය ශූන්ය නොවේ නම්, වෙනත් ආකාරයකින් ලෙස අදහස් ප්රකාශ කිරීමේ ඉතිරි ඇගයීමට null. ජාවා පොස්සේ සාමාජික ඩික් වෝල් සහ ඩෙවොක්ස් හි ඡන්දදායකයින් වැනි සමහර අය මෙම යෝජනාවට සැබවින්ම ඇලුම් කරති. එහෙත් විරුද්ධත්වයක් ද ඇත null.


යාවත්කාලීන කිරීම: එක් නිල යෝජනාව ජාවා 7 දී ශූන්ය-ආරක්ෂිත ක්රියාකරු යටතේ ඉදිරිපත් කර ඇති බවත් සඳහා ව්යාපෘති කාසිය. වාක්‍ය ඛණ්ඩය ඉහත උදාහරණයට වඩා ටිකක් වෙනස් ය, නමුත් එය එකම අදහසකි.


යාවත්කාලීන කිරීම: ශුන්‍ය-ආරක්ෂිත ක්‍රියාකරු යෝජනාව එය ව්‍යාපෘති කාසියට ඇතුළත් කර නැත. එබැවින්, ඔබට මෙම වාක්‍ය ඛණ්ඩය ජාවා 7 හි නොපෙනේ.


20
මම හිතන්නේ මේක වැරදියි. දී ඇති විචල්‍යය සැමවිටම ශුන්‍ය නොවන බව සඳහන් කිරීමට ක්‍රමයක් තිබිය යුතුය.
Thorbjørn Ravn Andersen

5
යාවත්කාලීන කිරීම: යෝජනාව ජාවා 7 බවට පත් නොකරනු ඇත. Blogs.sun.com/darcy/entry/project_coin_final_five බලන්න .
බොරිස් ටර්සික්

9
සිත්ගන්නා අදහස නමුත් සින්ටැක්ස් තේරීම විකාරයකි; සෑම සන්ධියකටම ප්‍රශ්න ලකුණු වලින් පිරුණු කේත පදනමක් මට අවශ්‍ය නැත.
රොබ්

7
මෙම ක්‍රියාකරු ග්‍රෝවි හි පවතී , එබැවින් එය භාවිතා කිරීමට කැමති අයට එය විකල්පයක් ලෙස පවතී.
මුහ්ඩ්

8
මෙය මා දුටු වඩාත්ම දක්ෂ අදහසයි. සී සින්ටැක්ස් හි සෑම සංවේදී භාෂාවකටම එය එකතු කළ යුතුය. තිරය ​​පුරා රේඛා අනුචලනය කිරීමට හෝ දවස පුරා “ආරක්ෂක වගන්ති” තට්ටු කිරීමට වඩා මම සෑම තැනකම “ප්‍රශ්න ලකුණු” කිරීමට කැමතියි.
වික්ටර්

196

නිර්වචනය නොකළ අගයන්ට අවසර නොමැති නම්:

විභව ශුන්‍ය අවලංගු කිරීම් ගැන ඔබට අනතුරු ඇඟවීම සඳහා ඔබේ IDE වින්‍යාසගත කළ හැකිය. උදා: සූර්යග්‍රහණයේ, මනාප> ජාවා> සම්පාදක> දෝෂ / අනතුරු ඇඟවීම් / ශුන්‍ය විශ්ලේෂණය බලන්න .

නිර්වචනය නොකළ අගයන්ට අවසර තිබේ නම්:

නිර්වචනය නොකළ අගයන් අර්ථවත් වන නව API එකක් අර්ථ දැක්වීමට ඔබට අවශ්‍ය නම් , විකල්ප රටාව භාවිතා කරන්න (ක්‍රියාකාරී භාෂාවලින් හුරුපුරුදු විය හැකිය). එයට පහත වාසි ඇත:

  • ආදානයක් හෝ ප්‍රතිදානයක් තිබේද නැද්ද යන්න ඒපීඅයි හි පැහැදිලිව සඳහන් කර ඇත.
  • "නිර්වචනය නොකළ" නඩුව හැසිරවීමට සම්පාදකයා ඔබට බල කරයි.
  • විකල්පය මොනාඩ් වේ , එබැවින් වාචික ශුන්‍ය පරීක්‍ෂණයක් අවශ්‍ය නොවේ, අගය ආරක්ෂිතව භාවිතා කිරීම සඳහා සිතියම / foreach / getOrElse හෝ ඒ හා සමාන සංයෝජකයක් භාවිතා කරන්න (උදාහරණය) .

ජාවා 8 හි සාදන ලද Optionalපන්තියක් ඇත (නිර්දේශිත); පෙර වෙළුම් සඳහා, උදාහරණයක් පුස්තකාල විකල්ප, ඇත පේර ගේ Optionalහෝ FunctionalJava ගේ Option. නමුත් බොහෝ ක්‍රියාකාරී ශෛලියේ රටා මෙන්, ජාවා හි විකල්පය භාවිතා කිරීම (8 පවා) බොහෝ බොයිලර් තහඩුවලට හේතු වේ, එමඟින් ඔබට අඩු වාචික ජේවීඑම් භාෂාවක් භාවිතා කිරීම අඩු කළ හැකිය, උදා: ස්කලා හෝ එක්ස්ටෙන්ඩ්.

ඔබට ශුන්‍ය ආපසු ලබා දිය හැකි API සමඟ ගනුදෙනු කිරීමට සිදුවුවහොත් , ඔබට ජාවා හි බොහෝ දේ කළ නොහැක. එක්ස්ටෙන්ඩ් සහ ග්‍රෝවි සතුව එල්විස් ක්‍රියාකරු ?: සහ ශුන්‍ය-ආරක්ෂිත විරූපණ ක්‍රියාකරු ඇත ?. , නමුත් මෙය ශුන්‍ය යොමු කිරීමකදී ශුන්‍ය වන බව සලකන්න, එබැවින් එය ශුන්‍ය ලෙස නිසි ලෙස හැසිරවීම “කල් දමයි”.


22
ඇත්ත වශයෙන්ම, විකල්ප රටාව නියමයි. සමහර ජාවා සමානකම් පවතී. ගුවා හි මෙම විකල්පයේ සීමිත අනුවාදයක් අඩංගු වන අතර එමඟින් බොහෝ ක්‍රියාකාරී දේ අත්හරිනු ඇත. හස්කල් හි මෙම රටාව සමහර විට හැඳින්වේ.
බෙන් හාඩි

9
විකල්ප පන්තියක් ජාවා 8
පියරේ හෙන්රි

1
... එයට (තවමත්) සිතියමක් හෝ පැතලි සිතියමක් නොමැත: download.java.net/jdk8/docs/api/java/util/Optional.html
thSoft

3
විකල්ප රටාව කිසිවක් විසඳන්නේ නැත; එක් ශුන්‍ය වස්තුවක් වෙනුවට, දැන් ඔබට දෙකක් තිබේ.
බෝවන්

1
O බෝන්, පරිස්සමින් භාවිතා කරන්නේ නම්, ඔබ ඔබේ සියලු අක්‍රීය ණය ගැටළු විසඳයි. එසේ නොවේ නම්, "භාවිත" ගැටලුවක් ඇති බව මම අනුමාන කරමි.
ලුවී එෆ්.

189

මෙම තත්වය සඳහා පමණි -

සමානාත්මතා ක්‍රමයක් ක්‍රියාත්මක කිරීමට පෙර විචල්‍යයක් ශුන්‍ය දැයි පරීක්ෂා නොකිරීම (නූලක් පහත උදාහරණය සංසන්දනය කරන්න):

if ( foo.equals("bar") ) {
 // ...
}

නොපවතින NullPointerExceptionනම් fooප්‍රති result ල ලැබෙනු ඇත .

ඔබ මේ ආකාරයට සංසන්දනය කළහොත් ඔබට එය වළක්වා ගත හැකිය String:

if ( "bar".equals(foo) ) {
 // ...
}

42
මම එකඟ වෙමි - එම තත්වය තුළ පමණි. මෙය ඊළඟ අනවශ්‍ය මට්ටමට ගෙන ගිය ක්‍රමලේඛකයන්ට නැගී සිටිමින් (ශුන්‍ය! = MyVar) නම් ලිවිය නොහැක ... මට අවලස්සන පෙනුමක් ඇති අතර කිසිදු අරමුණක් ඉටු නොකරයි!
ඇලෙක්ස් වර්ඩන්

20
මෙය සාමාන්‍ය හොඳ පුරුද්දකට වඩාත්ම භාවිතා කරන විශේෂිත උදාහරණයකි: ඔබ එය දන්නේ නම්, සෑම විටම කරන්න <object that you know that is not null>.equals(<object that might be null>);. equalsඔබ කොන්ත්රාත්තුව දන්නේ නම් සහ එම ක්රමවලට nullපරාමිතීන් හැසිරවිය හැකි නම් හැර වෙනත් ක්රම සඳහා එය ක්රියා කරයි .
ස්ටෙප්

9
ඇත්ත වශයෙන්ම අර්ථවත් වන යෝඩා තත්වයන් පිළිබඳව මා දුටු පළමු උදාහරණය මෙයයි
එරින් ඩ්‍රම්මන්ඩ්

6
NullPointerExceptions හේතුවක් සඳහා විසි කරනු ලැබේ. ඒවා විසි කරනු ලබන්නේ වස්තුවක් තිබිය යුතු තැන අහෝසි වන බැවිනි. මෙය නිවැරදි කිරීම ක්‍රමලේඛකයින්ගේ කාර්යය මිස ගැටලුව සඟවන්න නොවේ.
ඔලිවර් වොට්කින්ස්

1
උත්සාහ කරන්න- Catch-DoNothing ගැටලුව සඟවයි, භාෂාවේ සීනි නැතිවීම පිළිබඳව කටයුතු කිරීම වලංගු භාවිතයකි.
echox

167

ජාවා 8 සමඟ නව java.util.Optionalපංතිය පැමිණෙන්නේ සමහර ගැටලු විසඳිය හැකි බැවිනි. කෙනෙකුට අවම වශයෙන් එය කේතයේ කියවීමේ හැකියාව වැඩි දියුණු කරන බව පැවසිය හැකි අතර, පොදු ඒපීඅයි වලදී ඒපීඅයි හි කොන්ත්‍රාත්තුව සේවාදායක සංවර්ධකයාට වඩාත් පැහැදිලි කරයි.

ඔවුන් එසේ ක්‍රියා කරයි:

දී ඇති වර්ගයක් සඳහා විකල්ප වස්තුවක් ( Fruit) ක්‍රමයක ආපසු වර්ගය ලෙස නිර්මාණය වේ. එය හිස් හෝ Fruitවස්තුවක් අඩංගු විය හැකිය:

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

දැන් ලබා දී ඇති පළතුරු උදාහරණයක් සඳහා Fruit( fruits) ලැයිස්තුවක් සොයන මෙම කේතය දෙස බලන්න :

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

map()විකල්ප වස්තුවක් මත ගණනය කිරීමක් සිදු කිරීමට ඔබට ක්‍රියාකරු භාවිතා කළ හැකිය . orElse()නැතිවූ අගයන් සඳහා පසුබෑමක් සැපයීමට ඔබට ඉඩ දෙයි.

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

ඇත්ත වශයෙන්ම, ශුන්‍ය / හිස් අගය සඳහා චෙක්පත තවමත් අවශ්‍ය වේ, නමුත් අවම වශයෙන් සංවර්ධකයා දැනුවත්ව වටිනාකම හිස් විය හැකි අතර පරීක්ෂා කිරීමට අමතක වීමේ අවදානම සීමිතය.

මුල සිට සාදන ලද API Optionalඑකක ප්‍රතිලාභ අගයක් හිස් වූ විට භාවිතා කරමින් සරල වස්තුවක් ආපසු ලබා දිය හැකි විට null(සම්මුතිය), සේවාදායක කේතය සරල වස්තු ප්‍රතිලාභ අගයන් පිළිබඳ ශුන්‍ය චෙක්පත් අතහැර දැමිය හැකිය ...

ඇත්ත වශයෙන්ම Optionalක්‍රම තර්කයක් ලෙසද භාවිතා කළ හැකිය, සමහර විට අධි බර පැටවීමේ ක්‍රම 5 හෝ 10 ට වඩා විකල්ප තර්ක දැක්වීමට වඩා හොඳ ක්‍රමයක් විය හැකිය.

OptionalorElseපෙරනිමි අගයක් භාවිතා කිරීමට ඉඩ දෙන, සහ ලැම්බඩා ප්‍රකාශනifPresent සමඟ ක්‍රියා කරන වෙනත් පහසු ක්‍රම ඉදිරිපත් කරයි .

NullPointerException(සහ පොදුවේ ශුන්‍ය දර්ශකය) ගැටළු සහගත මෙන්ම (අර්ධ වශයෙන්) ගෙන එන ලද මෙම ලිපිය (මෙම පිළිතුර ලිවීම සඳහා මගේ ප්‍රධාන මූලාශ්‍රය) කියවීමට මම ඔබට ආරාධනා කරමි Optional: ජාවා විකල්ප වස්තු .


11
ගූගල් හි ගුආවා ජාවා 6+ සඳහා විකල්ප ඇඟවීමක් ඇත.
බ්‍රැඩ්ලි ගොට්ෆ්‍රයිඩ්

13
ඒක ගොඩක් ifPresent (සමග විකල්ප පමණක්) භාවිතා කරමින් බව අවධාරණය කිරීමට වැදගත් නොවන සාමාන්ය ශූන්ය පරීක්ෂා කිරීම ඉහත බොහෝ අගය එකතු කරන්න. එහි මූලික වටිනාකම වන්නේ එය සිතියම / ෆ්ලැප්මැප් හි ක්‍රියාකාරී දාමයන්හි භාවිතා කළ හැකි මොනාඩ් එකක් වන අතර එය වෙනත් තැනක සඳහන් කර ඇති ග්‍රෝවි හි එල්විස් ක්‍රියාකරුට සමාන ප්‍රති results ල ලබා ගනී. මෙම භාවිතයෙන් තොරව වුවද, orElse / orElseThrow සින්ටැක්ස් ද ඉතා ප්‍රයෝජනවත් බව මට පෙනේ.
කෝනල් මැසන්

මෙම බ්ලොග් අඩවියට විකල්ප වින්ටර්බේ.කොම්
JohnC

4
මිනිසුන්ට මෙය කිරීමට නැඹුරුවක් ඇත්තේ ඇයි if(optional.isPresent()){ optional.get(); }ඒ වෙනුවටoptional.ifPresent(o -> { ...})
සත්‍යේන්ද්‍ර කුමාර්

1
එබැවින්, ඒපීඅයි ගිවිසුම්ගත ඉඟි හැරුණු විට, එය ඇත්ත වශයෙන්ම දම්වැල් ක්‍රම නිමක් නැතිව භුක්ති විඳින ක්‍රියාකාරී ක්‍රමලේඛකයන්ට සැපයීම පමණි.
පොඩි කරන්න

125

ඔබ පරීක්ෂා කරන්නේ කුමන ආකාරයේ වස්තූන් මත පදනම්ව, ඔබට අපාචේ කොමන්ස් හි සමහර පන්ති භාවිතා කළ හැකිය: අපාචේ කොමන්ස් ලැන්ග් සහ අපාචේ කොමන්ස් එකතුව

උදාහරණයක්:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

හෝ (ඔබ පරීක්ෂා කළ යුතු දේ අනුව):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

StringUtils පන්තිය බොහෝ දෙනාගෙන් එකක් පමණි; ශුන්‍ය ආරක්ෂිත හැසිරවීමක් කරන කොමන්ස් හි හොඳ පන්ති කිහිපයක් තිබේ.

ඔබ අපාචේ පුස්තකාලය (කොමන්ස්-ලැන්ග් -2.4.ජාර්) ඇතුළත් කරන විට ජාවා හි ශුන්‍ය වලංගුකරණය භාවිතා කළ හැකි ආකාරය පිළිබඳ උදාහරණයක් මෙහි දැක්වේ.

public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

ඔබ වසන්තය භාවිතා කරන්නේ නම්, වසන්තය එහි පැකේජයේ එකම ක්‍රියාකාරීත්වයක් ඇත, පුස්තකාලය බලන්න (වසන්තය -2.4.6.ජාර්)

වසන්තයේ සිට මෙම ස්ථිතික පංතිය භාවිතා කරන්නේ කෙසේද යන්න පිළිබඳ උදාහරණය (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");

5
අපාචේ කොමන්ස් වෙතින් ඔබට වඩාත් සාමාන්‍ය අනුවාදය භාවිතා කළ හැකිය, මා සොයාගත් පරාමිතීන් පරීක්ෂා කිරීම සඳහා ක්‍රම ආරම්භයේදී එය බෙහෙවින් ප්‍රයෝජනවත් වේ. Validate.notNull (වස්තුව, "වස්තුව ශුන්‍ය නොවිය යුතුය"); commons.apache.org/lang/apidocs/org/apache/commons/lang/…
monojohnny

@monojohnny වලංගු කිරීම මඟින් ප්‍රකාශ ප්‍රකාශය භාවිතා කරයිද? මම එය අසන්නේ ජේවීඑම් හි ඇසර්ට් සක්‍රිය / අක්‍රිය කළ හැකි නිසාත් එය නිෂ්පාදනයේ භාවිතා නොකරන ලෙසත් යෝජනා කරයි.
කුරපිකා

එසේ සිතන්න එපා - වලංගු කිරීම අසමත් වුවහොත් එය ධාවන වේලාවක් ලබා දෙන බව මම විශ්වාස කරමි
මොනොජොනි

96
  • වස්තුවක් ශුන්‍ය නොවිය යුතු යැයි ඔබ සලකන්නේ නම් (හෝ එය දෝෂයකි) ප්‍රකාශයක් භාවිතා කරන්න.
  • ඔබේ ක්‍රමය ශුන්‍ය පරාමිතීන් පිළිගන්නේ නැත්නම් එය ජාවාඩොක් තුළ පවසන්න.

ඔබ වස්තුව සඳහා පරික්ෂා කළ යුතුය! = ශුන්‍ය ඔබට වස්තුව ශුන්‍ය විය හැකි නඩුව හැසිරවීමට අවශ්‍ය නම් පමණි ...

ශුන්‍ය / නොනවතින පරාමිතීන් සඳහා ජාවා 7 හි නව විවරණ එකතු කිරීමට යෝජනාවක් ඇත: http://tech.puredanger.com/java7/#jsr308



91

මම "වේගයෙන් අසමත්" කේතයේ රසිකයෙක්මි. ඔබෙන්ම මෙසේ අසන්න - පරාමිතිය අහෝසි වූ විට ඔබ ප්‍රයෝජනවත් යමක් කරනවාද? ඔබේ කේතය එම අවස්ථාවේ දී කළ යුතු දේ පිළිබඳව ඔබට පැහැදිලි පිළිතුරක් නොමැති නම් ... එනම් එය කිසි විටෙකත් ශුන්‍ය නොවිය යුතුය, පසුව එය නොසලකා හැර NullPointerException විසි කිරීමට ඉඩ දෙන්න. ඇමතුම් කේතය නීතිවිරෝධී ආරෝපණ එක්සෙප්ෂන් එකක් මෙන් එන්පීඊ පිළිබඳ හැඟීමක් ඇති කරයි, නමුත් ඔබේ කේතය වෙනත් අනපේක්ෂිත අවිනිශ්චිතතාවයක් ක්‍රියාත්මක කිරීමට උත්සාහ කරනවාට වඩා එන්පීඊ එකක් විසි කළ හොත් වැරැද්ද කුමක්දැයි තේරුම් ගැනීමට සංවර්ධකයාට පහසු වනු ඇත. තර්කනය - එහි ප්‍රති results ලය වන්නේ යෙදුම කෙසේ හෝ අසමත් වීමයි.


2
ප්‍රකාශ භාවිතා කිරීම වඩා හොඳය, එනම් Contract.notNull (abc, "abc ශුන්‍ය නොවිය යුතුය, xyz අතරතුර පැටවීමට අපොහොසත් වූවාද?"); - මෙය if (abc! = Null) {නව RuntimeException විසි කරන්න ...}
ianpojman

76

ගූගල් එකතු කිරීමේ රාමුව මඟින් ශුන්‍ය චෙක්පතක් ලබා ගැනීම සඳහා හොඳ සහ අලංකාර ක්‍රමයක් ඉදිරිපත් කරයි.

පුස්තකාල පන්තියක මෙවැනි ක්‍රමයක් තිබේ:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

භාවිතය (සමඟ import static):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

හෝ ඔබේ උදාහරණයේ:

checkNotNull(someobject).doCalc();

71
mmm, වෙනස කුමක්ද? p.getAge () එකම එන්පීඊයට වඩා අඩු ඉහළින් සහ පැහැදිලි තොගයක් සහිතව විසි කරයි. මට නැති වී ඇත්තේ කුමක්ද?
mysomic

15
ඔබේ උදාහරණයේ නීතිවිරෝධී ආරෝපණ එක්සෙප්ෂන් ("e == null") විසි කිරීම වඩා හොඳය, එය ක්‍රමලේඛකයා විසින් අපේක්‍ෂා කරන ලද ව්‍යතිරේකයක් බව පැහැදිලිව පෙන්නුම් කරන හෙයින් (ගැටලුව හඳුනා ගැනීමට නඩත්තුකරුට සැබවින්ම ඉඩ ලබා දීමට ප්‍රමාණවත් තොරතුරු සමඟ). NullPointerException JVM සඳහා වෙන් කළ යුතුය, එවිට එය පැහැදිලිවම පෙන්නුම් කරන්නේ මෙය නොදැනුවත්ව සිදු වූවක් බවය (සාමාන්‍යයෙන් එය හඳුනා ගැනීමට අපහසු තැනක සිදු වේ)
Thorbjørn Ravn Andersen

6
මෙය දැන් ගූගල් ගුවා හි කොටසකි.
ස්ටීවන් බෙනිටෙස්

32
මට අධික ඉංජිනේරු විද්‍යාව වගේ. ජේවීඑම් හට එන්පීඊ එකක් විසි කිරීමට ඉඩ දෙන්න.
ඇලෙක්ස් වර්ඩන්

5
මම එයට කැමති අතර තර්ක පිළිබඳ පැහැදිලි චෙක්පත් සහිත බොහෝ ක්‍රම සහ ඉදිකිරීම්කරුවන් විවෘත කරමි; දෝෂයක් තිබේ නම්, ක්‍රම සෑම විටම පළමු පේළි කිහිපය තුළම අසමත් වන අතර එවැනි දෙයක් සොයා නොගෙන වරදකාරී සඳහන මම දනිමිgetThing().getItsThing().getOtherThing().wowEncapsulationIsBroken().setLol("hi");
කෝරි කෙන්ඩල්

75

සමහර විට, සමමිතික මෙහෙයුමක් නිර්වචනය කරන එහි පරාමිතීන් මත ක්‍රියාත්මක වන ක්‍රම ඔබට ඇත:

a.f(b); <-> b.f(a);

B කිසි විටෙකත් ශුන්‍ය විය නොහැකි බව ඔබ දන්නේ නම්, ඔබට එය මාරු කළ හැකිය. සමානාත්මතාවය සඳහා එය වඩාත් ප්‍රයෝජනවත් වේ: foo.equals("bar");වඩා හොඳ කරන්න වෙනුවට "bar".equals(foo);.


2
නමුත් එවිට ඔබ උපකල්පනය equalsකළ යුතුය (ඕනෑම ක්‍රමයක් විය හැකිය) ශුන්‍යව නිවැරදිව හැසිරෙනු ඇත. ඇත්ත වශයෙන්ම මේ සියල්ල කරන්නේ වගකීම වෙනත් කෙනෙකුට පැවරීමයි (හෝ වෙනත් ක්‍රමයක්).
සුපර්සි

4
Up සුපර්සි මූලික වශයෙන් ඔව්, නමුත් equals(හෝ ඕනෑම ක්‍රමයක්) nullකෙසේ හෝ පරික්ෂා කළ යුතුය. නැතහොත් එය එසේ නොවන බව පැහැදිලිව ප්‍රකාශ කරන්න.
ඇන්ජලෝ ෆුච්

74

එහි භාවිතයන් ඇති ශුන්‍ය වස්තු රටාව වෙනුවට - ශුන්‍ය වස්තුව දෝෂයක් වන අවස්ථා සලකා බැලිය හැකිය.

ව්යතිරේකය විසි කරන විට, තොග හෝඩුවාව පරීක්ෂා කර දෝෂය හරහා වැඩ කරන්න.


17
ගැටළුව නම් සාමාන්‍යයෙන් ඔබ සන්දර්භය ලිහිල් කිරීම නිසා NullPointerException WHICH විචල්‍යය ශුන්‍ය වූ බවක් නොපෙන්වන අතර ඔබට "." කිහිපයක් තිබිය හැකිය - රේඛාවේ මෙහෙයුම්. "If (foo == null) විසි කිරීම නව RuntimeException (" foo == null ")" භාවිතා කිරීමෙන් වැරැද්ද කුමක්ද යන්න පැහැදිලිව ප්‍රකාශ කිරීමට ඔබට ඉඩ සලසයි.
Thorbjørn Ravn Andersen

1
ඇන්ඩර්සන් සමඟ - ජාවා හි ව්‍යතිරේක පද්ධතියට ක්‍රියා කරන විචල්‍යයක නමක් ඇතුළත් කිරීමට මම කැමතියි, එවිට NullPointerException මඟින් ව්‍යතිරේකය සිදුවූ රේඛාව පමණක් නොව විචල්‍ය නාමයද දක්වනු ඇත. අපැහැදිලි මෘදුකාංග වල මෙය හොඳින් ක්‍රියාත්මක විය යුතුය.
fwielstra

මම තවම එය ක්‍රියාත්මක කිරීමට සමත් වී නැත, නමුත් මෙය හරියටම එම ගැටළුව විසඳීමට අදහස් කරයි.
MatrixFrog

ප්රශ්නය කුමක් ද? ප්‍රමාණවත් සන්දර්භයක් ඇති සුදුසු මට්ටමින් NPE අල්ලාගෙන, සන්දර්භය පිළිබඳ තොරතුරු ඉවත දමා ව්‍යතිරේකය නැවත සලකා බලන්න ... එය ජාවා සමඟ එතරම් පහසුය.
user1050755

3
ක්‍රමවේදය ඇමතුම් දාමයට එරෙහිව දේශනා කළ මහාචාර්යවරයෙක් මට සිටියේය. ඔහුගේ න්‍යාය වූයේ ක්‍රම 2 කට වඩා දිගු ඇමතුම් දාමයන්ගෙන් ඔබ පරිස්සම් විය යුතු බවයි. එය දැඩි රීතියක් දැයි මම නොදනිමි, නමුත් එය නිසැකවම NPE තොග හෝඩුවාවන් සමඟ ඇති බොහෝ ගැටලු ඉවත් කරයි.
RustyTheBoyRobot

74

ශූන්‍යය 'ගැටලුවක්' නොවේ. එය සම්පූර්ණ ආකෘති නිර්මාණ මෙවලම් කට්ටලයක අනිවාර්ය අංගයකි . මෘදුකාංගය ලෝකයේ සංකීර්ණත්වය ආදර්ශනය කිරීම අරමුණු කර ගෙන එහි බර දරයි. ජාවා සහ ඒ හා සමාන 'දත්ත නැත' හෝ 'නොදන්නා' යන්න ශුන්‍යයෙන් දැක්වේ . එබැවින් මෙම අරමුණු සඳහා ශුන්‍ය භාවිතා කිරීම සුදුසුය. මම 'ශුන්‍ය වස්තුව' රටාවට කැමති නැත; මම හිතන්නේ එය ' භාරකරුවන් ආරක්ෂා කරන්නේ කවුද ' යන ප්‍රශ්නය මතු කරයි.
මගේ පෙම්වතියගේ නම කුමක්දැයි ඔබ මගෙන් ඇසුවොත්, මම ඔබට පෙම්වතියක් නොමැති බව ඔබට කියමි. ජාවා භාෂාවෙන් මම ආපසු එන්නෙමි. විකල්පයක් වනුයේ කිසියම් ගැටලුවක් දැක්වීමට අර්ථවත් ව්‍යතිරේකයක් විසි කිරීමයි (හෝ නොකළ යුතුය

  1. 'නොදන්නා ප්‍රශ්නයක්' සඳහා 'නොදන්නා පිළිතුරක්' දෙන්න.(ව්‍යාපාරික දෘෂ්ටි කෝණයෙන් මෙය නිවැරදි තැනක ශුන්‍යව සිටින්න) භාවිතයට පෙර ක්‍රමවේදයක් තුළ එක් වරක් ශුන්‍යය සඳහා තර්ක පරීක්ෂා කිරීම ඇමතුමකට පෙර බහු ඇමතුම්කරුවන් පරීක්ෂා කිරීමෙන් නිදහස් කරයි.

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }

    මගේ ඡායාරූප පුස්තකාලයෙන් නොපවතින පෙම්වතියකගේ ඡායාරූපයක් ලබා ගැනීමට පෙර සාමාන්‍ය තාර්කික ප්‍රවාහයකට මග පාදයි.

    getPhotoOfThePerson(me.getGirlfriend())

    එය නව ජාවා ඒපීඅයි සමඟ ගැලපේ (බලාපොරොත්තුවෙන්)

    getPhotoByName(me.getGirlfriend()?.getName())

    සමහර පුද්ගලයකු සඳහා ඩීබී තුළ ගබඩා කර ඇති ඡායාරූප සොයා නොගැනීම සාමාන්‍ය ව්‍යාපාර ප්‍රවාහයක් වන අතර, මම වෙනත් අවස්ථා සඳහා පහත වැනි යුගල භාවිතා කළෙමි

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);

    ටයිප් කිරීමට පිළිකුල් නොකරන්න <alt> + <shift> + <j> (සූර්යග්‍රහණයේ javadoc ජනනය කරන්න) සහ ඔබට පොදු API සඳහා අමතර වචන තුනක් ලියන්න. ලියකියවිලි කියවන්නේ නැති අයට හැර අන් සියල්ලන්ටම මෙය ප්‍රමාණවත් වනු ඇත.

    /**
     * @return photo or null
     */

    හෝ

    /**
     * @return photo, never null
     */
  2. මෙය තරමක් න්‍යායාත්මක සිද්ධියක් වන අතර බොහෝ අවස්ථාවන්හිදී ඔබ ජාවා ශුන්‍ය ආරක්ෂිත API වලට වැඩි කැමැත්තක් දැක්විය යුතුය (එය තවත් වසර 10 කින් නිකුත් වේ නම්), නමුත් NullPointerExceptionඑය උප කාණ්ඩයකි Exception. මේ අනුව, එය Throwableසාධාරණ යෙදුමකට ( ජාවඩොක් ) අල්ලා ගැනීමට අවශ්‍ය විය හැකි කොන්දේසි පෙන්නුම් කරයි . ව්‍යතිරේකයන්ගේ පළමු වඩාත්ම වාසිය භාවිතා කිරීම සහ දෝෂ හැසිරවීමේ කේතය 'සාමාන්‍ය' කේතයෙන් වෙන් කිරීම ( ජාවාහි නිර්මාතෘවරුන්ට අනුව ) අල්ලා ගැනීම සුදුසුය NullPointerException.

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }

    ප්‍රශ්න මතු විය හැකිය:

    ප්‍රශ්නය - getPhotoDataSource()නැවත ශුන්‍ය වුවහොත් කුමක් කළ යුතුද?
    පිළිතුර - එය ව්‍යාපාර තර්කනය මත ය. මම ඡායාරූප ඇල්බමයක් සොයා ගැනීමට අපොහොසත් වුවහොත් මම ඔබට ඡායාරූප කිසිවක් පෙන්වන්නේ නැත. AppContext ආරම්භ කර නොමැති නම් කුමක් කළ යුතුද? මෙම ක්‍රමයේ ව්‍යාපාර තර්කනය මේ සමඟ එකඟ වේ. එකම තර්කනය වඩාත් දැඩි විය යුතු නම්, ව්‍යතිරේකයක් විසි කිරීම එය ව්‍යාපාර තර්කනයේ කොටසක් වන අතර ශුන්‍යය සඳහා පැහැදිලි චෙක්පතක් භාවිතා කළ යුතුය (නඩුව 3). එම වඩා හොඳ මෙහි නව ජාවා NULL-ආරක්ෂිත API පණ අදිමින් වුවත් තෝරා දේ ගම්ය දේ ආරම්භනය කිරීමට ගම්ය වන්නේ නැත නියම කිරීමට අසමත් වේගයෙන් කිරීමට ක්රමලේඛකයාට වැරදි සම්බන්ධයෙන්.

    ප්‍රශ්නය - අතිරික්ත කේතය ක්‍රියාත්මක කළ හැකි අතර අනවශ්‍ය සම්පත් උදුරා ගත හැකිය.
    පිළිතුර - getPhotoByName()දත්ත සමුදා සම්බන්ධතාවයක් විවෘත PreparedStatementකිරීමට, පුද්ගලයාගේ නම SQL පරාමිතියක් ලෙස නිර්මාණය කිරීමට සහ භාවිතා කිරීමට උත්සාහ කරන්නේ නම් එය සිදුවිය හැකිය . නොදන්නා ප්‍රශ්නයක් සඳහා ප්‍රවේශය නොදන්නා පිළිතුරක් ලබා දෙයි (නඩුව 1) මෙහි ක්‍රියාත්මක වේ. සම්පත් උදුරා ගැනීමට පෙර ක්‍රමය පරාමිතීන් පරික්ෂා කර අවශ්‍ය නම් 'නොදන්නා' ප්‍රති result ල ලබා දිය යුතුය.

    ප්‍රශ්නය - උත්සාහය වසා දැමීම විවෘත කිරීම හේතුවෙන් මෙම ප්‍රවේශයට කාර්ය සාධන ද penalty ුවමක් ඇත.
    පිළිතුර - මෘදුකාංගය මුලින්ම තේරුම් ගැනීමට සහ වෙනස් කිරීමට පහසු විය යුතුය. මෙයින් පසුව පමණක් කෙනෙකුට කාර්ය සාධනය ගැන සිතිය හැකි අතර අවශ්‍ය නම් පමණි! අවශ්‍ය තැන! ( ප්‍රභවය ) සහ තවත් බොහෝ අය).

    පීඑස්. "නිත්‍ය" කේත මූලධර්මයෙන් වෙනම දෝෂ හැසිරවීමේ කේතය යම් ස්ථානයක භාවිතා කිරීම සාධාරණ බැවින් මෙම ප්‍රවේශය සාධාරණ වනු ඇත . ඊළඟ උදාහරණය සලකා බලන්න:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }

    පීපීඑස්. වේගයෙන් පහත් කොට සලකන අයට (සහ ලියකියවිලි කියවීමට එතරම් වේගවත් නොවේ) මම කියන්න කැමතියි මගේ ජීවිතයේ කිසි විටෙකත් ශුන්‍ය දර්ශක ව්‍යතිරේකයක් (එන්පීඊ) මා අල්ලාගෙන නැත. නමුත් මෙම හැකියාව හිතාමතාම ජාවා නිර්මාණකරුවන් විසින් නිර්මාණය කරන ලද්දේ NPE හි උප පංතියක් වන Exceptionබැවිනි. අපි ජාවා ඉතිහාසයේ පූර්වාදර්ශයක් ඇති වූ විට ThreadDeathයනු Errorඒක ඇත්තටම අයදුම්පතක් දෝෂයක් වේ, නමුත් එය එල්ල කිරීමට අදහස් කරන ලදී නොවේ පමණක් නිසා නිසා නොවේ! NPE Errorට වඩා කොපමණ ප්‍රමාණයක් ගැලපේද ThreadDeath! නමුත් එය එසේ නොවේ.

  3. 'දත්ත නැත' යන්න පරීක්ෂා කරන්න ව්‍යාපාර තර්කනය එයින් ඇඟවෙන්නේ නම් පමණි.

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }

    හා

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }

    AppContext හෝ dataSource ආරම්භ කර නොමැති නම් පාලනය කළ නොහැකි ධාවන කාලය NullPointerException වත්මන් නූල් විනාශ කරන අතර එය Thread.defaultUncaughtExceptionHandler විසින් සකසනු ඇත (ඔබේ ප්‍රියතම ලොගර් හෝ වෙනත් දැනුම්දීම් යාන්ත්‍රණය නිර්වචනය කර භාවිතා කිරීමට). සකසා නොමැති නම්, ThreadGroup # uncaughtException මඟින් පද්ධතියේ දෝෂයට ස්ටැක්ට්‍රේස් මුද්‍රණය වේ. අයදුම්පත් දෝෂ ල log ු-සටහන් අධීක්‍ෂණය කළ යුතු අතර, ජිරා ගැටළුව විවෘත කළ යුතුය. ක්‍රමලේඛකයා ආරම්භක දේවල් වල කොතැනක හෝ දෝෂ නිවැරදි කළ යුතුය.


6
අල්ලා ගැනීම NullPointerExceptionසහ නැවත පැමිණීම නිදොස් nullකිරීම භයානක ය. ඔබ කෙසේ හෝ පසුව NPE සමඟ අවසන් වන අතර, මුලින් ශුන්‍ය වූයේ කුමක් දැයි සොයා ගැනීම දුෂ්කර ය.
artbristol

23
මට කීර්තියක් තිබේ නම් මම පහත් කොට සලකමි. ශුන්‍ය අවශ්‍ය නොවේ පමණක් නොව, එය වර්ග පද්ධතියේ සිදුරකි. ගසක් ලැයිස්තුවකට පැවරීම වර්ග දෝෂයකි, මන්ද ගස් වර්ග ලැයිස්තුවේ අගයන් නොවන බැවිනි; එම තර්කනයෙන්ම, ශුන්‍යය පැවරීම වර්ගයේ දෝෂයක් විය යුතුය, මන්ද ශුන්‍ය වර්ගය වස්තුවක වටිනාකමක් හෝ එම කාරණය සඳහා කිසියම් ප්‍රයෝජනවත් වර්ගයක් නොවේ. ශුන්‍යය සොයාගත් මිනිසා පවා එය ඔහුගේ "ඩොලර් බිලියනයක වැරැද්ද" ලෙස සලකයි. “T වර්ගයේ හෝ කිසිවක් නැති අගයක් විය හැකිය” යන සංකල්පය එයටම ආවේණික වන අතර එය නිරූපණය කළ යුතුය (උදා: සමහර විට <T> හෝ විකල්ප <T>).
Doval

2
"සමහර විට <T> හෝ විකල්ප <T>" අනුව ඔබට තවමත් කේත ලිවිය යුතුය, if (maybeNull.hasValue()) {...}එබැවින් වෙනස if (maybeNull != null)) {...}කුමක්ද?
Mykhaylo Adamovych

1
"NullPointerException අල්ලා ගැනීම සහ ශුන්‍යව නැවත පැමිණීම නිදොස් කිරීම භයානක ය. ඔබ කෙසේ හෝ පසුව NPE සමඟ අවසන් වන අතර මුලින් ශුන්‍ය වූයේ කුමක් දැයි සොයා ගැනීම දුෂ්කර ය". මම සම්පූර්ණයෙන්ම එකඟයි! එවැනි අවස්ථාවන්හිදී ඔබ 'if' ප්‍රකාශ දුසිමක් ලිවිය යුතුය, නැතහොත් ව්‍යාපාර තර්කනය මඟින් දත්ත නිසි පරිදි ක්‍රියාත්මක වන්නේ නම් NPE විසි කළ යුතුය, නැතහොත් නව ජාවා වෙතින් ශුන්‍ය-ආරක්ෂිත ක්‍රියාකරු භාවිතා කළ යුතුය. නමුත් මට නිශ්චිත පියවරක් ලබා නොදෙන අවස්ථා තිබේ. උදාහරණයක් ලෙස දත්ත අස්ථානගත විය හැකි යැයි ඔබ අපේක්ෂා කරන විට තිරය මත පෙන්වීමට පෙර පරිශීලකයා සඳහා සමහර අගයන් ගණනය කිරීම.
මයිඛයිලෝ ඇඩමොවිච්

3
YmykhayloAdamovych: ඔබේ ශුන්‍ය විය හැකි අවස්ථාවක Maybe<T>හෝ නැතිනම් එහි වාසිය , නමුත් එය කිසි විටෙකත් ශුන්‍ය නොවිය යුතුය. ඔබ සතුව “මෙම අගය ශුන්‍ය විය හැකිය - ප්‍රවේශමෙන් භාවිතා කරන්න ” යනුවෙන් පැහැදිලිවම අදහස් කරන වර්ගයක් තිබේ නම්, ඔබ එවැනි වර්ගයක් නිරන්තරයෙන් භාවිතා කර ආපසු එවන්නේ නම්, ඔබේ කේතයේ පැරණි පැරණි දෙයක් ඔබ දකින සෑම විටම එය කිසි විටෙකත් ශුන්‍ය නොවන බව උපකල්පනය කළ හැකිය. ( Optional<T>TT
se මාලාව

71

ජාවා 7 හි නව java.util.Objectsඋපයෝගිතා පන්තියක් ඇති අතර ඒ සඳහා requireNonNull()ක්‍රමවේදයක් ඇත. මේ සියල්ල කරන්නේ NullPointerExceptionඑහි තර්කය ශුන්‍ය නම් එය විසි කිරීම පමණි , නමුත් එය කේතය ටිකක් පිරිසිදු කරයි. උදාහරණයක්:

Objects.requireNonNull(someObject);
someObject.doCalc();

ඉදිකිරීම්කරුවෙකුගේ පැවරුමකට පෙර පරීක්ෂා කිරීම සඳහා මෙම ක්‍රමය වඩාත් ප්‍රයෝජනවත් වේ , එහිදී සෑම භාවිතයක්ම කේත පේළි තුනක් ඉතිරි කර ගත හැකිය:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

බවට පත්වේ

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

9
ඇත්ත වශයෙන්ම, ඔබේ උදාහරණය කේත පිපිරීමක් වේ: පළමු පේළිය අනවශ්‍ය බැවින් NPE දෙවන පේළියට විසි කරනු ඇත. ;-)
user1050755

1
සැබෑ. ඊට වඩා හොඳ උදාහරණයක් වනුයේ දෙවන පේළිය නම් doCalc(someObject).
ස්ටුවර්ට් මාර්ක්ස්

රඳා පවතී. ඔබ doCalc () හි කතුවරයා නම්, චෙක්පත එම ක්‍රමයේ ශරීරයට ඇතුළත් කිරීමට මම යෝජනා කරමි (හැකි නම්). එවිට ඔබ බොහෝ විට කිසියම් ඕබෙක්ට්.සෝම්මෙතඩ් () අමතනු ඇත, එහිදී නැවත ශුන්‍යය පරීක්ෂා කිරීමට අවශ්‍ය නොවේ. :-)
user1050755

හොඳයි, ඔබ කර්තෘ නොවේ නම් doCalc()සහ එය ශුන්‍ය වූ විට එය වහාම NPE විසි නොකරන්නේ නම්, ඔබට ශුන්‍යදැයි පරීක්ෂා කර NPE ඔබම විසි කළ යුතුය. ඒ Objects.requireNonNull()සඳහා ය.
ස්ටුවර්ට් මාර්ක්ස්

7
එය හුදෙක් කේත පිපිරීමක් නොවේ. අතුරු ආබාධ ඇති කරන හෝ කාලය / අවකාශය භාවිතා කරන ක්‍රමයක් හරහා අඩකට වඩා ඉදිරියෙන් පරීක්ෂා කිරීම වඩා හොඳය.
රොබ් ග්‍රාන්ට්

51

අවසානයේදී, මෙම ගැටළුව මුළුමනින්ම විසඳීමට ඇති එකම ක්‍රමය වෙනස් ක්‍රමලේඛන භාෂාවක් භාවිතා කිරීමයි:

  • පරමාර්ථ-සී හි, ඔබට ක්‍රමවේදයක් ක්‍රියාත්මක කිරීමට සමාන දෙයක් කළ හැකි අතර nil, කිසිවක් සිදු නොවනු ඇත. මෙය බොහෝ ශූන්‍ය චෙක්පත් අනවශ්‍ය කරයි, නමුත් එය දෝෂ හඳුනා ගැනීමට අපහසු වේ.
  • දී සතුටක් විය හැකි-ශූන්ය අනුවාදය සහ නො-ශූන්ය අනුවාදය:, ජාවා-ව්යුත්පන්න භාෂාව, සියලු වර්ගයේ අනුවාද දෙකක් ඇත. ඔබට ආයාචනා කළ හැක්කේ ශුන්‍ය නොවන වර්ග මත පමණි. ශුන්‍යය සඳහා පැහැදිලි පරීක්ෂාවකින් විභව-ශුන්‍ය වර්ග ශුන්‍ය නොවන වර්ග බවට පරිවර්තනය කළ හැකිය. ශුන්‍ය චෙක්පත් අවශ්‍ය වන්නේ කොතැනද සහ ඒවා නොමැති තැන දැන ගැනීම මෙමඟින් පහසු කරයි.

වෝ ... වඩාත්ම නිවැරදි පිළිතුර සහ එය පහත් කොට සලකනු ලැබේ, යුක්තිය කොහේද? ජාවා ශුන්‍යය සැමවිටම වලංගු අගයකි. එය සෑම දෙයකම සහසම්බන්ධය වස්තුවකි - ශුන්‍යය යනු සෑම දෙයක්ම (ඇත්ත වශයෙන්ම අපි මෙහි ප්‍රාථමිකයන් නොසලකා හරින නමුත් ඔබට අදහස ලැබෙනු ඇත). පුද්ගලිකව මම නයිස් විසින් ගනු ලැබූ ප්‍රවේශයට කැමැත්තක් දක්වන්නෙමි, නමුත් අපට එය කළ හැකි වන අතර එමඟින් ක්‍රමෝපායන් අහෝසි කළ හැකි වර්ග සඳහා යොදා ගත හැකි අතර පරික්‍ෂා කළ ව්‍යතිරේකයන් සඳහා NPEs ප්‍රවර්ධනය කළ හැකිය. දැනට පවතින සියලුම කේතයන් බිඳ දැමිය හැකි බැවින් මෙය සම්පාදක ස්විචයක් හරහා සිදු කළ යුතුය :(
CurtainDog

4
මට නයිස් ගැන හුරුපුරුදු නැත, නමුත් කෝට්ලින් එකම අදහස ක්‍රියාත්මක කරයි, භාෂාවේ වර්ග පද්ධතියට ශුන්‍ය හා ශුන්‍ය නොවන ආකාරයන් ඇත. විකල්ප හෝ ශුන්‍ය වස්තු රටාවට වඩා බොහෝ සංක්ෂිප්ත ය.
mtsahakis

38

ජාවාහි පොදු "ගැටලුව" ඇත්ත වශයෙන්ම.

පළමුව, මේ පිළිබඳ මගේ සිතුවිලි:

NULL වලංගු වටිනාකමක් නොමැති තැන NULL සම්මත වූ විට යමක් "අනුභව කිරීම" නරක යැයි මම සලකමි. ඔබ යම් ආකාරයක දෝෂයකින් ක්‍රමයෙන් ඉවත් නොවන්නේ නම් එයින් අදහස් වන්නේ ඔබේ ක්‍රමයේ කිසිවක් වැරදී නැති බවත් එය සත්‍ය නොවන බවත්ය. එවිට ඔබ බොහෝ විට මෙම අවස්ථාවෙහිදී ශුන්‍යව ආපසු එනු ඇති අතර, ලැබීමේ ක්‍රමයේදී ඔබ නැවත ශුන්‍යය සඳහා පරීක්ෂා කර බැලූ විට එය කිසි විටෙකත් අවසන් නොවන අතර ඔබ අවසන් වන්නේ "if! = Null" යනාදියෙනි.

එබැවින්, IMHO, null යනු තවදුරටත් ක්‍රියාත්මක කිරීම වළක්වන තීරණාත්මක දෝෂයක් විය යුතුය (එනම්, ශුන්‍යය වලංගු අගයක් නොවන තැන).

මම මෙම ගැටළුව විසඳන ආකාරය මෙයයි:

පළමුව, මම මෙම සම්මුතිය අනුගමනය කරමි:

  1. සියලුම පොදු ක්‍රම / ඒපීඅයි සෑම විටම එහි තර්ක ශුන්‍ය සඳහා පරික්ෂා කරයි
  2. පාලිත ක්‍රම වන බැවින් සියලුම පුද්ගලික ක්‍රම ශුන්‍යය සඳහා පරික්ෂා නොකරයි (එය ඉහත හසුරුවනු නොලැබුවහොත් ශුන්‍ය ලක්ෂ්‍ය ව්‍යතිරේකය සමඟ මිය යාමට ඉඩ දෙන්න)
  3. ශුන්‍යය පරික්ෂා නොකරන අනෙක් ක්‍රම වන්නේ උපයෝගිතා ක්‍රම වේ. ඒවා පොදු ය, නමුත් ඔබ යම් හේතුවක් නිසා ඔවුන් අමතන්නේ නම්, ඔබ සම්මත කරන පරාමිතීන් මොනවාදැයි ඔබ දන්නවා. මෙය හරියට ජලය ලබා නොදී කේතලයේ ජලය තම්බා ගැනීමට උත්සාහ කිරීමක් වැනිය ...

අවසාන වශයෙන්, කේතයේ දී, පොදු ක්‍රමයේ පළමු පේළිය මේ ආකාරයට යයි:

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

AddParam () ස්වයංක්‍රීයව නැවත පැමිණෙන බව සලකන්න, එවිට ඔබට පරීක්ෂා කිරීමට තවත් පරාමිතීන් එකතු කළ හැකිය.

කිසියම් පරාමිතියක් ශුන්‍ය නම් ක්‍රමය validate()පරීක්ෂා කරනු ValidationExceptionලැබේ (පරීක්ෂා කර හෝ පරීක්ෂා නොකිරීම වඩා නිර්මාණ / රස ගැටළුවක් වේ, නමුත් මගේ ValidationExceptionපරික්ෂා කර ඇත).

void validate() throws ValidationException;

උදාහරණයක් ලෙස "සැලසුම්" අහෝසි නම් පණිවිඩයේ පහත සඳහන් පෙළ අඩංගු වේ:

" නීති විරෝධී තර්කය අගය NULL පරාමිතිය සඳහා මුහුණ වේ [සැලසුම්] "

ඔබට පෙනෙන පරිදි, පරිශීලක පණිවිඩය සඳහා addParam () ක්‍රමයේ (නූල්) දෙවන අගය අවශ්‍ය වේ, මන්ද යත් පරාවර්තනය සහිතව වුවද සම්මත සම්මත විචල්‍ය නාමයක් ඔබට පහසුවෙන් හඳුනාගත නොහැකි බැවිනි (කෙසේ වෙතත් මෙම තනතුරට යටත් නොවේ ...).

ඔව්, මෙම රේඛාවෙන් ඔබ්බට අපට තවදුරටත් ශුන්‍ය අගයක් හමු නොවන බව අපි දනිමු. එබැවින් අපි එම වස්තූන් සඳහා ආරක්ෂිතව ක්‍රමවේදයන් ඉල්ලා සිටිමු.

මේ ආකාරයෙන්, කේතය පිරිසිදු, පහසුවෙන් නඩත්තු කළ හැකි සහ කියවිය හැකි ය.


3
නියත වශයෙන්ම. දෝෂ සහ බිඳවැටීම් විසි කරන යෙදුම් උසස් තත්ත්වයේ ඒවා ක්‍රියාත්මක නොවන විට සැකයක් නැත. දෝෂ අවම වශයෙන් ගිල ගන්නා යෙදුම් මනාව පිරිහී ඇති නමුත් සාමාන්‍යයෙන් ඒවා හඳුනා ගැනීමට අපහසු සහ නිවැරදි නොවන ආකාරයෙන් ක්‍රියා නොකරයි. ගැටලුව දුටු විට ඒවා නිදොස්කරණය කිරීමට වඩා අපහසු වේ.
පෝල් ජැක්සන්

35

එම ප්‍රශ්නය ඇසීමෙන් පෙන්නුම් කරන්නේ ඔබ දෝෂ හැසිරවීමේ උපාය මාර්ග කෙරෙහි උනන්දුවක් දක්වන බවයි. ඔබගේ කණ්ඩායමේ ගෘහ නිර්මාණ ශිල්පියා විසින් වැරදි ක්‍රියා කරන්නේ කෙසේදැයි තීරණය කළ යුතුය. මෙය කිරීමට ක්‍රම කිහිපයක් තිබේ:

  1. ව්‍යතිරේකයන්ට ඉරිතැලීමට ඉඩ දෙන්න - ඒවා 'ප්‍රධාන පුඩුවේ' හෝ වෙනත් කළමනාකරණ පුරුද්දකදී අල්ලා ගන්න.

    • දෝෂ තත්වයන් පරීක්ෂා කර ඒවා නිසි ලෙස හසුරුවන්න

ඇස්පෙක්ට් ඔරියන්ටඩ් ක්‍රමලේඛනය දෙසද බලන්න - if( o == null ) handleNull()ඔබේ බයිට් කේතයට ඇතුළු කිරීමට ඔවුන්ට ක්‍රම තිබේ .


35

භාවිතා කිරීමට අමතරව assertඔබට පහත සඳහන් දෑ භාවිතා කළ හැකිය:

if (someobject == null) {
    // Handle null here then move on.
}

මෙය මීට වඩා තරමක් හොඳයි:

if (someobject != null) {
    .....
    .....



    .....
}

2
ම්, ඇයි ඒ? කරුණාකර කිසිදු ආරක්ෂාවක් දැනෙන්නේ නැත, මම ජාවා ගැන වැඩිදුර දැන ගැනීමට කැමතියි :)
මතියස් මීඩ්

9
Ud මුදු සාමාන්‍ය රීතියක් ලෙස, if ප්‍රකාශයේ ප්‍රකාශනය “negative ණ” ප්‍රකාශයකට වඩා “ධනාත්මක” ප්‍රකාශයක් වීමට මම කැමැත්තෙමි. එබැවින් මා if (!something) { x(); } else { y(); }දුටුවහොත් එය ප්‍රතිචක්‍රීකරණය කිරීමට මා පෙළඹෙනු ඇත if (something) { y(); } else { x(); }(යමෙකුට != nullඑය වඩාත් ධනාත්මක විකල්පය යැයි තර්ක කළ හැකි වුවද ...). නමුත් වඩා වැදගත් දෙය නම්, කේතයේ වැදගත් කොටස {}s තුළට ඔතා නොමැති අතර බොහෝ ක්‍රම සඳහා ඔබට එක් මට්ටමක අඩු ඉන්ඩෙන්ටේෂන් එකක් ඇත. එය වේගවත් කේතවාදයේ තර්කයක් දැයි මම නොදනිමි, නමුත් එය මගේ ය.
MatrixFrog

1
මමත් එසේ කිරීමට නැඹුරු වන්නේ මෙයයි .. මගේ මතය අනුව කේතය පිරිසිදුව තබා ගනී.
කෝරේ ටුගෙයි

34

කිසි විටෙකත් ශුන්‍ය භාවිතා නොකරන්න. එයට ඉඩ නොදෙන්න.

මගේ පංති වලදී, බොහෝ ක්ෂේත්‍ර සහ දේශීය විචල්‍යයන් ශුන්‍ය නොවන පෙරනිමි අගයන් ඇති අතර, මෙය බලාත්මක වන බවට වග බලා ගැනීම සඳහා මම කේතයේ සෑම තැනකම කොන්ත්‍රාත් ප්‍රකාශ (සෑම විටම ප්‍රකාශ කරමි) එකතු කරමි (එය වඩාත් සංක්ෂිප්ත හා එයට ඉඩ දෙනවාට වඩා ප්‍රකාශිත බැවින් NPE ලෙස පැමිණ පසුව පේළි අංකය නිරාකරණය කිරීම ආදිය).

මම මෙම පුරුද්ද අනුගමනය කළ පසු, ගැටලු විසඳා ඇති බව මම දුටුවෙමි. සංවර්ධන ක්‍රියාවලියේදී ඔබ බොහෝ කලකට පෙර අහම්බෙන් දේවල් අල්ලාගෙන ඔබට දුර්වල ස්ථානයක් ඇති බව වටහා ගනී .. සහ වඩා වැදගත් ලෙස .. එය විවිධ මොඩියුලයන්ගේ උත්සුකයන් වටහා ගැනීමට උපකාරී වේ, විවිධ මොඩියුලයන් එකිනෙකා 'විශ්වාස කළ හැකිය', සහ තවදුරටත් පැටව් ගසන්නේ නැත if = null elseඉදිකිරීම් සමඟ කේතය !

මෙය ආරක්ෂක ක්‍රමලේඛනය වන අතර දිගු කාලීනව වඩා පිරිසිදු කේතයක් ඇති කරයි. සෑම විටම දත්ත සනීපාරක්ෂාව කරන්න, උදා: දෘඩ ප්‍රමිතීන් බලාත්මක කිරීමෙන් මෙහි ගැටළු පහව යයි.

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

කොන්ත්‍රාත්තු යනු සෑම විටම ක්‍රියාත්මක වන, නිෂ්පාදනයේදී පවා ක්‍රියාත්මක වන කුඩා ඒකක පරීක්ෂණ හා සමාන වන අතර, දේවල් අසාර්ථක වූ විට, අහඹු NPE එකකට වඩා ඔබට කෙසේ හෝ හඳුනාගත යුත්තේ මන්දැයි ඔබ දන්නවා.


මෙය පහත් කොට සලකන්නේ ඇයි? මගේ අත්දැකීම් අනුව, මෙය අනෙක් ප්‍රවේශයන්ට වඩා බෙහෙවින් උසස් ය, එසේ නොවන්නේ මන්දැයි දැන ගැනීමට කැමතියි
ianpojman

මම එකඟ වෙමි, මෙම ප්‍රවේශය සෑම තැනකම කේත ශුන්‍ය චෙක්පත් මගින් නිරාකරණය කරනවාට වඩා ශුන්‍ය සම්බන්ධ ගැටළු වළක්වයි.
ක්‍රිස්බ්ලොම්

7
මෙම ප්‍රවේශයේ ඇති ගැටළුව නම්, නම කිසි විටෙකත් සකසා නොමැති නම්, එයට "<unknown>" අගය ඇති අතර එය නියම අගයක් ලෙස ක්‍රියා කරයි. දැන් අපි කියමු, නම කිසි විටෙකත් සකසා නොමැතිදැයි පරීක්ෂා කිරීමට (නොදන්නා), "<unknown>" විශේෂ අගයට සාපේක්ෂව මට නූල් සංසන්දනයක් කළ යුතුය.
ස්ටීව් කුඕ

1
ඇත්ත හොඳ කරුණක් ස්ටීව්. මම බොහෝ විට කරන්නේ එම අගය නියතයක් ලෙස තිබීමයි, උදා: පොදු ස්ථිතික අවසාන නූල UNSET = "__ setet" ... private string field = UNSET ... ඉන්පසු පුද්ගලික බූලියන් isSet () {ආපසු UNSET.equals (field); }
ianpojman

IMHO, මෙය ඔබ විසින්ම විකල්ප (කොන්ත්‍රාත්තුව) ක්‍රියාත්මක කිරීමත් සමඟ ශුන්‍ය වස්තු රටාව ක්‍රියාත්මක කිරීමකි. අඛණ්ඩ පන්ති පන්තිය මත එය හැසිරෙන්නේ කෙසේද? එම අවස්ථාවේ දී මට අදාළ නොවන බව පෙනේ.
කුරපිකා

31

ගූගල් හි ඉතා ප්‍රයෝජනවත් මූලික පුස්තකාලයක් වන ගුවා, ශුන්‍යයන් වළක්වා ගැනීම සඳහා හොඳ සහ ප්‍රයෝජනවත් API එකක් ඇත. UseAndAvoidingNullExplained ඉතා ප්‍රයෝජනවත් බව මට පෙනේ .

විකියේ විස්තර කර ඇති පරිදි:

Optional<T>යනු ශුන්‍ය නොවන ටී යොමුව ශුන්‍ය නොවන අගයක් සමඟ ප්‍රතිස්ථාපනය කිරීමේ ක්‍රමයකි. විකල්පයක් තුළ ශුන්‍ය නොවන ටී යොමු කිරීමක් අඩංගු විය හැකිය (එම අවස්ථාවේදී අපි යොමු කිරීම "පවතින" යැයි කියමු), හෝ එහි කිසිවක් අඩංගු නොවිය හැකිය (එවැනි අවස්ථාවකදී අපි "නොපැමිණීම" යැයි කියමු). එය කිසි විටෙකත් "ශුන්‍යය අඩංගු" යැයි නොකියයි.

භාවිතය:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

Ody කෝඩි ගුල්ඩ්නර් රයිට්, කෝඩි. වැඩි සන්දර්භයක් ලබා දීම සඳහා මම සබැඳියෙන් අදාළ උපුටා දැක්වීමක් ලබා දුන්නෙමි.
මුරාත් ඩෙරියා

25

සෑම ජාවා සංවර්ධකයෙකුටම මෙය ඉතා පොදු ගැටළුවකි. එබැවින් අවුල් සහගත කේතයකින් තොරව මෙම ගැටළු විසඳීම සඳහා ජාවා 8 හි නිල සහාය ඇත.

ජාවා 8 හඳුන්වා දී java.util.Optional<T>ඇත. එය ශුන්‍ය නොවන අගයක් හෝ නොතිබිය හැකි බහාලුමකි. සමහර අවස්ථාවන්හි වටිනාකම අහෝසි විය හැකි වස්තුවක් හැසිරවීමට ජාවා 8 ආරක්ෂිත ක්‍රමයක් ලබා දී ඇත. එය දේවානුභාවයෙන් හස්කල් සහ ස්කාලාගේ අදහස් වලින් .

කෙටියෙන් කිවහොත්, විකල්ප පන්තියට වටිනාකමක් ඇති හෝ නොමැති අවස්ථාවන්හි පැහැදිලිව කටයුතු කිරීමේ ක්‍රම ඇතුළත් වේ. කෙසේ වෙතත්, ශුන්‍ය යොමු කිරීම් හා සසඳන විට ඇති වාසිය නම්, විකල්ප <T> පන්තිය මඟින් අගය නොමැති විට නඩුව ගැන සිතා බැලීමට බල කරයි. ප්‍රති consequ ලයක් ලෙස, ඔබට අනපේක්ෂිත ශුන්‍ය දර්ශක ව්‍යතිරේකයන් වළක්වා ගත හැකිය.

ඉහත උදාහරණයේ දී අප සතුව ගෘහ සේවා කර්මාන්ත ශාලාවක් ඇති අතර එය නිවසේ ඇති විවිධ උපකරණ සඳහා හසුරුව නැවත ලබා දෙයි. නමුත් මෙම සේවාවන් ලබා ගත හැකිය / නොතිබිය හැකිය; එයින් අදහස් වන්නේ එය NullPointerException වලට හේතු විය හැකි බවයි. ifකිසියම් සේවාවක් භාවිතා කිරීමට පෙර ශුන්‍ය කොන්දේසියක් එකතු කරනවා වෙනුවට , එය විකල්ප <සේවා> වෙත ඔතා ගනිමු.

විකල්පයට ඔතා <T>

කර්මාන්ත ශාලාවකින් සේවාවක් පිළිබඳ සඳහනක් ලබා ගැනීමේ ක්‍රමයක් සලකා බලමු. සේවා යොමු කිරීම වෙනුවට, එය විකල්ප සමඟ ඔතා. ආපසු ලබා දුන් සේවාව ලබා ගත නොහැකි / ක්‍රියාකාරී නොවිය හැකි බව ආරක්ෂිතව භාවිතා කිරීමට API පරිශීලකයාට එය ඉඩ දෙයි

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

ඔබ දකින Optional.ofNullable()පරිදි යොමු කිරීම ඔතා ගැනීමට පහසු ක්‍රමයක් සපයයි. විකල්ප සමුද්දේශ ලබා ගැනීමට තවත් ක්රම තිබෙනවා, එක්කෝ Optional.empty()සහOptional.of() . එකක් හිස් වස්තුවක් නැවත ලබා ගැනීම වෙනුවට නැවත ලබා දීම සඳහා වන අතර අනෙක පිළිවෙලින් ශුන්‍ය නොවන වස්තුවක් එතීම සඳහා ය.

එසේ නම්, සම්පූර්ණ පරීක්‍ෂණයකින් වැළකී සිටීමට එය හරියටම උපකාර කරන්නේ කෙසේද?

ඔබ විමර්ශන වස්තුවක් ඔතා ගත් පසු, එන්පීඊ නොමැතිව ඔතා ඇති යොමුවකට ක්‍රම කැඳවීමට විකල්ප බොහෝ ප්‍රයෝජනවත් ක්‍රම සපයයි.

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresent විසින් ලබා දී ඇති පාරිභෝගිකයාට එය ශුන්‍ය නොවන අගයක් නම් යොමු කිරීමක් ඉල්ලා සිටී. එසේ නොමැති නම්, එය කිසිවක් නොකරයි.

@FunctionalInterface
public interface Consumer<T>

තනි ආදාන තර්කයක් පිළිගෙන කිසිදු ප්‍රති .ලයක් ලබා නොදෙන මෙහෙයුමක් නියෝජනය කරයි. අනෙකුත් බොහෝ ක්‍රියාකාරී අතුරුමුහුණත් මෙන් නොව, පාරිභෝගිකයා අතුරු ආබාධ හරහා ක්‍රියාත්මක වනු ඇතැයි අපේක්ෂා කෙරේ. එය එතරම් පිරිසිදු හා තේරුම් ගැනීමට පහසුය. ඉහත කේත උදාහරණයේ,HomeService.switchOn(Service) විකල්ප රඳවා ගැනීමේ යොමුව ශුන්‍ය නොවේ නම් ආයාචනා කරනු ලැබේ.

ශුන්‍ය තත්වය පරීක්ෂා කිරීම සඳහා අපි බොහෝ විට ත්‍රිමාණ ක්‍රියාකරු භාවිතා කර විකල්ප අගයක් හෝ පෙරනිමි අගයක් ලබා දෙන්නෙමු. විකල්පය ශුන්‍යය පරික්ෂා නොකර එකම තත්වයක් හැසිරවීමට තවත් ක්‍රමයක් සපයයි. විකල්පය ශුන්‍ය අගයක් ඇත්නම් Optional.orElse (defaultObj) defaultObj ලබා දෙයි. මෙය අපගේ නියැදි කේතයේ භාවිතා කරමු:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

දැන් HomeServices.get () එකම දේ කරයි, නමුත් වඩා හොඳ ආකාරයකින්. සේවාව දැනටමත් ආරම්භ කර නොමැතිදැයි එය පරීක්ෂා කරයි. එය එසේ නම් එය නැවත ලබා දෙන්න හෝ නව නව සේවාවක් සාදන්න. විකල්ප <T>. හෝ පෙරනිමි අගයක් ලබා දීමට වෙනත් (ටී) උපකාරී වේ.

අවසාන වශයෙන්, මෙන්න අපගේ NPE මෙන්ම ශුන්‍ය චෙක්-රහිත කේතය:

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

සම්පූර්ණ තනතුර NPE මෙන්ම ශුන්‍ය චෙක්-රහිත කේතය… ඇත්තද? .


ඉහත කේතයේ ශුන්‍ය චෙක්පතක් ඇත - if(homeServices != null) {එය වෙනස් කළ හැකිය homeServices.ifPresent(h -> //action);
ක්‍රිෂ්ප්‍රකකර්

23

මම නැට් ප්‍රයිස්ගේ ලිපි වලට කැමතියි. මෙන්න සබැඳි:

ලිපි වල ජාවා සමහර විට ටයිප් කිරීම සඳහා Git නිධියකට සබැඳියක් ද ඇත, එය මට සිත්ගන්නා සුළුය, නමුත් එය පමණක් පරීක්ෂා කිරීමේ කේත පිපිරීම අඩු කළ හැකි යැයි මම නොසිතමි. අන්තර්ජාලයේ යම් පර්යේෂණයක් කිරීමෙන් පසුව, මම සිතන්නේ ! = ශුන්‍ය කේත පිපිරීම ප්‍රධාන වශයෙන් ප්‍රවේශමෙන් සැලසුම් කිරීමෙන් අඩු කළ හැකිය.


ඔබ සඳහන් කළ ආකාරයට ප්‍රවේශයන් ගැන මයිකල් ෆෙදර්ස්
ivan.aguirre

21

මම උත්සාහ කර ඇති NullObjectPatternනමුත් මට සෑම විටම යන්න හොඳම ක්‍රමය නොවේ. සමහර විට "ක්‍රියාවක් නැත" යන්න සුදුසු නොවේ.

NullPointerExceptionයනු ධාවන හැර යනු එය සංවර්ධකයින් වරද හා ප්රමාණවත් අත්දැකීම් සමග එය ඔබ පවසනවා හරියටම දෝෂය බව.

දැන් පිළිතුරට:

ඔබගේ සියලු ගුණාංග සහ එහි ප්‍රවේශයන් හැකි තරම් පුද්ගලික කිරීමට උත්සාහ කරන්න හෝ ඒවා සේවාදායකයින්ට නිරාවරණය කිරීමෙන් වළකින්න. ඔබට ඇත්ත වශයෙන්ම ඉදිකිරීම්කරු තුළ තර්ක අගයන් තිබිය හැකිය, නමුත් විෂය පථය අඩු කිරීමෙන් ඔබ සේවාදායක පන්තියට අවලංගු අගයක් පසු කිරීමට ඉඩ නොදේ. ඔබට අගයන් වෙනස් කිරීමට අවශ්‍ය නම්, ඔබට සැමවිටම නව එකක් නිර්මාණය කළ හැකිය object. ඔබ ඉදිකිරීම්කරුගේ අගයන් පමණක් පරීක්ෂා කරන්න එක් වරක් කරන අතර ඉතිරි ක්‍රම වලදී අගයන් ශුන්‍ය නොවන බවට ඔබට සහතික විය හැකිය.

ඇත්ත වශයෙන්ම, මෙම යෝජනාව තේරුම් ගැනීමට සහ අදාළ කර ගැනීමට වඩා හොඳ ක්‍රමය අත්දැකීම් වේ.

බයිට්!


19

ජාවා 8 හෝ නව සඳහා හොඳම විකල්පය වන්නේ Optionalපන්තිය භාවිතා කිරීමයි .

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

විය හැකි ශුන්‍ය අගයන් සහිත දිගු දාම සඳහා මෙය විශේෂයෙන් පහසුය. උදාහරණයක්:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

ව්‍යතිරේකය ශුන්‍යයට විසි කරන්නේ කෙසේද යන්න පිළිබඳ උදාහරණය:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

ජාවා 7 හඳුන්වා දුන්නේය Objects.requireNonNull අහෝසි නොවන දෙයක් සඳහා යමක් පරික්ෂා කළ යුතු විට එය ප්‍රයෝජනවත් වේ. උදාහරණයක්:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

17

මම ඊට වඩා පොදුවේ පිළිතුරු දෙන්නම්!

අපි සාමාන්‍යයෙන් මෙම ගැටලුවට මුහුණ දෙන්නේ ක්‍රමවේදයන් අප බලාපොරොත්තු නොවූ ආකාරයෙන් පරාමිතීන් ලබා ගත් විටය (නරක ක්‍රම ඇමතුම ක්‍රමලේඛකයාගේ වරදකි). උදාහරණයක් ලෙස: ඔබ වස්තුවක් ලබා ගැනීමට අපේක්ෂා කරයි, ඒ වෙනුවට ඔබට ශුන්‍යයක් ලැබේ. ඔබ අවම වශයෙන් එක් අක්ෂරයක් සහිත නූලක් ලබා ගැනීමට අපේක්ෂා කරයි, ඒ වෙනුවට ඔබට හිස් නූලක් ලැබේ ...

එබැවින් අතර වෙනසක් නැත:

if(object == null){
   //you called my method badly!

}

හෝ

if(str.length() == 0){
   //you called my method badly again!
}

ඔවුන් දෙදෙනාම අපට වෙනත් කාර්යයන් කිරීමට පෙර වලංගු පරාමිතීන් ලැබී ඇති බවට සහතික කර ගැනීමට අවශ්‍යය.

වෙනත් පිළිතුරු වල සඳහන් කර ඇති පරිදි, ඉහත ගැටළු වළක්වා ගැනීම සඳහා ඔබට කොන්ත්‍රාත් රටාව අනුව සැලසුම අනුගමනය කළ හැකිය . කරුණාකර http://en.wikipedia.org/wiki/Design_by_contract බලන්න .

ජාවා මෙම රටාව ක්රියාත්මක කිරීම සඳහා, ඔබ වැනි මූලික ජාවා විවරණයන් ඉදිරිපත් භාවිතා කළ හැකිය javax.annotation.NotNull හෝ වැනි භාවිතය වඩාත් සූක්ෂම පුස්තකාල හයිබනේට් Validator .

නියැදියක් පමණි:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

ආදාන පරාමිතීන් පරික්ෂා කිරීමකින් තොරව දැන් ඔබට ඔබේ ක්‍රමයේ මූලික ක්‍රියාකාරිත්වය ආරක්ෂිතව සංවර්ධනය කළ හැකිය, ඔවුන් ඔබේ ක්‍රම අනපේක්ෂිත පරාමිතීන්ගෙන් ආරක්ෂා කරයි.

ඔබට තවත් පියවරක් ඉදිරියට ගොස් ඔබගේ යෙදුම තුළ වලංගු පූජෝ පමණක් සෑදිය හැකි බවට වග බලා ගන්න. (ශිශිර වලංගු කිරීමේ වෙබ් අඩවියෙන් සාම්පලය)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

javaxඅර්ථ දැක්වීම අනුව, විසින්, වන නොවේ "කේන්ද්රීය ජාවා".
ටොමාස්

17

සෑම තත්වයකදීම ශුන්‍ය වස්තු භාවිතා කිරීමට යෝජනා කරන පිළිතුරු මම නොසලකා හරිමි. මෙම රටාව මඟින් කොන්ත්රාත්තුව බිඳ දැමිය හැකි අතර ඒවා විසඳීම වෙනුවට ගැඹුරින් හා ගැඹුරින් වළලනු ඇත, නුසුදුසු ලෙස භාවිතා කිරීම ගැන සඳහන් නොකිරීම අනාගත නඩත්තුව අවශ්ය වන බොයිලර් ප්ලේට් කේතයේ තවත් ගොඩවල් නිර්මාණය කරයි.

යථාර්ථය නම්, කිසියම් ක්‍රමයකින් ආපසු ලබා දුන් දෙයක් අහෝසි කළ හැකි නම් සහ ඇමතුම් කේතය ඒ පිළිබඳව තීරණයක් ගත යුතු නම්, කලින් ඇමතුමක් තිබිය යුතුය.

මතක තබා ගන්න, එම ශුන්‍ය වස්තු රටාව සැලකිලිමත් නොවී භාවිතා කරන්නේ නම් මතකයේ බඩගිනි වනු ඇත. මේ සඳහා - NullObject හි උදාහරණය අයිතිකරුවන් අතර බෙදා ගත යුතු අතර, මේ සෑම එකක් සඳහාම අද්විතීය අවස්ථාවක් නොවිය යුතුය.

ගණිතමය ආයතන වැනි, පරිමාණයන් නොවන ප්‍රාථමික වර්ග නිරූපණයක් ලෙස මෙම රටාව භාවිතා කිරීමට මම නිර්දේශ නොකරමි: දෛශික, න්‍යාස, සංකීර්ණ සංඛ්‍යා සහ රාජ්‍ය රඳවා තබා ගැනීමට අදහස් කරන POD (සරල පැරණි දත්ත) වස්තු. ජාවා සාදන ලද වර්ගවල. අවසාන අවස්ථාවේ දී ඔබ අත්තනෝමතික ප්‍රති .ල සමඟ ඇමතුම් ලබා ගැනීමේ ක්‍රමවේදයන් අවසන් කරනු ඇත. උදාහරණයක් ලෙස NullPerson.getName () ක්‍රමයක් නැවත පැමිණිය යුත්තේ කුමක් ද?

විකාර ප්‍රති .ල වළක්වා ගැනීම සඳහා එවැනි අවස්ථා සලකා බැලීම වටී.


"HasBackground ()" සමඟ ඇති විසඳුමට එක් අඩුපාඩුවක් ඇත - එය නූල් ආරක්ෂිත නොවේ. ඔබට එකක් වෙනුවට ක්‍රම දෙකක් ඇමතීමට අවශ්‍ය නම්, ඔබ බහු-නූල් පරිසරයේ සම්පූර්ණ අනුක්‍රමය සමමුහුර්ත කළ යුතුය.
pkalinow

kpkalinow ඔබ විසින් ව්‍යපෘතිගත උදාහරණයක් ඉදිරිපත් කළේ මෙම විසඳුමේ අඩුපාඩුවක් ඇති බව පෙන්වා දීමට පමණි. කේතය බහු තෙරපුම් යෙදුමක ධාවනය කිරීමට අදහස් නොකරන්නේ නම් අඩුපාඩුවක් නොමැත. නූල් ආරක්ෂිත නොවන ඔබේ කේතයෙන් 90% ක් මට ඔබ වෙත ඉදිරිපත් කළ හැකිය. කේතයේ මෙම අංගය ගැන අපි මෙහි කතා නොකරමු, අපි කතා කරන්නේ මෝස්තර රටාව ගැන ය. බහු තෙරපුම යනු තනිවම මාතෘකාවකි.
luke1985

ඇත්ත වශයෙන්ම තනි නූල් යෙදුමක එය ගැටළුවක් නොවේ. මම එම අදහස ලබා දී ඇත්තේ සමහර විට එය ගැටලුවක් වන බැවිනි.
pkalinow

kpkalinow ඔබ මෙම මාතෘකාව සමීපව අධ්‍යයනය කළහොත්, ශුන්‍ය වස්තු සැලසුම් රටාව මඟින් බහු තෙරපුම් ගැටලු විසඳන්නේ නැති බව ඔබට වැටහෙනු ඇත. එබැවින් එය අදාල නොවේ. ඇත්තම කිව්වොත්, මෙම රටාව මනාව ගැලපෙන ස්ථාන මම සොයාගෙන ඇත, එබැවින් මගේ මුල් පිළිතුර ටිකක් වැරදියි, ඇත්ත වශයෙන්ම.
luke1985

16
  1. විචල්‍යයන් කිසි විටෙකත් ශුන්‍ය කිරීමට ආරම්භ නොකරන්න.
  2. (1) නොහැකි නම්, සියලු එකතු කිරීම් සහ අරා හිස් එකතු කිරීම් / අරා වෙත ආරම්භ කරන්න.

මෙය ඔබේම කේතයකින් කිරීමෙන් ඔබට වළක්වා ගත හැකිය! = ශූන්‍ය චෙක්පත්.

බොහෝ විට ශුන්‍ය චෙක්පත් එකතු කිරීම් හෝ අරා මත ලූප ආරක්ෂා කරන බවක් පෙනේ, එබැවින් ඒවා හිස්ව ආරම්භ කරන්න, ඔබට කිසිදු ශුන්‍ය චෙක්පතක් අවශ්‍ය නොවේ.

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

මෙහි ඉතා කුඩා පොදු කාර්යයක් ඇත, නමුත් එය පිරිසිදු කේතයක් සහ අඩු NullPointerException සඳහා වටී.



3
+1 මෙය මම එකඟ වෙමි. ඔබ කිසි විටෙකත් ආරම්භක වස්තූන් අඩක් ආපසු ලබා නොදිය යුතුය. ජැක්ස් සම්බන්ධ කේතය සහ බෝංචි කේතය මේ සඳහා නොටීරියස් වේ. එය නරක පුරුද්දකි. සියළුම එකතු කිරීම් ආරම්භ කළ යුතු අතර, සියලු වස්තූන් ශුන්‍ය යොමු කිරීම් නොමැතිව (ඉතා මැනවින්) පැවතිය යුතුය. එකතුවක් ඇති වස්තුවක් සලකා බලන්න. වස්තුව ශුන්‍ය නොවන බවත්, එකතුව ශුන්‍ය නොවන බවත්, එකතුවෙහි ශුන්‍ය වස්තු නොමැති බවත් පරීක්ෂා කිරීම අසාධාරණ සහ මෝඩකමකි.
ggb667

15

බොහෝ සංවර්ධකයින් සඳහා සිදු වූ වඩාත් පොදු දෝෂය මෙයයි.

මෙය හැසිරවීමට අපට ක්‍රම ගණනාවක් තිබේ.

ප්‍රවේශය 1:

org.apache.commons.lang.Validate //using apache framework

notNull (වස්තු වස්තුව, සංගීත පණිවිඩය)

ප්‍රවේශය 2:

if(someObject!=null){ // simply checking against null
}

ප්‍රවේශය 3:

@isNull @Nullable  // using annotation based validation

ප්‍රවේශය 4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}

දැන්වීම. 4. එය එතරම් ප්‍රයෝජනවත් නොවේ - දර්ශකයක් ශුන්‍ය දැයි ඔබ පරීක්ෂා කරන විට, ඔබට ඒ සඳහා ක්‍රමයක් ඇමතීමට අවශ්‍ය වනු ඇත. ක්‍රමයක් ශුන්‍ය ලෙස ඇමතීමෙන් ඔබට එකම හැසිරීමක් ලැබේ - NullPointerException.
pkalinow

11
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}

2
මෙම ක්‍රමයේ ඇති වැරැද්ද කුමක්ද, මම සිතන්නේ ltltester ට අවශ්‍ය වන්නේ එය ශුන්‍ය නම් පෙරනිමි අගයක් ලබා දීමටයි.
සැයර්

1
Apache commons-lang හි එවැනි ක්‍රමයක් තිබේ : ObjectUtils.defaultIfNull(). තවත් එක් සාමාන්‍යයක් තිබේ : ObjectUtils.firstNonNull(), එය පහත් උපාය මාර්ගයක් ක්‍රියාත්මක කිරීමට භාවිතා කළ හැකිය:firstNonNull(bestChoice, secondBest, thirdBest, fallBack);
ivant
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.