Optional<SomeObject> someMethod() {
...
return Optional.ofNullable(someObject);
}
// 클라이언트 코드
SomeObject someObject = someMethod()
.orElseThrow(() -> new NullPointerException("객체가 null!");
... we did have a clear intention when adding this feature, and it was not to be a general purpose Maybe type, as much as many people would have liked us to do so. Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors.
위에서 언급한 것처럼 Optional은 의도를 가지고 만들어졌다. 필드나 메소드에 이를 사용하는 것은 과용이다. 메소드 반환 타입으로만 사용하도록 하자
추가적으로 필드에 Optional 사용시 직렬화가 되지 않는다
// Bad!
class SomeClass {
private Optional<String> sth;
String someMethod(Optional<String> param) {
...
}
}
// Good!
class OtherClass {
private String oth;
Optional<String> otherMethod(String param) {
...
}
}
get()
을 호출하지 말자// Bad
Optional<String> optText = getText();
String text = optText.get();
// Good
Optional<String> optText = getText();
String text = optText.orElseThrow(() -> new NullPointerException(""));
String text2 = optText.orElse("");
... 등등등 다양한 Optional api를 활용하자
get()
메소드 이름을 지은 것을 후회한다며 다음과 같이 말했다NEVER call
Optional.get
unless you can prove it will never be null; instead use one of the safe methods likeorElse
orifPresent
. In retrospect, we should have called get something likegetOrElseThrowNoSuchElementException
or something that made it far clearer that this was a highly dangerous method that undermined the whole purpose of Optional in the first place.
public void someMethod(SomeObject object) {
Optional.ofNullable(object).orElseThrow(() -> new NullPointerException());
...
}
위 코드는 Optional의 의도와 다르게 사용하고 있을 뿐만 아니라, null이 아닌 경우 객체를 반환함에도 이를 사용하지 않고 있다
위 같은 상황에서는 그냥 명시적으로 null 체크를 하자
public void someMethod(SomeObject object) {
if (object == null) {
throw new NullPointerException();
}
...
}
public void someMethod(@NonNull SomeObject object) {
...
}
Optional<Object> optObject;
Object object;
// Bad
if (optObject.isPresent()) {
object = optObject.get();
} else {
throw new NullPointerException("null!");
}
// Good
// 참고로 orElseThrow는 자바 10부터 추가됐다
object = optObject.orElseThrow(() -> new NullPointerException("null!"));
filter()
, map()
과 같은 api는 사용하는 것을 잘 보지 못했다. 한번 사용해보자!// Bad
Optional<List<Integer>> method1() ...
Optional<int[]> method2() ...
// Good
List<Integer> method1() {
...
return Collections.emptyList();
}
Optional<int[]> method2() {
...
return new int[0];
}
메소드명에서 알 수 있듯이 ofNullable()
은 null이 들어갈 수 있다. 반대로 of()
에는 null이 들어가면 NPE가 발생한다
만약 of()
에서 NPE가 발생했다면, 뭔가 의도치 않은 잘못된 동작이 실행 됐음을 알 수 있다
객체를 감싸는 Optional<T>이외에도 프리미티브 값을 감쌀 수 있는 OptionalInt, OptionalDouble 등이 존재한다
객체로의 박싱을 피하기 위해 위 객체들을 사용하자
// 특히 값을 이용해 연산을 하는 등 박싱/언박싱이 많이 발생하는 상황에서 사용하면 성능에 나쁘다
// Bad
Optional<Integer> optNum;
// Good
OptionalInt optNum;
equals()
는 1) 동일한 객체, 2) 비어있는 Optional, 3) 감싼 객체의 equals로 비교시 동등한 경우 동등하다고 판단하도록 오버라이딩 되어있다// Bad
Optional<SomeObject> someObj;
Optional<OtherObject> otherObj;
assertEquals(someObj.get(), otherObj.get());
// Good
Optional<SomeObject> someObj;
Optional<OtherObject> otherObj;
assertEquals(someObj, otherObj);
https://dzone.com/articles/java-8-optional-how-use-it
https://dzone.com/articles/using-optional-correctly-is-not-optional