- 시작하게 된 계기 및 다짐 😮
이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프
에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.
- 학습 목표 😮
목표 | 결과 |
---|---|
enum(열거형) 이해 및 활용 | O |
에너테이션 개념 및 사용 이유/활용 | O |
람다(Lambda) 이해 및 사용법 | O |
스트림의 특징과 사용목적 및 주요 메서드 활용 | O |
- 정리
열거형(enum)
- 서로 관련이 있는 것들을 모아서 그것들에 번호를 매겨놓은것
- static변수 참조처럼, 따로 new를 통한 객체생성없이 열거형.상수명 으로도 호출가능
ex)
enum 열거형이름{ 상수형1, 상수형2, 상수형3... }
열거형이름 열거형 변수 = 열거형이름.상수명;
열거 객체 메소드
- name() : 열거 객체가 가지고 있는 문자열 리턴(정의시 상수이름과 동일)
- ordinal() : 열거 객체의 순번을 리턴합니다.
- compareTo() : 주어진 매개값과 비교해서 순천 차이를 리턴합니다.
- valueOf(String name) : 주어진 문자열(name)의 열거 객체를 리턴합니다.
- values() : 모든 열거 객체들을 배열로 리턴합니다. (열거 객체 배열)
public static final 문제점
- final 키워드를 사용시, 상수명이 중복되는 경우가 발생
- Interface로 구현시, 이는 해결되지만 타입안정성에 문제가 생김
ex) 의미적으로 비교할 수 없는 개념임에도 불구하고 비교가 되어 문제가 발생
- 클래스로 구현시, 코드가 길어지고 switch문 사용 불가
==> switch문은 (기본타입과 enum타입만 사용가능, 사용자 정의타입 x)
enum 장점
- 상수명의 중복을 피할 수 있습니다.
- 타입에 대한 안정성을 보장합니다.
- 코드가 단순해지고 가독성이 좋아집니다.
- switch문에 사용할 수 있습니다.
에너테이션(Annotation)
- 주석과 같은 개념으로, 프로그램에게 정보는 제공하는 역할
- 런타임에 특정 기능을 수행하도록 정보를 제공
- 프로그램을 빌드할 때 코드를 자동으로 생성할 수 있도록 정보를 제공
ex) @Test // 에너테이션
public void run(){};
표준 에너테이션
- 자바에서 기본제공 에너테이션
1. @Override : 컴파일러에게 메서드를 오버라이딩하는 것이라고 알림
2. @Deprecated : 앞으로 사용하지 않을 대상을 알릴 때 사용
3. @FunctionalInterface : 함수형 인터페이스라는 것을 알림
==> 함수형 인터페이스는 하나의 추상메서드만 존재해야함
==> default 메서드 : 기본적 제공, 원하면 오버라이딩 해서 사용가능
==> static 메서드 : 무조건 사용 필수
4. @SuppressWarning : 컴파일러가 경고메세지를 나타내지 않음
메타 에너테이션
- ★에너테이션에 붙이는 에너테이션
-- ”java.lang.annotation.ElementType.*”
import문을 이용하여 ElementType.TYPE 대신 TYPE과 같이 간단히 작성
==> @Target({FIELD, TYPE, TYPE_USE})
1. @Target : 애너테이션을 정의할 때 적용 대상을 지정하는데 사용한다.
``` FILED(멤버변수,열거형 상수), TYPE(클래스,인터페이스,열거형)
2. @Documented : 애너테이션 정보를 javadoc으로 작성된 문서에 포함시킨다.
3. @Inherited : 애너테이션이 하위 클래스에 상속되도록 한다.
4. @Retention : 애너테이션이 유지되는 기간을 정하는데 사용한다.
5. @Repeatable : 애너테이션을 반복해서 적용할 수 있게 한다.
==> @interface ToDos { // 여러개의 ToDo애너테이션을 담을 컨테이너 애너테이션 ToDos
ToDo[] value(); } // ToDo애너테이션 배열 타입의 요소를 선언. 이름이 반드시 value여야 함
==> @Repeatable(ToDos.class) // ToDo 애너테이션을 여러 번 반복해서 쓸 수 있게 한다.
@interface ToDo{
String value(); }
==> @ToDo("update test codes.")
@ToDo("override test methods")
사용자 정의 에너테이션
-- import java.lang.annotation.*;
- 인터페이스와 비슷하게 정의
ex)
@Target(ElementType.FIELD)//애너테이션이 적용 가능한 대상을 FIELD로 정해줍니다.
@Retention(RetentionPolicy.RUNTIME)//코드 실행시 까지 애너테이션이 유지되게 정해줍니다.
@Documented //애너테이션 정보를 javadoc으로 작성된 문서에 포함시킨다.
public @interface BackendFramework { //백엔드 프레임워크를 지정해주는 애너테이션을 작성합니다.
enum Frameworks {SPRING, DJANGO, EXPRESS}
Frameworks backendFramework() default Frameworks.DJANGO; }
public class KimCoding {
@BackendFramework(backendFramework = BackendFramework.Frameworks.SPRING)
private String KimCodingBackend;}
람다
- 함수 지향 언어, 코드가 매우 간결해짐
- 컬렉션요소 필터링/ 매핑해서 원하는 결과를 쉽게 집계
★ 람다식은 매개변수를 가지는 코드 블록이지만 런타임에 익명 구현 객체를 생성
ex) ★★
타입 변수명 = new 타입(){
public void run() {..} ==> 타입 변수명 = () -> { ... } ; (람다식 형태)
}
★★
// 1. 기본 작성
(타입 매개변수) -> { ... }
// 2. 매개변수가 1개 일 때, 매개변수 () 생략가능
매개변수 -> { ... }
// 3. 매개변수가 2개 이상이고, 리턴문만 존재할 때는 return을 생략가능
(매개변수1, 매개변수2) -> 리턴값;
(num1, num2) -> {return num1 + num2} // return문만 존재하므로
(num1, num2) -> num1 + num2 // return 생략가능, 중괄호도 생략
// 4. 매개변수가 2개 이상이고, 실행문을 실행하고 결과값을 리턴할 경우
(매개변수1, 매개변수2) -> { ... };
// {}안의 코드가 return문이 아니고한줄일 경우, {} 생략가능
return 문만 존재할시, {}와 return 문 생략가능
함수형 인터페이스
- 단하나의 추상메서드만을 포함하는 인터페이스
ex) @FunctionalInterface
public interface MyFunctionalInterface {
public void accept(); ==> MyFunctionalInterface example = () -> { ... };
} -> example.accept();
: accept(); 실행시 {} 안의 코드 실행 함수 오버라이딩 = (매개변수) -> {실행코드};
변수.함수명(매개변수 줄것)
메서드 레퍼런스
- 람다식에서 불필요한 매개변수를 제거하는 목적
- 람다식과 마찬가지로, 인터페이스의 익명 구현 객체로 생성
- 정적/인스턴스 메서드를 참조할 수 있고, 생성자 참조도 가능
1. 정적 메서드
- 클래스 :: 메서드
2. 인스턴스 메서드
- 객체를 생성한 뒤, 참조변수 뒤에
- 참조변수 :: 메서드
ex)
(left, right) -> Math.max(left, right); ==> Math :: max;
IntBinaryOperator operato = Math :: max;
IntBinaryOperator operator;
//static method
operator = Calculator::staticMethod;
System.out.println("정적메서드 결과 : " + operator.applyAsInt(3, 5));
//instance method
Calculator calculator = new Calculator();
operator = calculator::instanceMethod;
System.out.println("인스턴스 메서드 결과 : "+ operator.applyAsInt(3, 5));
3. 매개변수의 메서드 레퍼런스
- 람다식의 매개변수를 사용하여 메서드를 호추 사용
ex)
(a,b) -> {a.instanceMethod(b);}; ==> 클래스::instanceMethod
4. 생성자 참조
- 객체를 생성하고 리턴하도록 람다식의 생성자 참조로 대치 가능
ex) (a,b) -> {return new 클래스(a,b);}; ==> 클래스 :: new
스트림
- 배열,컬렉션의 저장요소를 하나씩 참조하여 람다식으로 처리할 수 있도록 해주는 반복자
- 복잡한 연산 수행 및 가독성,재사용성이 높은 코드 작성
- 스트림은 Read_only로 읽기만 할 뿐 변경 불가
- 일회용으로써, 한번 사용하면 닫히므로, 필요하다면 새로운 스트림 생성 필요
- 요소단위로 하나씩 스트림을 거쳐서 최종 연산까지
# 선언형 프로그래밍
- '어떻게' 수행하는지보다 '무엇을'수행하는지 관심을 두는 프로그래밍
# 내부반복자
- 컬렉션 내부에서 요소들을 반복시키고 개발자는 요소당 처리해야할 코드만 제공하는 코드패턴
- 어떻게 반복시킬지를 컬렉션에게 맡겨두어, 개발자는 요소 처리 코드에만 집중할 수 있다는 장점
- 중간 연산에서는 매핑,필터링,정렬을 수행하고 최종 연산에서는 카운팅,평균,총합등의 집계 수행
# 외부반복자
- 사용자가 코드를 이용해 for,while등을 이용해 반복하는 형태
파이프라인 구성(.)
- 여러개의 스트림이 연결되어 있는 구조로, 최종 연산을 제외하고 모두 중간 연산 스트림이다.
- 최종 연산이 시작되기 전까지 중간 연산들은 기다리다가 최종 연산이 시작되면 데이터의 흐름이 시작됨
# 리덕션
- 대량의 데이터를 가공해서 축소하는 것, 합계,평균값,카운팅등이 리덕션의 결과물
스트림 코드
- Stream<type> stream_ = 스트림_만들_변수.stream(); : 스트림 으로 만들기
- Stream(type) stream_ = Stream.of("a","b","c")
Arrays.stream(new string[] {"a","b","c"}); : 스트림 생성
★★ boxed() : 원시타입 -> 참조/객체 타입으로 변환(배열)
- .filter() : 조건에 맞는 데이터만 정제하여 더 작은 컬렉션
- .distinct() : 중복된 요소 제거
- ★★.map() : 기존의 Stream요소들을 대체하는 연산, 인자로 함수형 인터페이스 funtion을 받음
(mapToInt(), mapToLong(), mapToDouble())
- .flatMap() : 요소를 대체하는 복수 개의 요소들로 구성된 새로운 스트림 리턴 (1차원으로 평면화)
# map은 스트림의 스트림(Stream<Stream>, flatMap은 스트림(Stream)을 반환 , 사진
- .sorted() : default로 오름차순으로 정렬되며 내림차순으로 하려면 Comparator.reverseOrder()을 이용
# 클래스에 직접 비교 메서드를 작성하여 사용하여도 됨 (클래스.메서드(인스턴스::메서드(내부)))
- .peek() : 중간 연산 메서드로, 요소를 하나씩 돌면서 출력, 디버깅을 위함
# forEach()는 최종연산이므로 한번만 사용가능하지만, 이는 중간 연산이라 여러번 가능
- forEach() : 스트림의 모든 요소 출력 , 요소를 하나씩 연산
- allMatch() : 모든 요소들이 주어진 predicate의 조건 만족하는지 조사
- anyMatch() : 최소한 한개의 요소가 매개값으로 만족하는지 조사
- noneMatch() : 모든 요소들이 만족하지 않는지 조사
- reduce(초기값, (a,b) -> a+b) : 최대 3개의 매개변수를 받고,
병렬 연산결과를 합치기 위함
# 위의 reduce는 sum()을 이용한 방법
- collect() : List,set,Map등으로 결과를 수집하고 싶을때, 일반적으로 List로 수집하는 경우가 많음
(toList,toCollection,toMap(Function.identity() = 인자를 그대로 전달), joining("구분자")(String 한줄로))
- toArray() : Array로 반환 ()안에는 클래스::new 형식 or x -> new String[x]
---------
- sum()
- count()
- average()
- max()
- min()
==> 기본타입에 사용
---------
ex)
long sum = Arrays.stream(intArr).sum();
.filter(x -> x.startsWith("조건"))
.map(s -> s.toUpperCase())
.stream_.forEach(System.out::println);
.allMatch(x -> x%2 == 0);
.toArray(String[]::new)
스트림 리턴타입
- Stream : 소스 : 컬렉션
- IntStream,LongStream,DoubleStream : 배열
- IntStream : int 범위
- LongStreram : long 범위
ex)
IntStream stream_ = IntStream.range(4,10) ; ==> 인트범위 스트림 4 ~9
---
Optional<T>
- null값으로 인해 에러가 발생하는 현상을 객체 차원에서 효율적으로 방지하고자 도입
- 모든 클래스를 담을 수 있는 final 클래스(상속 불가)
- 객체 생성시 of() or ofNullable()을 사용 (참조변수의 값이 null일 가능성이 있다면 ofNullable()사용)
- .isPresent() 를 이용하여 null인지 여부를 리턴
Optional 코드
- .isPresent() : null인지 여부를 리턴
- Optional.of() , ofNullable() : 객체 생성
- .<타입>empty(); : 참조변수를 기본값으로 초기화
- .get() : 해당 값 가져오기
- orElse() : null 값일 경우 디폴트 값 지정가능
- .map() : 스트림과 같은 형법
★★ Optionalt의 경우 객체 형식이므로 getAsInt(),getAsDouble()나 orElse()를 이용하여 기본타입으로 변환할 수 있음
ex)
public final class Optional<T> {
private final T value; // T타입의 참조변수 ==> 정의되어 있음
}
Optional<String> opt1 = Optional.ofNullable(null);
System.out.println(opt1.isPresent());
---
컬렉션과 스트림의 차이점
- 컬렉션 : 즉시수행 (Eager)
- 스트림 : Lazy, Short-circuit( 지연,단락평가)
- 스트림은 최종 연산을 호출해야 그제야 나머지 작업들이 처리됨
- 피드백 😮
자바에서 많이 활용하는 enum,에너테이션에 추가적으로 lambda와 stream을 학습하였다. enum의 경우 기존에 배웠던 언어에서도 사용하는 개념이라 비교적 쉽게 이해할 수 있었는데 에너테이션의 경우 한번도 사용해 본적이 없고 이해하기도 쉽지 않은 개념이다. 현업에서 많은 사용이 있다하니 추가적으로 학습하며 코드를 작성할 때 @functionalInterface같은 비교적 쉽게 사용할 수 있는 것들은 사용해 봐야겠다.
Lambda의 경우 축약형 함수로, 코드를 간결하게 하기 위하여 사용하는데 아직 Java에 익숙해지지 않은 상태로 사용하려니 새로 언어를 배우는 것 같다. 이는 Java에 좀더 익숙해지면서 사용하여야 겠다. stream도 마찬가지로 자바에 익숙해지면서 사용해야 겠다.
- 앞으로 해야 될 것 😮