8) I/O와 Stream
입출력(Input/Output)
- 컴퓨터 내부 또는 외부 장치와 프로그램 사이에서 데이터를 주고 받는 것
Stream
- Java에서 I/O을 위해 두 대상을 연결하여 데이터를 송/수신하는데 사용되는 연결통로
- 중간에 끊김이 없이 연속적으로 데이터를 송/수신
8-1) Stream의 종류
- I/O Stream은 한 종류의 일만 할 수 있음(읽거나 쓰거나)
- InputStream : 입력이 가능한 Stream(read()로 입력)
- OutputStream : 출력이 가능한 Stream(write()로 출력)
- 데이터 종류에 따라서도 바이트 기반 Stream과 문자 기반 Stream이 존재
- 각 Stream에는 보조 Stream을 이용해 기반 Stream의 겅능을 높임
📌Byte 기반 Stream
📌Byte 기반 보조 Stream
📌문자 기반 Stream
📌문자 기반 보조 Stream
📌표준 입출력
📌파일 입출력
File 클래스
- File의 생성이나 삭제, 혹은 Directory를 다루는데 사용되는 클래스
- 파일의 내용을 읽기/쓰기 기능을 원한다면 file Stream을 이용해야 함.
RandomAccessFile 클래스
- 파일에 대한 I/O를 하나의 클래스로 사용할 수 있도록 구현할 클래스
- 파일에 특정 위치에 쓰거나 읽는 것이 가능
📌직렬화(Serialization)
- 직렬화 : 객체에 저장된 데이터를 스트림에 쓰기 위해 연속적인 데이터로 변환하는 것 <-> 역직렬화
ObjectInputStream/ObjectOutputStream
을 이용해 객체 직렬화/역직렬화
Serializable
인터페이스를 구현해야함.
transient
키워드로 특정 필드를 직렬화에 배제할 수 있음.
8-2) 오류와 예외
- 프로그램의 에러는 크게 3가지
- Java에서의 런타임 에러
- 오류(Error) : 로직 상에서 수습될 수 없는 심각한 오류
- 예외(Exception) : 로직 상에서 수습될 수 있는 미약한 오류
📌Exception 분류
- Exception 클래스들은 사용자로부터 발생되는 예외(Checked Exception)
- Complie 시점에 체크
- DataFormatException, FileNotFoundException 등
- RuntimeException 클래스들은 개발자의 실수로 발생되는 예외(Unchecked Exception)
- Complie 시점에 체크할 수 없음
- NullPointerException, ArithmeticException 등
📌Exception 클래스 계층
8-3) 예외 처리
📌try-catch-finally문
📌try-catch-finally문
📌try-with-resources문
📌예외 선언
- 메소드에 예외를 선언하는 법
- 예외를 처리하는 방법으로는try-catch-finally문 뿐 아니라 throws로 메소드를 호출한 메소드에게 처리를 위임하는 방법
- 여러 예외인 경우 ,(쉼표)로 구분하며 Exception만 붙여주면 모든 예외가 발생할 가능성이 있다는 뜻
- 위임하는 처리 방법으로 통해 호출 관계를 알 수 있음
📌예외 발생과 catch 블록
📌사용자 정의 예외
기존 Exception 혹 RuntimeException 클래스를 상속받아 구현
📌연결된 예외의 처리
- 여러 예외 중 원인 예외를 지정해서 처리하는 방식
- A예외가 B예외를 일으켰다면 A예외를 원ㅇ니 예외로 지정
initCause
메소드로 지정
- 연결된 예외 처리를 하는 이유
- 여러 작은 Exception을 하나의 큰 exceptiond으로 묶어서 처리
- Checked exception을 unchecked exception으로 변경해서 처리
과제1
과제2
9) Generics와 Enum
9-1) Generics
📌제네릭이란?
- 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법
- 즉, 개발 시점에서는 일반화한 타입을 지정
- 이로서 형변환의 번거로움을 줄여주고, 컴파일 타입에 체크함으로써 안정성을 높임
📌제네릭 선언과 사용
📌제네릭 메서드
- 매개 변수와 반환 값에 타입 파라미터를 갖는 메소드
- 제네릭 클래스의
<T>
와 제네릭 메서드의 <T>
는 별개
- static 변수에 제네릭 타입은 안되지만 메서드에는 가능
- 제네릭 메서드는 호출할 때 마다 타입 매개변수에 타입을 대임(대부분 추론 가능)
📌제네릭 타입과 다형성
- 참조 변수와 생성자로 대입된 타입은 일치해야 함
- 부모 타입으로 지정된 자료 구조나 참조 변수에는 자식 클래스가 들어갈 수 있음
- JDK 1.7부터는 타입 추론이 가능(생성자 타입을 추론 가능)
- 대입된 타입이 다른 제네릭 타입 간의 형 변환은 불가능(와일드 카드인 경우 가능)
📌제한된 제네릭
- 제네릭 타입에 'extends' 키워드를 사용하면 같은 부모 클래스와 부모 클래스를 상속받는 자식 클래스들만 가능
<T extends Animal>
와 같은 식으로 하면 Animal 클래스와 Animal이라는 부모 클래스를 상속받는 자식 클래스만 T에 들어갈 수 있음
- 특정 인터페이스를 구현한 클래스로 제약이 필요하면 implements가 아닌 extends를 사용
📌와일드 카드
- 메소드의 매개변수로 제네릭 클래스의 객체를 받을 때, 타입을 제한하기 위해 사용
<? extends T>
상한 제한(upper bound) : T와 그 자손들을 구현한 객체들만 매개변수로 가능
<? super T>
하한 제한(lower bound) : T와 그 조상들을 구현한 객체들만 매개변수로 가능
<?>
: 제한 없음
- 와일드 카드에는 "&"을 사용할 수 없음
9-2) Enum
📌열거형(Enum type)이란?
- 관련된 상수들을 모아서 나열해 둔 타입을 뜻함
- 자바의 열거형은 값과 타입을 모두 체크 -> 하나라도 다르면 컴파일 에러가 발생
- 타입에 안전(Type safe)한 열거형을 제공
- 열거형에는 기본적으로 0부터 시작되는 정수 값이 ordinal로 부여됨
- 정수 값 외에 필드도 추가 할 수 있음
📌열거형 비교
- 열거형 비교에서는 '=='과 compareTo 메서드 사용 가능
- compareTo 메서드는 oridinal의 차이를 반환
📌java.lang.Enum
- 모든 Enum의 조상격인 추상 클래스
과제
제네릭의 와일드 카드를 사용하여 sum이라는 함수를 구현하세요.
- Sum 메소드에서 숫자 관련된 데이터 타입을 다 받을 수 있어야 함
- 반환 타입을 double
10) Lambda와 Stream
10-1) 람다 표현식(Lambda Expression)
메서드를 하나의 식으로 표현한 것
- 형태는 매개 변수를 가진 코드 블록이지만 런타임 시에는 익명 클래스를 생성
- 간략하면서도 명확한 식으로 표현
- 객체지향보다 함수 지향 언어와 가까움
(타입 매개변수) -> { 실행문; ... }
형태로 작성
📌람다 표현식의 특징
장점
단점
- 람다식의 호출이 까다로움
- 람다 stream으로 단순 반복문 사용 시 성능 저하
- 불필요한 사용 시, 가독성 저하
📌함수형 인터페이스
구현해야 할 추상 메소드가 하나만 정의된 인터페이스
- 인터페이스 위에 @FunctionalInterface룰 붙여 표시
- 컴파일러에서 추상 메서드를 갖춘 인터페이스인지 검사
📌java.util.function 패키지
자주 사용하는 형식에 대한 interface를 제공(>=JDK 1.8)
10-2) Stream API
📌스트림이란?
여러 종류의 데이터를 다양한 방식으로 다룰 수 있도록 제공하는 표준화된 방법 (>=JDK 1.8)
- 배열이나 컬렉션 뿐만 아니라 파일 데이터도 가능
- 반복문이나 반복자(iterator)를 사용하여 개발하지 않아도 되도록 지원
📌스트림 특징
- 원본 데이터를 변경 불가능
- 일회용
- 내부 반복으로 작업 처리
- 기본 데이터 형을 처리할 수 있는 래퍼 스트림 지원
(Int/Double/LongStream)
📌스트림 연산 과정
스트림 생성 -> 중개 연산(스트림의 변환) -> 최종 연산(스트림의 사용)
📌스트림 생성
스트림을 사용하기 위해서는 아래의 여러 원본 데이터를 이용해 스트림 형태로 만들어야 함
- 컬렉션, 배열
- 가변 매개변수
- 지정된 범위의 연속된 정수
- 난수들
- 람다 표현식
- 파일
- 빈 스트림
📌스트림 중개 연산
앞에서 생성된 초기 스트림을 전달받아 필터링이나 변환 등의 연산을 수행
- Filtering
- Mapping
- Sorting
- Splitting
- Iterating
Filtering
- filtering() : 주어진 조건에 참인 요소를 필터링
- distinct() : 스트림의 중복 요소를 제거
Mapping
- map() : map에 명령문을 인수로 전달하여, 반환값들로 구성된 새로운 스트림을 반환
- flatMap() : 스트림 요소가 배열인 경우, 주어진 명령문을 적용한 새로운 스트림으로 반환
Sorting
- sorted() : Comparator를 구현하여 넘겨주거나 natural order로 정렬
Splitting
- limit() : 스트림에서 limit에 들어가는 수만큼의 새로운 스트림을 반환
- skip() : 스트림의 첫 요소부터 skip에 들어가는 수를 제외한 새로운 스트림을 반환
Iterating
- peek() : 각 요소를 돌면서 peek에 전달된 명령문을 수행
📌스트림 최종 연산
앞에서 수행된 중개 스트림을 전달받아 최종적인 연산을 진행하여 인전의 스트림을 사용 할 수 없게 됨
- Calculating
- Collecting
- Reducing
- Matching
- Iterating
Calculating
- count(), min(), max() : 요소의 개수와 최댓값, 최솟값을 반환
- sum(), average() : 요소들의 합과 평균 값을 반환
Collecting
- collect() : 매개변수로 Collectors의 구현 메소드를 받아 메소드의 동작대로 요소를 수집하여 반환
Reducing
- reduce() : 스트림의 첫 두 요소를 가지고 연산 후, 이후 요소들로 연산한 값을 반환
Matching
- anyMatch() : 스트림이 일부 요소가 특정 조건을 만족하면 true를 반환
- allMatch() : 스트림이 모든 요소가 특정 조건을 만족하면 true를 반환
- noneMatch() : 스트림이 모든 요소가 특정 조건을 만족하지 않으면 true를 반환
- findFirst() : 스트림의 첫 요소를 반환
- findAny() : 스트림의 첫 요소를 반환하는 것 같지만 parallelStream의 경우에 쓰임
Iterating
- foreach() : 각 요소를 돌면서 foreach에 전달된 명령문을 수행
📌Optional 클래스
Null값으로 인한 예외를 회피할 수 있는 래퍼 클래스
- 모든 타입의 참조 변수를 저장가능
- 메소드를 이용하여 NullPointerException을 회피 가능
- Stream과 비슷하게 기본 데이터 형을 처리할 수 있는 래퍼 클래스 지원
과제1
특정 수를 입력 받아 1부터 해당 수까지 factorial 연산과 합을 구하는 람다 표현식을 작성하세요.
- Interface 정의
- 하나의 메소드로 두가지 기능을 구현
과제2
특정 수를 입력 받고 해당 숫자 안의 모든 소수를 list로 만드는 스트림을 작성하세요.
11) Deep Dive into JVM
11-1) JVM 리마인드
📌Java 동작 원리
📌JDK vs JRE vs JVM
11-2) JVM 구조
📌Class Loader
class 파일을 JVM에 올려주고, 검증, 초기화해주는 역할
- 클래스 파일을 JVM올려주는 과정을
Loading
- 클래스 파일을 사용하기 위해 검증하고 기본값으로 초기화하는 과정을
Linking
- 클래스 파일을 이용해 static 변수 등을 초기화하는 과정을
Initialization
📌Loading 동작과정
Bootstrap Class Loader
- 가장 필수가 되는 Library class들을 load(rt.jar 등)
Extension Class Loader
- Bootstrap class 다음으로 중요한 class를 load($JAVAHOME/jre/lib/ext/*.jar)
Application Class Loader
- 개발자가 작성한 클래스 파일을 load(classpath에 위치)
📌Linking
Verification
Preparation
- 클래스와 인터페이스 등에 필요한 static field 메모리 할당 및 기본값 초기화
Resolution
- Symbolic Reference 값을 Method Area의 Direct Reference값으로 변환
📌Initialization
앞의 과정이 끝나면 Class 파일의 코드를 읽음
클래스와 인터페이스의 값들을 지정한 값으로 초기화
멀티 쓰레드로 동작하기 때문에 동시성 고려
📌Execution Engine
Interpreter
- 바이트 코드를 한 줄씩 해석, 실행하는 방식
- 초기 방식으로 속도가 느림
JIT(Just-In-Time) 컴파일러
- 실제 실행(바이트코드를 실행하는 시점)하는 시점에 각 OS에 맞는 Native Code로 변환하여 실행 속도 향상
- 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다 일정 사용기준을 넘어가면 JIT 컴파일러 방식으로 실행
- 실행할 때 컴파일한 코드를 캐싱
📌Runtime Data Area
Method Area
- static 변수, 그리고 메소드에 사용되는 데이터와 같은 Class 메타데이터가 저장
- JVM에 하나만 존재, JVM 구동 시에 해당 영역이 생성되고 JVM이 종료 시에 해제
Heap
- Java로 구성된 인스턴스, 배열 등이 저장됨
- 모든 Java Stack 영역에서 참조되어, Thread 간 공유
- 해당 영역이 모두 차게 되면 OutOfMemoryException발생
Java Stack
- Java의 메소드가 호출될 때 사용되는 메모리 공간
- 변수, 오퍼레이션, reference 정보 등이 저장되어 있음
PC Register
- Thread 별로 동시에 동작할 수 있도록 메모리 주소를 저장하는 공간
Native Method Stack
- 시스템 자원을 사용하거나 Java로 구성된 코드만 사용될 수 없는 경우, 다른 프로그래밍 언어로 작성된 메소드를 호출 시 사용되는 영역
11-2) Garbage Collection
📌Garbage Collection(GC)란?
Java의 Heap 영역에서 참조되고 있지 않는 객체들의 메모리를 할당 해제하는 과정
- 명시적으로 불필요한 데이터는 null로 선언
- System.gc() 메소드로 GC를 할 수 있으나 프로그램의 성능에 큰 영향을 미침
- GC과정에서 중요한 개념은 Reachability, Stop-the-world
- 영역에 따라 Minor GC, Major GC로 나뉨
📌Reachability
GC에서 객체가Garbage인지 판별하는 개념
- 어떤 객체로부터 유효한 참조가 있으면 ʻreachable’ <-> ʻunreachable’
- 유요한 참조의 최초 셋을 Root set이라고 함
- Heap 영역 내부의 객체들은 Method Area , java Stack , Native Stack 에서 참조되면 reachable로 판정
📌Stop-the-world
GC수행하기 위해 JVM이 애플리케이션 실행을 멈추는 것
- Stop-the-world가 발생하면 GC 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 대기
- 어떤 GC 알고르짐을 사용하더라도 stop-the-world는 발생
- GC 튜닝이란 stop-the-world 시간을 줄이는 것
📌GC 기본 알고리즘
Mark & Swap Algorithm
- Root Set으로부터 참조된 객체를 mark(Mark phase)
- Mark가 없는 객체는 메모리에서 해제(Sweep phase)
- Fragmentation 발생
- Mark & Swap Algorithm에서 문제인 Fragmentation을 해결
- Sweep단계에서 메모리를 해제하고, 메모리를 정리(Compact Phase)
📌발생 시점에 따른 GC
Minor GC
- Young Generation 영역에서 일어나는 GC
- Eden 영역이 꽉 차면 Minor GC가 발생
- 사용되지 않는 메모리는 해제되고 Eden 영역에 존재하는 객체는 Survivor 영역으로 이동
- 두 개의 Survivor 영역 중 한 영역은 반드시 비어야 함
- Old Generation에서 일어나는 GC
- 일반적으로 Minor GC 보다 오래 걸림
- Young Gen으로부터 promotion된 객체로 인해 Old gen의 메모리가 부족하면 발생
- Major GC가 오래 걸리면 어플리케이션에 치명적인 영향
📌여러가지 GC 방식
Serial GC
Parallel GC
CMS GC
G1 GC
12) Java의 유용한 패키지
12-1) lang 관련 패키지
📌java.lang 패키지
import없이 사용가능한 기본이 되는 가장 중요한 패키지
- 모든 클래스의 최고 조상 클래스인 Object클래스
- String관련 클래스
- datatype 관련 클래스
- System관련 클래스
- Thread관련 클래스 등
📌Object 클래스
- 모든 자바 클래스의 최고 조상 클래스
- 아무것도 상속받지 않으면 자동으로 Object를 상속
- Object 클래스는 필드가 없으며, 총 11개의 메소드만 존재
📌String 클래스
문자열을 다룰 때 많이 사용하는 클래스(참조형 데이터 타입)
- 불변 객체
- 생성자(new)로 변수를 선언하면 heap영역
- 바로 문자열을 할당할 경우 stack영역
+
연산자를 이용해 두 문자열을 합칠 수 있으나 많은 연산 시, 성능 저하
- Stringbuffer / Stringbuilder 클래스 이용
📌StringBuffer퐻 StringBuilder
String 클래스 대신 연산이 많은 경우 사용되는 클래스
- 가변 객체
- 빈번한 연산 시, 성능 좋음(문자열을 합치거나 중간에 특정 문자를 제거하는 경우 등)
StringBuffer과 StringBuilder의 차이점은 동기화의 유무
- 동기화를 하지 않는 StringBuilder가 StringBuffer보다 성능이 좋음
- 멀티 쓰레드 환경에서는 StringBuffer로 동기화
📌String vs StringBuffer
📌Math 클래스
- 수학적인 통계와 계산 이외에도 삼각 함수와 같은 다양한 기능을 제공하는 클래스
- Math 클래스는 생성자가 private으로 되어 있기 때문에 객체를 생성할 수 없음
- Math 클래스는 final 클래스 이기 때문에 상속이 불가능
📌Wrapper 클래스
8개의 기본 타입에 해당하는 데이터를 객체로 포장해 주는 클래스
📌boxing과 unboxing
12-2) util 관련 패키지
📌java.util 패키지
개발에 대부분 사용되는 자료구조나 날짜나 시간 등 유용하게 사용되는 클래스들이 모여 있는 패키지
- Collection 클래스
- Date, Calendar 클래스
- Random , StringTokenizer 클래스 등
📌Collection 관련 클래스
다수의 데이터를 쉽고 효과적으로 처리할 수 있는 방법을 제공하는 클래스(>= JDK 1.2)
- 이 집합을 컬렉션 프레임워크라고 함
- Interface를 사용해 구현
- 대표적으로 많이 사용되는 자료구조의 interface는 List, Set, Map
- JDK 1.5부터 Queue interface도 들어옴
Collection들을 다루기 위한 Collections 클래스도 존재
📌List 컬렉션
List 컬렉션은 객체를 일렬로 늘어놓은 구조
- 객체 자체를 저장하는 것이 아닌 객체의 번지를 참조
- 순서가 있는 데이터의 집합으로 데이터의 중복을 허용
대표적인 클래스
- ArrayList : 배열 기반의 자료구조로 동기화 처리가 없음
- Vector: ArrayList와 비슷, 동기화 처리로 성능때문에 잘 사용하지 않음
- Stack: Vector클래스를 상속받아 스택 메모리 구조의 클래스를 제공. 후입선출(LIFO) 형태
- LinkedList : ArrayList의 단점인 추가, 삭제 기능을 노드를 이용하여 향상시킴
📌Set 컬렉션
Set 컬렉션은 집합과 같은 구조
- 객체 자체를 저장하는 것이 아닌 객체의 번지를 참조
- 순서가 없는 데이터의 집합으로 데이터의 중복을 허용하지 않음
대표적인 클래스
- HashSet : Set을 구현한 대표적인 클래스, hashcode로 객체를 비교
- TreeSet : 이진 탐색 트리(binary search tree)로 구현된 클래스, 범위 탐색과 정렬에 유리, 요소 추가 및 삭제 시 성능 감소
- LinkedHashSet : HashSet에 순서 보장 기능 향상
📌Map 컬렉션
Map 컬렉션은 key, value의 pair의 집합 구조
- 순서가 없음
- Key는 중복 허용x, value는 중복 허용
대표적인 클래스
- HashMap : ArrayList와 LinkedList의 장점을 합쳐서 만든 클래스이며, 해싱기법을 사용하여 검색이 빠름
- TreeMap : TreeSet과 비슷한 구조로 Key를 정렬하고 Entry를 저장하여 사용. 범위 검색 시 성능 좋음
- HashTable : HashMap과 비슷하지만 동기화 처리로 성능때문에 잘 사용하지 않음
- LinkedHashMap : HashMap에 순서 보장 기능 향상
📌Collection 다이어그램
📌Random 클래스
난수를 발생시키는 클래스
- 여러 기본 데이터 형에 맞춰 난수 생성
- 일정 범위 내의 난수 생성 가능
📌StringTokenizer 클래스
문자열을 특정한 구분 문자(Delimiter)로 여러 개의 토큰(Token) 문자열로 분리
• 특수 문자뿐만 아니라 공백(space), 한 문자부터 문자열도 가능
12-3) 시간 날짜 관련 패키지
Date 클래스
- JDK 1.1부터 지원
- 현재는 대부분 Deprecated
Calendar 클래스
- JDK 1.1부터 지원
- 3가지 정도의 문제점을 내재하고 있음
java.time 패키지
- JDK 1.8부터 지원
- 날짜, 시간 외에 타임존이나 표현 형식 관련 지원
📌Date 클래스
주로 날짜를 다룰 때 쓰는 클래스(JDK1.0)
특정 시점, 현재 시점을 기준으로 Date객체를 만들어 사용
SimpleDateFormat 클래스와 같이 많이 사용됨.
📌Calendar 클래스
주로 날짜와 시간을 다룰 때 쓰는 추상 클래스(JDK1.1)
- Date 클래스 대신 사용됨.
- GregorianCalendar 클래스
- Calendar 클래스의 모든 필드는 클래스 변수(static variable)
몇가지의 문제점을 내재하고 있음.
- 윤년, 윤달 등 특이한 케이스를 고려하지 않음.
- 불변 객체가 아님 -> 멀티 쓰레드에서 하나의 객체를 볼 경우, 문제 발생 가능성
- 월 계산의 헷갈림(1월~12월 -> 0 ~ 11)
📌java.time 패키지
날짜, 시간 뿐 아니라 시간대까지 표현가능한 패키지(JDK 1.8)
Calendar 클래스의 문제점을 해결
- 불변 객체
- 멀티 쓰레드 환경에서 안전
- LocalDate, LocalTime, LocalDateTime, ZonedDateTime 클래스 4가지