From 4654fb37ae05f73dd922ff07326a2c0d9a525191 Mon Sep 17 00:00:00 2001 From: livenow14 Date: Sat, 18 Sep 2021 11:26:02 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20#29=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gump.md" | 269 +++++++++++++++++- 1 file changed, 260 insertions(+), 9 deletions(-) diff --git "a/java/q5-Java7\352\263\274 Java8\354\235\230 \355\212\271\354\247\225\354\225\240 \353\214\200\355\225\264 \354\204\244\353\252\205\355\225\264\354\243\274\354\204\270\354\232\224/gump.md" "b/java/q5-Java7\352\263\274 Java8\354\235\230 \355\212\271\354\247\225\354\225\240 \353\214\200\355\225\264 \354\204\244\353\252\205\355\225\264\354\243\274\354\204\270\354\232\224/gump.md" index 2979bed..07b0d71 100644 --- "a/java/q5-Java7\352\263\274 Java8\354\235\230 \355\212\271\354\247\225\354\225\240 \353\214\200\355\225\264 \354\204\244\353\252\205\355\225\264\354\243\274\354\204\270\354\232\224/gump.md" +++ "b/java/q5-Java7\352\263\274 Java8\354\235\230 \355\212\271\354\247\225\354\225\240 \353\214\200\355\225\264 \354\204\244\353\252\205\355\225\264\354\243\274\354\204\270\354\232\224/gump.md" @@ -1,5 +1,7 @@ # 정리 +언젠가는 한번 정리해봐야지 했는데, 정리 하다보니 역시 Java8이 오랬동안 사랑받는 이유를 알거 같아요(추가, 변경사항이 엄청나군요..!). 가장 큰 특징들을 그나마 추려봤어요. + ## Java7의 특징 ### Try-with-resources 지원 @@ -174,6 +176,8 @@ public class Machine { 애노테이션을 통해 컴파일 예외가 발생하지 않음 +
+ ## Java8의 특징 ### Heap Permanent Generation 제거 @@ -213,33 +217,274 @@ String producer = Vehicle.producer(); ### Functional interfaces -함수형 인터페이스 +하나의 기능을 제공하는 단 하나의 추상메서드를 정의하는 인터페이스가 추가됐어요. +기능을 위해 default메소드는 원하는 만큼 추가할 수 있어요. +@FunctionalInterface와 함께 쓰이며, 부적절하게 사용될 때 컴파일 하지 않게 할 수 있어요. + +`Comsumer` + +```java +@FunctionalInterface +public interface Consumer { + + /** + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(T t); + + /** + * Returns a composed {@code Consumer} that performs, in sequence, this + * operation followed by the {@code after} operation. If performing either + * operation throws an exception, it is relayed to the caller of the + * composed operation. If performing this operation throws an exception, + * the {@code after} operation will not be performed. + * + * @param after the operation to perform after this operation + * @return a composed {@code Consumer} that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null + */ + default Consumer andThen(Consumer after) { + Objects.requireNonNull(after); + return (T t) -> { accept(t); after.accept(t); }; + } +} +``` ### Lambda expressions -람다 표현식 +람다식은 메서드로 전달할 수 있는 익명 함수를 단순화 한 것이에요. +쉽게 객체 대신 코드를 메서드의 파라미터로 전달하거나, 데이터 그룹을 처리하여 알고리즘을 실행하는데 사용돼요. + +**내부/외부 Iteration** + +외부반복 + +```java +for (String value: myCollection) { + System.out.println(value); +} +``` + +내부반복 + +```java +myCollection.forEach(value -> System.out.println(value)); +``` + +**passing code with behavior parameterization** (동적 파라미터화 코드 전달) + +`Before` + +```java +public class Apple { + private final int weight; + + public Apple(int weight) { + this.weight = weight; + } + + public int getWeight() { + return weight; + } +} +``` + +```java +void before() { + List apples = Arrays.asList(new Apple(10), + new Apple(30), + new Apple(50), + new Apple(70)); + List inventory = new ArrayList<>(); + + for (Apple apple : apples) { + if (apple.getWeight() > 50) { //동작 + inventory.add(apple); + } + } + for (Apple apple : inventory) { + System.out.println("apple.getWeight() = " + apple.getWeight()); + } +} +``` + +위에서의 동작은 조건문 부분이라 볼 수 있어요. 이부분을 동작 파라미터를 사용해서 리팩토링해보면 + +`After` + +```java +void after() { + List apples = Arrays.asList(new Apple(10), + new Apple(30), + new Apple(50), + new Apple(70)); + List inventory = filterApples(apples, it -> it.getWeight() > 50 ); + + for (Apple apple : inventory) { + System.out.println("apple.getWeight() = " + apple.getWeight()); + } +} + +public static List filterApples(List apples, Predicate p) { + List inventory = new ArrayList<>(); + for (Apple apple : inventory) { + if (p.test(apple)) { + inventory.add(apple); + } + } + return inventory; +} +``` + +같은 결과를 출력하는 것을 알 수 있다. ### Method References -메서드 참조 +메서드 참조는 람다식을 좀더 짧고 읽기 쉽게 사용하는 것이에요. 메서드 참조에는 4가지 방법이 있어요. + +**정적 메서드 참조** + +정적 메서드에 대한 참조는 `클래스::메소드명`으로 사용돼요. 먼저 람다식을 사용한 경우를 살펴보면 아래와 같아요. + +```java +boolean isReal = list.stream().anyMatch(u -> User.isRealUser(u)); +``` + +이를 메서드 참조로 변경하면 + +```java +boolean isReal = list.stream().anyMatch(User::isRealUser); +``` + +위와 같이 사용돼요. + +**인스턴스 메서드 참조** + +인스턴스 메서드에 대한 참조는 `인스턴스::메소드명`으로 사용돼요. +아래 코드는 User의 isLegalName(String string)을 호출해요. + +```java +User user = new User(); +boolean isLegalName = list.stream().anyMatch(user::isLegalName); +``` + +**특정 유형의 객체의 인스턴스 메서드 참조** + +특정유형(String, BigDecimal 등) + +```java +long count = list.stream().filter(String::isEmpty).count(); +``` + +**생성자 참조** + +생성자 참조는 `클래스명::new`로 사용해요. 생성자는 특수한 메소드이기 대문에, 메소드 이름으로 new를 사용해요. + +```java +Stream stream = list.stream().map(User::new); +``` ### Date and time API 지원 -날짜와 시간 API 제공 +이전에는 날짜와 시간을 처리하는 것이 굉장히 귀찮았어요. 월요일이 0 또는 1으로 시작하는지, moth는 0으로 시작하는 지 등을 파악 했어야해요. +이를 편리하게 해주는 API가 추가됐어요. + +`javax.time.Clock` + +``` +Clock.systemUTC(); //current time of your system in UTC. +Clock.millis();//time in milliseconds from 1/1/1970. +``` + +`javax.tme.ZoneId` + +``` +ZoneId zone = ZoneId.of(“Europe/London”);//zoneId from a timezone. +Clock clock = Clock.system(zone);//set the zone of a Clock. +``` + +`javax.time.LocalDate` + +``` +LocalDate date = LocalDate.now();//current date +String day = date.getDayOfMonth();//day of the month +String month = date.getMonthValue();//month +String year = date.getYear();//year +``` ### Optional 지원 -Optional을 제공하여 null에 대한 참조를 안전하게 해줌 +Optional을 제공하여 null에 대한 참조를 안전하게 할 수 있게 됐어요. +이전에는 어떠한 객체를 참조할 때 null인지 아닌지 검사를 무조건 했어요(코드량이 많아지면 엄청 귀찮았겟죠?). +이러한 불편함을 해소하기 위해, NPE를 얻을 상황을 처리하는 Optinal이 추가가 됐어요. +Optinal 에서, T의 값이 null이면, 빈 Optinal를 반환하기에, 비어있을 경우 정의된 작업을 처리할 수 있게 됐어요. +`befer` + +```java +User user = getUser(); +if (user != null) { + Address address = user.getAddress(); + if (address != null) { + String street = address.getStreet(); + if (street != null) { + return street; + } + } +} +return "not specified"; +``` + +`after` -### Collectors +```java +Optional user = Optional.ofNullable(getUser()); +String result = user + .map(User::getAddress) + .map(Address::getStreet) + .orElse("not specified"); +``` + +아래와 같이 Optional에서 제공하는 메서드 들을 통해, null참조 가능성이 있는 상황에 유용하게 쓰일 수 있게 됐어요. (더 많은 메소드는 java.util.Optional확인) -### forEach +**Optional.empty()** + +```java +Optional optional = Optional.empty(); +``` + +**Optional.ofNullable(T t) && Optional.of(T t)** + +```java +Optional optional = Optional.ofNullable(getString()); +``` ### Stream API -### Stream Filter +Stream이란 순차/병렬 작업을 지원하는 어떠한 순차적인 요소예요. (java.util.stream.Stream) +쉽게 스트림을 데이터 컬렉션 반복을 멋지게 처리하는 기능이라 생각하면 편해요. + +간단히 특징에 대해 정리하면 -### StringJoiner +- 스트림 API의 특징에는 선언형, 조립할 수 있음, 병렬화가 있다. +- 스트림은 연속된 요소, 중간연산, 최종연산으로 이루어진다. +- 자바 컬렉션은 외부반복, 스트림은 내부반복을 사용한다. +- 중간 연산은 파이프라인으로 구성되어 최종 연 산에서 한 번에 처리된다. 이를 지연 계산된다고 한다. +- 중간 연산은 stream을 반환하고, 최종 연산은 스트림이 아닌 결과을 반환한다. +- 중간 연산의 예시로는 map, filter, flatMap 가 있고, 최종 연산의 예시로는 count, foreach, collect가 있다. + +**데이터 컬렉션(컬렉션)과 스트림의 차이는?** + +문서에도 잘 나와있지만, 둘의 차이는. 크게 목표하는 바가 다르다는 거에요. +컬렉션은 데이터를 어떻게 저장/관리하고 접근하는지를 목표하고 있어요. +이와 반대로 스트림은 데이터를 직접 접근하거나 조작하는 기능을 제공하지 않으며, 데이터를 어떻게 계산할지에 대한 목표를 가지고있어요. +즉, 데이터의 저장/관리가 목적이라면 컬렉션을, 데이터의 계산이 목적이라면 스트림을 사용하는게 좋다고 볼 수 있어요. + +### Collections + +Stream API와 Collections API가 통합되어 Iterator를 상속하는 컬랙션과 Map 컬렉션에 대한 대량 작업이 가능하게 됐어요. ### Parallel Array Sorting (배열 정렬의 병렬처리) @@ -264,6 +509,12 @@ byte[] asBytes = Base64.getDecoder().decode("your base 64 string");
+## Refer + +- [http://openjdk.java.net/projects/jdk8/features#150](http://openjdk.java.net/projects/jdk8/features#150) +- [https://manifesto.co.uk/java-jdk-8-features/](https://manifesto.co.uk/java-jdk-8-features/) +- [https://www.baeldung.com/java-8-new-features](https://www.baeldung.com/java-8-new-features) + ### 질문 varargs란?