미니프로젝트 코드 개선해보기
1. 스트림 이용해 리스트 조회 코드 개선
2. Optional 이용해 Null Safety 코드로 개선
keyword
Promotion | Object
Dynamic Dispatch
익명 객체 | 메소드 레퍼런스
Immutable / Mutable
Stream
Optional
체크리스트
✔ 인터페이스 내용복습
✔ Promotion 과 Dynamic Dispatch를 설명 가능?
✔ 함수형 인터페이스와 람다 이해
✔ 스트림 활용 가능?
✔ Optional 사용 가능?
✔ 미니프로젝트 개선 가능?
interface Practice {
// 상수
(final/static : 지우라고뜸) 타입 상수명(대문자 convention) = 값;
String HI = "Hi~";
// 추상 메서드
List<String> findAllName();
// Default 메소드
default 타입 메소드명(파라미터,...) {...}
default void printHi() {
System.out.println(HI);
}
// static 메소드
static void printHi() {
System.out.println(HI);
}
}
다형성(polymorphism)이란?
하나의 객체가 여러가지 타입을 가질 수 있는 것
자바에서는 부모 클래스의 참조 변수로 자식 클래스의 인스턴스를 참조할 수 있도록 구현
상속, 추상화와 더불어 객체지향프로그래밍 중요한 특징
상속을 통해 기능을 확장하거나 변경하는 것을 가능하게 해줌
같은 클래스 내에 코드 길이를 줄여줌
인터페이스는 객체로 생성할 수 없기 떄문에 생성자 없음
추상클래스는 생성자 있음
-> 모든 클래스는 extends Object 생략
-> 모든 클래스는 Object로 Upcasting 가능
Object anyClazz = new AnyThing();
다형성 -> 오버라이딩 구현
오버라이딩이란?
상위 클래스에 선언되어 있는 메소드를 하위 클래스에서 동일하게 선언하여 사용하는 것
슈퍼클래스를 상속받은 서브클래스에서 슈퍼클래스의
(추상)메소드를 같은 이름, 같은 반환값, 같은 인자로 메소드 내의 로직들을 새롭게 정의하는 것
오버로딩이란?
하나의 클래스에서 같은 이름의 메소드들을 여거래 가질 수 있게 하는 것
단, 메소드 인자들은 달라야 함 (반환 타입은 같아도 되고, 달라도 됨)
Promotion으로 Upcasting된 객체 메소드를
런타임 시점에서
오버라이딩된 메소드에 대한 호출 확인
@FunctionalInterface
public interface Sum {
int intSum(int x, int y);
}
애노테이션이란 ?
상단에 @으로 시작하게 쓴 것
int sum(int x, int y) {
return x + y;
}
// 람다 표현식으로 변경
(x, y) -> x + y;
...
import ...Sum;
public class Main {
Sum sum = (a, b) -> a + b;
System.out.println(sum.intSum(1, 2));
}
// 메소드 레퍼런스 사용
...
import ...Sum;
public class Main {
Sum sum = Integer::sum;
System.out.println(sum.intSum(1, 2));
}
배열이나 컬렉션에 담긴 데이터를 다룰 때, 반복문이나, iterator를 사용하면 코드가 길어지고, 가독성이 떨어지는 것을 해결하기 위해 Stream API 등장
filter
, distinct
map
, flatMap
limit
, skip
sorted
forEach
findFirst
, findAny
count
, min
, max
sum
, average
collect
NPE(Null Pointer Exception) 예외를 Optional이 제공하는 메소드로 간단하게 회피 가능
But, 잘못 사용하게되면 오히려 코드 지저분해지고, 의미없는 동작, Side-Effect이 많이 발생할 수 있음
null을 반환하면 오류가 발생할 가능성이 매우 높은 경우,
“결과 없음”을 명확하기 드러내기 위해
메소드의 반환 타입으로 사용되도록 매우 제한적인 경우로 설계
- Java 언어 아키텍트 Brian Goetz
래퍼 클래스(Wrapper class)
- 기본 타입에 해당하는 데이터를 객체로 포장해 주는 클래스
- 각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어줌
- 모두 java.lang 패키지에 포함되어 제공
기본 타입 래퍼 클래스 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean 래퍼 클래스 중에서 Integer 클래스와 Character 클래스만이 자신의 기본 타입과 이름이 다름
Optional<String> opt = Optional.ofNullable("Optional은 Wrapper Class");
System.out.println(opt.get());
Optional<String> empty = Optional.empty();
System.out.println(empty.isPresent()); // false
Optional<String> empty = Optional.of("assert NotNull");
System.out.println(empty.isPresent()); // true
Optional.of(null); // NPE 발생. of는 null이 아님을 확신할때 사용
Optional<String> empty = Optional.ofNullable(null);
System.out.println(empty.isPresent()); // false
String name = null;
Optional<String> opt = Optional.ofNullable(name);
opt.ifPresent(n -> System.out.println(n.length()));
System.out.println(Optional.ofNullable(null).orElse("냐옹"));
System.out.println(Optional.ofNullable("Hey!").orElse("냐옹"));
// 냐옹
//Hey!
System.out.println(Optional.ofNullable(null).orElseGet(String::new));
System.out.println(Optional.ofNullable(null).orElseGet(() -> "냐옹"));
System.out.println(Optional.ofNullable("Hey!").orElseGet(() -> "냐옹"));
// 냐옹
//Hey!
String nullName = null;
String name = Optional.ofNullable(nullName).orElseThrow(
IllegalArgumentException::new);
// Exception
List<String> elements = Stream.of("a", "b", "c")
.filter(element -> element.contains("b"))
.collect(Collectors.toList());
Optional<String> anyElement = elements.stream().findAny();
System.out.println(anyElement.orElse("암것두 없어"));
Optional<String> firstElement = elements.stream().findFirst();
System.out.println(firstElement.orElse("한개두 없어"));
// b
// b
Stream<String> onceModifiedStream = Stream.of("abcd", "bbcd", "cbcd");
Stream<String> twiceModifiedStream = onceModifiedStream
.skip(1)
.map(element -> element.substring(0, 3));
System.out.println(twiceModifiedStream); //?
System.out.println(twiceModifiedStream.collect(Collectors.toList()));
// java.util.stream.ReferencePipeline$3@816f27d
// [bbc, cbc]
class Product {
private int age;
private String name;
public Product(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
List<Product> productList = Arrays.asList(
new Product(23, "potatoes"),
new Product(14, "orange"), new Product(13, "lemon"),
new Product(23, "bread"), new Product(13, "sugar")
);
List<String> collectorCollection = productList.stream()
.map(Product::getName)
.collect(Collectors.toList());
System.out.println(collectorCollection);
double averageAge = productList.stream()
.collect(Collectors.averagingInt(Product::getAge));
System.out.println("나이 평균 : " + averageAge);
int summingAge = productList.stream().mapToInt(Product::getAge).sum();
System.out.println("나이 총합 : " + summingAge);
// [potatoes, orange, lemon, bread, sugar]
// 나이 평균 : 17.2
// 나이 총합 : 86