NullPointerException 예외의 발생 상황 1
class Friend { // 친구 정보
String name;
Company cmp; // null 일 수 있음
public Friend(String n, Company c) {
name = n;
cmp = c;
}
public String getName() { return name; }
public Company getCmp() { return cmp; }
}
class Company { // '친구 정보'에 속하는 '회사 정보'
String cName;
ContInfo cInfo; // null 일 수 있음
public Company(String cn, ContInfo ci) {
cName = cn;
cInfo = ci;
}
public String getCName() { return cName; }
public ContInfo getCInfo() { return cInfo; }
}
class ContInfo { // '회사 정보'에 속하는 '회사 연락처'
String phone; // null 일 수 있음
String adrs; // null 일 수 있음
public ContInfo(String ph, String ad) {
phone = ph;
adrs = ad;
}
public String getPhone() { return phone; }
public String getAdrs() { return adrs; }
}
가장 좋은 것은 null로 초기화 할 인스턴스 변수가 없는 것!
그러나 허용해야 하는 경우도 있다.
NullPointerException 예외의 발생 상황 2
public static void showCompAddr(Friend f) {
String addr = null;
if(f != null) { // 인자로 전달된 것이 null 일 수도 있으니
Company com = f.getCmp();
if(com != null) { // 회사 정보가 없을 수도 있으니
ContInfo info = com.getCInfo();
if(info != null) // 회사의 연락처 정보가 없을 수도 있으니
addr = info.getAdrs();
}
}
if(addr != null) // 위의 코드에서 주소 정보를 얻지 못했을 수 있으니
System.out.println(addr);
else
System.out.println("There's no address information.");
}
null 가능성에 대비하는 코드의 작성은 번거롭고
그 코드 스타일도 만족스러운 편은 아니다.
이를 해결하기 위해 등장한 것이 Optional 클래스
Optional 클래스의 기본적인 사용 방법 1
public final class Optional<T> extends Object {
private final T value; // 이 참조변수를 통해 저장을 하는 일종의 래퍼 클래스
....
}
public static void main(String[] args) {
Optional<String> os1 = Optional.of(new String("Toy1")); // of는 null을 허용하지 않음
Optional<String> os2 = Optional.ofNullable(new String("Toy2")); // ofNullable은 null 허용
if(os1.isPresent())
System.out.println(os1.get());
if(os2.isPresent())
System.out.println(os2.get());
}
Toy1
Toy2
Optional 클래스의 기본적인 사용 방법 2
class StringOptional2 {
public static void main(String[] args) {
Optional<String> os1 = Optional.of(new String("Toy1"));
Optional<String> os2 = Optional.ofNullable(new String("Toy2"));
os1.ifPresent(s -> System.out.println(s)); // 람다식 버전
os2.ifPresent(System.out::println); // 메소드 참조 버전
}
}
public void ifPresent(Consumer<? super T> consumer)
// Consumer<T> void accept(T t)
Toy1
Toy2
Optional 클래스를 사용하면 if ~ else문을 대신할 수 있다:
이러한 if ~ else 문들…
class ContInfo {
String phone; // null 일 수 있음 (가정)
String adrs; // null 일 수 있음 (가정)
public ContInfo(String ph, String ad) {
phone = ph;
adrs = ad;
}
public String getPhone() { return phone; }
public String getAdrs() { return adrs; }
}
public static void main(String[] args) {
ContInfo ci = new ContInfo(null, "Republic of Korea");
String phone;
String addr;
if(ci.phone != null)
phone = ci.getPhone();
else
phone = "There is no phone number.";
if(ci.adrs != null)
addr = ci.getAdrs();
else
addr = "There is no address.";
System.out.println(phone);
System.out.println(addr);
}
There is no phone number.
Republic of Korea
Optional 클래스를 사용하면 if ~ else문을 대신할 수 있다:
map 메소드의 소개
public static void main(String[] args) {
Optional<String> os1 = Optional.of("Optional String");
Optional<String> os2 = os1.map(s -> s.toUpperCase());
System.out.println(os2.get());
Optional<String> os3 = os1.map(s -> s.replace(' ', '_'))
.map(s -> s.toLowerCase());
System.out.println(os3.get());
}
// public <U> Optional<U> map(Function<? super T, ? extends U> mapper)
// Function<T, U> U apply(T t)
map 메소드는 apply 메소드가 반환하는 대상을 Optional 인스턴스에 담아서 반환한다.
OPTIONAL STRING
optional_string
Optional 클래스를 사용하면 if ~ else문을 대신할 수 있다:
orElse 메소드의 소개
public static void main(String[] args) {
Optional<String> os1 = Optional.empty();
Optional<String> os2 = Optional.of("So Basic");
String s1 = os1.map(s -> s.toString())
.orElse("Empty");
String s2 = os2.map(s -> s.toString())
.orElse("Empty");
System.out.println(s1);
System.out.println(s2);
}
Optional 인스턴스를 대상으로 orElse 메소드를 호출하면,
orElse를 호출하면서 전달된 인스턴스가 대신 반환된다.
저장된 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 인수로 전달된 값을 반환함.
Empty
So Basic
Optional 클래스를 사용하면 if ~ else문을 대신할 수 있다 :
최종 결론
public static void main(String[] args) {
ContInfo ci = new ContInfo(null, "Republic of Korea");
String phone;
String addr;
if(ci.phone != null)
phone = ci.getPhone();
else
phone = "There is no phone number.";
if(ci.adrs != null)
addr = ci.getAdrs();
else
addr = "There is no address.";
System.out.println(phone);
System.out.println(addr);
}
->
public static void main(String[] args) {
Optional<ContInfo> ci
= Optional.of(new ContInfo(null, "Republic of Korea"));
String phone = ci.map(c -> c.getPhone())
.orElse("There is no phone number.");
String addr = ci.map(c -> c.getAdrs())
.orElse("There is no address.");
System.out.println(phone);
System.out.println(addr);
}
showCompAddr 메소드의 개선 결과
// public <U> Optional<U> map(Function<? super T, ? extends U> mapper)
// Function<T, U> U apply(T t)
public static void showCompAddr(Friend f) {
String addr = null;
if(f != null) {
Company com = f.getCmp();
if(com != null) {
ContInfo info = com.getCInfo();
if(info != null)
addr = info.getAdrs();
}
}
if(addr != null)
System.out.println(addr);
else
System.out.println("There's no...");
}
->
public static void showCompAddr(Optional<Friend> f) {
String addr = f.map(Friend::getCmp)
.map(Company::getCInfo)
.map(ContInfo::getAdrs)
.orElse("There's no...");
System.out.println(addr);
}
public static void main(String[] args) {
ContInfo ci =
new ContInfo("321-444-577", "Republic of Korea");
Company cp = new Company("YaHo Co., Ltd.", ci);
Friend frn = new Friend("LEE SU", cp);
showCompAddr(Optional.of(frn));
}
Optional 클래스의 flatMap 메소드:
Optional 클래스를 코드 전반에 사용하기 1
public static void main(String[] args) {
Optional<String> os1 = Optional.of("Optional String");
Optional<String> os2 = os1.map(s -> s.toUpperCase());
System.out.println(os2.get());
Optional<String> os3 = os1.flatMap(s -> Optional.of(s.toLowerCase()));
System.out.println(os3.get());
}
map은 람다식이 반환하는 내용물을 Optional로 감싸서 반환!
flatMap은 그냥 반환! 따라서 필요하면 직접 Optional로 감싸야 한다.
OPTIONAL STRING
optional string
Optional 클래스의 flatMap 메소드:
Optional 클래스를 코드 전반에 사용하기 2
class ContInfo {
Optional<String> phone; // null 일 수 있음
Optional<String> adrs; // null 일 수 있음
public ContInfo(Optional<String> ph, Optional<String> ad) {
phone = ph;
adrs = ad;
}
public Optional<String> getPhone() {
return phone;
}
public Optional<String> getAdrs() {
return adrs;
}
}
public static void main(String[] args) {
Optional<ContInfo> ci = Optional.of(
new ContInfo(Optional.ofNullable(null), Optional.of("Korea"))
);
String phone = ci.flatMap(c -> c.getPhone())
.orElse("There is no phone number.");
String addr = ci.flatMap(c -> c.getAdrs())
.orElse("There is no address.");
System.out.println(phone);
System.out.println(addr);
}
There is no phone number.
Republic of Korea
Optional 클래스의 flatMap 메소드:
Optional 클래스를 코드 전반에 사용하기 3
예제 NullPointerCaseStudy3.java를
Optional 사용의 모델로 제공을 하니 적절히 참고하기 바랍니다.
'# 02 > Java' 카테고리의 다른 글
[윤성우 열혈자바] 29-1. 스트림의 이해와 스트림의 생성 (0) | 2019.10.28 |
---|---|
[윤성우 열혈자바] 28-3. OptionalInt, OptionalLong, OptionalDouble 클래스 (0) | 2019.10.28 |
[윤성우 열혈자바] 28-1. 메소드 참조 (0) | 2019.10.28 |
[윤성우 열혈자바] 27-2. 정의되어 있는 함수형 인터페이스 (0) | 2019.10.25 |
[윤성우 열혈자바] 27-1. 람다와 함수형 인터페이스 (0) | 2019.10.25 |