Java ã§å¼æ°ã® null ãã§ãã¯ã§è¿·ã£ã話
ãã㯠Java Advent Calendar 2015 ã® 15 æ¥ç®ã®è¨äºã§ãã
æ¨æ¥ã¯ @opengl_8080 ããã® Byteman 使ãæ¹ã¡ã¢ï¼Î± ã§ãããææ¥ã¯ @irof ããã§ãã
åç½®ã
ã¤ãããªãã ãã¼ã ã§ã¡ãã£ã¨ã ã話é¡ã«ä¸ã£ã¦ãã¿ããªããç¨åº¦æéã¯æã£ã¦ãããã®ã®ãå²ã¨æ©ã¿ã¤ã¤æ確ã«çããåºããªãã£ãã®ã§ããã£ã¨è¯ãæè¦ãããã°ã¨æã£ã¦æãã¦ã¿ã¾ããã¾ããããã話ã ããJava 8 㧠Optional
ã使ããããã«ãªã£ã¦ null
ã«ã¤ãã¦èªãããã±ã¼ã¹ãå¢ããã¨æãã®ã§ãåèããã¡ããã©ããæ©ä¼ã«ãªãã°ãããªã¼ã¨æãã¾ããåå¿è
åãã§ãã
ã©ãå¦ãï¼å¦ãï¼
ãããªç¶æ³ã®æã«ããªããªãã©ããã¾ããï¼
// Generics ãªã®ã¯ä¾ã§ããString ã§ããªãã§ãããã§ã public T doSomething(T input) { // input ã null ã®æã«ã©ãå¦ãï¼å¦ãï¼ }
ãã¡ãããå¼ã³åºãå´ã®ã³ã³ããã¹ãã¨ããã©ã¤ãã©ãªãä½ä½¿ããã¨ããJava 8 or ãã以åã¨ãããããã£ãåæã«ãã£ã¦ãããã対å¦ã¯å¤ãã£ã¦ããã¨ã¯æãã®ã§ãããããã¤ãé¸æè¢ãããã¨æãã¾ããè¯ãæªããç½®ãã¨ãã¦ãããè¦ãã®ã¯ã
null
ãè¿ã- ä½ããã®ããã©ã«ãå¤ãè¿ã
java.lang.IllegalArgumentException
ãªã©ã®ä¾å¤ãæãã
辺ãããªãã¨æãã¾ããnull
ãè¿ããã¿ã¼ã³ã®æã¯ãããè¿ãå¤ã Collection
ãé
åãªã®ã«ãnull
è¿ãã¡ãããããªã®ãè¦ãããããEffective Java ããã£ã¨å·®ãåºãã¦ããã¦ãã ããã
ãã¬ãæ°ãå¹ãã¦ãã®ã
å人çã«ã以ä¸ã®ãããªå®è£ ãè¦ãããããããã¬ããã¹ãã¿ãªãã£ãå¿å¾ã¦ããã®ã ãã£ã¦æãã¾ãã
- Null Object ãã¿ã¼ã³ã§ä½ãããªããªãã¸ã§ã¯ããè¿ã
- ãããä¸ç¨®ã®ããã©ã«ãå¤ãè¿ããã¿ã¼ã³ã¨è¨ãã
public interface Command { void execute(); } public class ABCCommand implements Command { public void execute() { System.out.println("ABC"); } } // ããã¤ã Null Object public class NullCommand implements Command { public void execute() { // do nothing } } public class Main { public static void main(String... args) { Command missing = createCommand(null); // æ®éãããªãã¨ãããªããã© missing.execute(); // createCommand ã®æ»ãå¤ã null ã ã£ãããã¨ãã null ãã§ãã¯ãè¦ããªã } public static Command createCommand(String name) { if ("abc".equals(name)) { return new ABCCommand(); } else { return new NullCommand(); } } }
- ã¬ã¼ãç¯ã表ç¾ããå®è£
ããã
- ã¡ã½ããå ã®é ã§ãåãå ¥ããããªãå¤ãæ¥ããããã©ã«ãå¤ãä¾å¤ãæããããã«ãã¦ã¡ã½ããããæãããã¨ã§ãèããªãããããªããã¨ãæ¸ããã
java.util.Objects#requireNonNull
ã¨ããApache Commons Lang ã®Validate#notNull
ã¨ãã®null
ãã§ãã¯ç³»ã®ã¦ã¼ãã£ãªãã£ã¡ã½ããã使ã£ã¦ãã°ãããã«ãããããããåç¥ããæä¸ããã¾ã
public T doSomething(T input) { if (input == null) { throws new IllegalArgumentException("null ã¯ãã¡ãããã¡ãã¡"); } // ãããã input != null ã®å ´åã®å¦ç } public T doSomething(T input) { Objects.requireNonNull(input); // ãããã input != null ã®å ´åã®å¦ç }
- Java 8 使ã£ã¦ããªã
- ã¬ã¼ãç¯ã§ãè¯ããã©ã
java.util.Optional
ã®ifPresent()
ãorElse()
ã§null
ã®æãç¡è¦ããããããã©ã«ãå¤ãè¿ãããã«ãã - ãæåã«åãå
¥ããªãå¤ãå¼¾ããã¨ããããã¯ããåãå
¥ããæã ãå¦çãããã¨ããåãå
¥ããªã奴ã¯å¾ã§
orElse()
ãããã¿ãããªã¡ã³ã¿ã«ã¢ãã«ã®è»¢æãå¿ è¦ãããããªã
- ã¬ã¼ãç¯ã§ãè¯ããã©ã
public String capitalize(String input) { return Optional.ofNullable(input).map(String::toUpperCase).orElse(""); // null ã®æã¯ç©ºæåãè¿ã } public void printCapitalize(String input) { Optional.ofNullable(input).ifPresent(s -> System.out.println(s.toUpperCase())); // null ãããªãæã ãå¦çãã } // ããã¯ã¢ã«ã³ public String capitalize(String input) { Optional<String> optionalInput = Optional.ofNullable(input); if (optionalInput.isPresent()) { return ""; } return optionalInput.map(String::toUpperCase).get(); }
ããããæ¬é¡
ã§ãç§ã¨ãã¦ã¯ãå¼æ°ã null
ã®æã«åææ¡ä»¶ãæºããã¦ããªãã±ã¼ã¹ã§ããã©ã«ãå¤ãè¿ããªãã¦è¯ãå ´åã¯ãIllegalArgumentException
ï¼ã¾ãã¯ã¢ããªã±ã¼ã·ã§ã³åºæã®åææ¡ä»¶ã¨ã©ã¼ã表ç¾ããå®è¡æä¾å¤ï¼ãæãããã¨ãå¤ãã§ããä¸ã®ä¾ã§æããã
public T doSomething(T input) { if (input == null) { throws new IllegalArgumentException("null ã¯ãã¡ãããã¡ãã¡"); } // ãããã input != null ã®å ´åã®å¦ç } public T doSomething(T input) { Objects.requireNonNull(input); // ãããã input != null ã®å ´åã®å¦ç }
ãã®ãã¿ã¼ã³ã§ããã
ã§ãJava 7 ãã使ããããã«ãªã£ã java.util.Objects#requireNonNull
便å©ããªã¼ã¨æã£ã¦å®è£
ãè¦ã¦ãããã
public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } public static <T> T requireNonNull(T obj, String message) { if (obj == null) throw new NullPointerException(message); return obj; }
ãããªã£ã¦ããã§ããIllegalArgumentException
ã§ã¯ãªãã¦ãNullPointerException
ãè¿ãã¦ããã§ããããããä»ã¾ã§ç§ã¯ IllegalArgumentException
æ´¾ã ã£ããã§ããçç±ã¯ã
- å¼æ°ã
null
ãªã®ãèªæãªã®ã§ãèªåã§ããããNullPointerException
æããã®ãåé·ã ããªããæµæããã - ã¬ãã½ãèµ·ããã¨ããã§ã¬ãã½ã ããã£ã¦ã¡ãã»ã¼ã¸ãåºããããã
IllegalArgumentException
ã§null
ã¯åãå ¥ããªãããã¨ããã¡ãã»ã¼ã¸ã®æ¹ãããåææ¡ä»¶ãã¯ã£ãã主張ãã¦ããã¨æã
ãã ãã¡ãªããããã£ã¦ãjava.util.Objects#requireNonNull
ã® Javadoc ã«ãæ¸ãã¦ããã¾ãããã³ã³ã¹ãã©ã¯ã¿ã§ä½¿ãã¨å®éã®ã¡ã½ããå¼ã³åºãæããæ©ã NullPointerException
ãã©ãããåãããã¨ãããã¨ãããã¾ãã
public Foo(Bar bar) { this.bar = Objects.requireNonNull(bar); }
ãããªæãã§ãã©ã£ã¡ãããã®ãè¿·ã£ã¦ãã¾ã£ãã®ã§ãã¨ããããä»ã®å®è£ ãè¦ã¦ã¿ã¾ããã
è¦ã¦ã¿ãã®ã¯ä»¥ä¸ã®4ã¤ã
- Apache Commons Lang 2ç³»ï¼v2.6ï¼ã®
Validate#notNull()
- Apache Commons Lang 3ç³»ï¼v3.4ï¼ã®
Validate#notNull()
- Google Guava v19.0 ã®
Preconditions#checkNotNull()
- Spring Framework Core ã®
Assert#notNull()
Apache Commons Lang 2ç³»ï¼v2.6ï¼ã® Validate#notNull()
public static void notNull(Object object) { notNull(object, "The validated object is null"); } public static void notNull(Object object, String message) { if (object == null) { throw new IllegalArgumentException(message); } }
Apache Commons Lang 3ç³»ï¼v3.4ï¼ã® Validate#notNull()
private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null"; // éä¸çç¥ public static <T> T notNull(final T object) { return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE); } public static <T> T notNull(final T object, final String message, final Object... values) { if (object == null) { throw new NullPointerException(String.format(message, values)); } return object; }
Google Guava v19.0 ã® Preconditions#checkNotNull()
public static <T> T checkNotNull(T reference) { if (reference == null) { throw new NullPointerException(); } return reference; } public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) { if (reference == null) { throw new NullPointerException(String.valueOf(errorMessage)); } return reference; }
Spring Framework Core ã® Assert#notNull()
public static void notNull(Object object) { notNull(object, "[Assertion failed] - this argument is required; it must not be null"); } public static void notNull(Object object, String message) { if (object == null) { throw new IllegalArgumentException(message); } }
å®éã«å®è¡ãã¦ã¿ã
ãã¾ãï¼Lombok
Lombok ã«ã @NonNull
ã¨ãã null
ã許容ããªããã¨ã表ãã¢ããã¼ã·ã§ã³ãããã®ã§ããããä¸ç·ã«å®è¡ãã¦ã¿ã¾ããã
@Data public class NullObject { private String name; public NullObject(@NonNull String name) { this.name = name; } }
ãã¹ãã³ã¼ã
public class NullTest { @Test public void caseOfRequireNonNull() throws Exception { Objects.requireNonNull(null); } @Test public void caseOfCommonsLang2Validate() throws Exception { org.apache.commons.lang.Validate.notNull(null); } @Test public void caseOfCommonsLang3Validate() throws Exception { org.apache.commons.lang3.Validate.notNull(null); } @Test public void caseOfGuava() throws Exception { com.google.common.base.Preconditions.checkNotNull(null); } @Test public void caseOfSpring() throws Exception { org.springframework.util.Assert.notNull(null); } @Test public void caseOfLombok() throws Exception { new NullObject(null); } }
å®è¡çµæ
java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at MainTest.caseOfRequireNonNull(MainTest.java:13) java.lang.IllegalArgumentException: The validated object is null at org.apache.commons.lang.Validate.notNull(Validate.java:192) at org.apache.commons.lang.Validate.notNull(Validate.java:178) at MainTest.caseOfCommonsLang2Validate(MainTest.java:23) java.lang.NullPointerException: The validated object is null at org.apache.commons.lang3.Validate.notNull(Validate.java:222) at org.apache.commons.lang3.Validate.notNull(Validate.java:203) at MainTest.caseOfCommonsLang3Validate(MainTest.java:18) java.lang.NullPointerException at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:212) at MainTest.caseOfGuava(MainTest.java:28) java.lang.IllegalArgumentException: [Assertion failed] - this argument is required; it must not be null at org.springframework.util.Assert.notNull(Assert.java:115) at org.springframework.util.Assert.notNull(Assert.java:126) at MainTest.caseOfSpring(MainTest.java:33) java.lang.NullPointerException: name at NullObject.<init>(NullObject.java:11) at MainTest.caseOfLombok(MainTest.java:39)
ã¾ã¨ããã¨
ã©ã¤ãã©ãª | çµæ |
---|---|
Java 7 ã® java.util.Objects ã® Objects#requireNonNull() |
NullPointerException |
Apache Commons Lang 2ç³»ï¼v2.6ï¼ã® Validate#notNull() |
IllegalArgumentException |
Apache Commons Lang 3ç³»ï¼v3.4ï¼ã® Validate#notNull() |
NullPointerException |
Google Guava v19.0 ã® Preconditions#checkNotNull() |
NullPointerException |
Spring Framework Core ã® Assert#notNull() |
IllegalArgumentException |
Lombok ã® @NonNull |
NullPointerException ã§ã¨ã©ã¼ã¡ãã»ã¼ã¸ã§ null ã ã£ããã£ã¼ã«ããæãã¦ãããï¼è¨å®ã§ IllegalArgumentException ã«ãã§ãã模æ§ï¼ |
è¦äºã«å²ãã¾ãããã§ãcommons-lang ã® 2 ç³»ã¯å¤ãã®ã§ç¡è¦ããã¨ãã¦ãSpring ã® Assert#notNull()
ã core ããã±ã¼ã¸ã«å±
ããã¨ããã£ã¦ã©ã¡ããã¨è¨ãã¨ãã¬ã¼ã ã¯ã¼ã¯å
é¨ã®ããã®ã¯ã©ã¹ã®ãããªæ°ãããã®ã§ããããã㨠NullPointerException
åªå¢ãªæããªã®ããªãããªãã¦æã£ããã
ãã¼ã ã®äººã«ãèãã¦ã¿ã
åé ã§ãè¿°ã¹ãã¨ããããã¼ã ã®äººã«ãèãã¦ã¿ãã®ã§ãã£ãããã°ãæãã¦ã¿ã¾ããããããæè¦ãèãã¾ãããåºæ¬ãµã¼ããµã¤ãã®äººãå¤ãã§ãããA ãã㯠Android ãã£ãããããªã®ã§ã¾ã観ç¹ãéãã¾ããã
ï¼ãããï¼: Java ã§å¼æ°ã null ãã©ãããã§ãã¯ããæãNPE ã IllegalArgumentException ããã©ã£ã¡æãã¾ãï¼ ããããããç§ IAE æ´¾ã ã£ããã§ããã©ãJava7 ããå ¥ã£ã Objects#requireNonNull ã NPE è¿ãããã«ãªã£ã¦ã¦ãã©ã£ã¡ãããããããªã¼ã¨æã£ã次第 ããããããã¡ãªã¿ã« Apache commons lang ï¼Validate#notNullï¼ã ã¨2系㯠IAEã3系㯠NPE ããããããGoogle guava ã® Preconditions#checkNotNull 㯠NPE ããããããSpring Framework ã® Assert#notNull 㯠IAE ããããããæ©ã¾ãã ããããããLombok ã® @NonNull ã NPE ã ãªã¼ ããããããNPE ã®æ¹ã主æµãªã®ãâ¦ãªããèªå㧠NPE æããã®æµæãããã ããªãï½ ï¼Aããï¼: ãããããã ããããããAndoridStudioã®@NonNull,@Nullableã«æ £ãããã¦ãã¦nullããªãã¼ã·ã§ã³ã¯æ¾ç½®ç¶æ ã®æè¦ã«ãªã£ã¦ããããã ï¼Bããï¼: Effective Javaã£ã¦ã©ã£ã¡æ´¾ã§ããã£ãï½ããªãã触ãã¦ãé ããã¾ãããã ããããããã¡ãªã¿ã«åãIllegalArgumentExceptionã§ãããï½ ï¼ãããï¼: ã§ãããï½ ããããããIDEä»»ãã«ãããªã @NonNull 使ãã®ãããã®ããªã¼ãã£ã±ã ããããããEffective Java 㯠null è¿ãããããªãã¦ç©ºè¿ããã¨ããããªãã§ããã£ã ï¼Bããï¼: 空è¿ããããã¾ããããããã¨ã¯å¥ã®é ã£ã ããããã æ°ã«ãªãï½ ããããã http://tbpgr.hatenablog.com/entry/20130203/1359914058 ããããã ããã ï¼ ããããã NullPointerExceptionã ã£ãï½ï½ï½ ï¼ãããï¼: Effective Java ãè¨ãããªãééããªãï¼è¿«ç ï¼Bããï¼: å¾ãç¾æãã³ããªãã§ãã ï¼ãããï¼: çç±ã¨ãã¦ã¯ã¬ãã½ã¯ã¬ãã½ã¨ãã¦è¡¨ç¾ããã£ã¦ãã¨ãªã®ããªã¼ï¼IAE ã¨æ··ãããªå±éºçãªï¼ ï¼Cããï¼: ãã⦠Springã® Assert ã£ã¦ä¾å¤æããã®ã⦠ãªãã assert ã®æ§æã¨ã¯éããã®ã¨ããèªèãèãã£ãã¿ããã§ãã¯ã¿ã·çã«ã¯ ï¼ãããï¼: ããç½ ã£ã½ããããï½ ï¼Cããï¼: ä»ç¥ãã¦ããã£ãï½ ããããããIAE > NPE çãªæãï¼ã§ä½¿ãã°è¯ãããï¼ãªãããã ããããããnullã®ã±ã¼ã¹ã¯NPEããããç㪠ï¼ãããï¼: ãããªæãã£ã½ãã㪠ï¼Aããï¼: ç²ç®çã«NPEã¨ããããã¡ã½ããã®ã¬ã¤ã¤ã¼ã«ãããæ°ããããã§ããã©ããã ããããããAPIçãªåä½ãããå ´åãä»ã®å¼æ°ä¸æ£ãIAEã§ãã£ã¦ããã®ã«NonNullæã ãNPEã£ã¦ããã®ã使ãã«ããæãããããªå°è±¡ãããã¾ãã ï¼ãããï¼: ãµã¼ããµã¤ãã ã¨ãæçµçã«ãã¬ã¼ã ã¯ã¼ã¯ã®éãã§ãã¯ä¾å¤ã§ä¸¸ãã¡ããäºãå¤ãã®ã§ãã©ã£ã¡ãã¨ããã¨ã¡ãã»ã¼ã¸ãã¡ããã¨ãã¦ããã©ããã®ã»ããéè¦ãªã®ãããããªãã§ãã ï¼Cããï¼: å人çã«ã¯null以å¤ã®ã±ã¼ã¹ã¨åºå¥ããã£ã¦æå³ã§ã¯è¯ãããã«æãã¾ããã©ãèªåã§validationç³»ã®ä¾å¤æããããªãã±ã¼ã¹ã¨ãã«ã©ããããã£ã¦æããã ããããããï¼ã¡ãã»ã¼ã¸ãã¡ããã¨ãã¦ããã©ããã®ã»ããéè¦ ãããããã確ãã« ï¼Aããï¼: ï¼ã¡ãã»ã¼ã¸ãã¡ããã¨ãã¦ããã©ããã®ã»ããéè¦ ãããããããªãã»ã©ã ï¼Cããï¼: ãã¨ã¯ Effective Java çã«ã¯ã¡ããã¨ããã¥ã¡ã³ãæ¸ããã£ã¦ããè¨ããã¦ãã¨ãããè¦ãã« ããããããhttps://docs.oracle.com/javase/jp/8/api/java/util/Map.html ããããããcontainsKeyã¨ãã®ããã¥ã¡ã³ãã«ã¯ã¡ããã¨NPEã®åºãã±ã¼ã¹ãæ¸ããã¦ãã®ã§ ããããããããããã®ã«å£ã£ã¦ããã®ãè¯ããã§ããã ï¼ãããï¼: ãã¼ãã»ãã¾ã ããããããput ã¨ãã¡ããã¨ä½¿ãåãã¦ãã®ãâ¦ä»ããç¥ã£ãw ããããããhttps://docs.oracle.com/javase/jp/8/api/java/util/Map.html#put-K-V- ï¼Cããï¼: ããï¼putããä¾ã£ã½ã ï¼Aããï¼: ãã®ä¾ããã解ããããã§ããï¼ ãããããããã¨ã¯å¼æ°nullãã§ãã¯ãã¦NPEãããããthrowããæ°æã¡æªãæ㨠ããããããthrow new NullPointerException("IllegalArgument"); ããããããã¨æ¸ããããªãèªæã¨ã®æ¦ãã»ã»ã»ã
ã¾ã¨ã
Objects.requireNonNull
ãªã©ãnull
ãã§ãã¯ãè¡ãã©ã¤ãã©ãªã®å®è£ ã¯NullPointerException
åªå¢- Java8 ã§
Optional
ã使ããããã«ãªã£ãã®ã§ãifPresent()
ãorElse()
ãä¸æã使ããããã«ãªã£ã¦ãã - IDE ã®ãã§ãã¯ã JSR-305 ã«ä»»ããã®ãä¸èï¼
@NonNull
ã¨ã@Nullable
ã¨ãï¼ - ãã®ã³ã¼ããã©ã¤ãã©ãªãªã®ãã¢ããªã±ã¼ã·ã§ã³ãªã®ãã«ãã£ã¦ã対å¦ã¯éã£ã¦ãã
- ã¨ã©ã¼ã¡ãã»ã¼ã¸ãã¡ããã¨æ¸ãã¾ããã
- Javadoc ã«ã¡ããã¨æ¸ãã¾ãããï¼Effective Java ã«ãããæ¸ãã¦ããï¼
NullPointerException
ã¨IllegalArgumentException
ãæ··ããªãæ¹ãããï¼- ä¾ã¨ãã¦
java.util.Map<K, V>#put()
ã¯ä½¿ãåãã¦ãã
ãæè¦è³ããã
ã±ã¼ã¹ãã¤ã±ã¼ã¹ã ã¨æãã®ã§ãå ¨ã¦ã®ã±ã¼ã¹ã§åä¸ã®å¯¾å¦ã§æ¸ã¾ãããã¨ã¯ã§ããªãã¨æãã¾ãããããããæã¯ãããã¹ããã¨ãããããªãæè¦ããã£ãããã³ã¡ã³ãçã§æãã¦ããããå¬ããã§ãã
ãã¨ãç§ã¨ãã¦ã¯ããå¾è¼©ã« null
é¢é£ã®è³ªåããããããã¾ãã¯å¤ªä¸ï¼ @ryushi ï¼ããã® JJUG CCC ã®ã¹ã©ã¤ããèªã¿ãªããéåã奨å±ãã¦ãã¾ãã