String readLine()
// 줄의 끝이나 파일 끝을 만나기까지의 문자열을 반환한다
// 각 바이트들을 0 패딩하여 char로 변환하므로, 유니코드를 읽기는 부적합하다
// 아무것도 읽지 못한 경우, 빈 문자열이 아닌 null이 반환된다
String readUTF()
// 먼저 readUnsignedShort()와 같은 방법으로 2개 바이트를 읽어와 길이를 구한다
// 구한 길이만큼의 바이트를 읽으면서 상기한 Modified UTF-8에 맞춰 String을 만든다
// 길이만큼의 바이트를 다 읽기 전에 EOF를 만나면 예외를 던진다
DataOutput
DataInput과 대칭
InputStream
바이트 단위 읽기에 대한 최상위 추상 클래스
작업이 끝날 때까지 스레드가 블록되며, 스트림이 비동기적으로 닫히거나, 인터럽트가 발생하는 경우에 대해 대처하지 않는다
↓ java
static InputStream nullInputStream()
// 아무것도 읽지 않는 InputStream
// 반환된 스트림은 처음부터 열려 있고, 마치 스트림의 끝에 도달한 것처럼 작동한다
long transferTo(OutputStream out)
// 입력 스트림의 모든 바이트를 읽어들여 out에 쓴다
// 총 전송 바이트 수를 반환하며, 스트림을 닫는 작업은 하지 않는다
byte[] readAllBytes()
byte[] readNBytes(int len)
long skip(long n)
// 실제로 건너뛴 바이트 수를 반환. 음수 매개변수에 대해 0을 반환한다. 서브클래스들의 구현은 이와 다를 수 있다
int available()
// 막힘 없이 한 번에 읽어올 수 있는 바이트 수 예상값을 반환
// 구현에 따라 전체 바이트 수를 반환하기도, 그렇지 않기도 하다. InputStream 자체는 항상 0을 반환하며, 서브클래스에서 재정의해야 한다
boolean markSupported() // mark, reset 메서드를 지원하는지 여부 반환. 기본 false
void mark(int readlimit) // 현재 위치 마킹
void reset() // 마지막 마킹 위치로 이동
OutputStream
바이트 단위 쓰기에 대한 최상위 추상 클래스
↓ java
static OutputStream nullOutputStream()
// 실제로 데이터를 쓰지는 않는 OutputStream 객체를 반환한다
ByteArrayInputStream
내부 버퍼 byte[] buf에 대한 읽기 연산을 지원하는 InputStream
ByteArrayOutputStream
내부 버퍼 byte[] buf에 대해 쓰기 연산을 지원하는 OutputStream. 버퍼 크기는 자동으로 확장된다
↓ java
void writeTo(OutputStream out) // 버퍼를 out에 모두 쓴다. == out.write(buf, 0, count)
byte[] toByteArray() // 사본 반환
void reset() // 버퍼 처음부터 재활용
String toString(Charset charset)
PipedInputStream
PipedOutputStream를 소스로 하는 InputStream. PipedOutputStream과 별개 스레드에서 동작해야 한다
PipedOutputStream
PipedInputStream에 쓰는 OutputStream. PipedInputStream과 별개 스레드에서 동작해야 한다
FileChannel getChannel()
// 유니크한 FileChannel을 반환하며, 채널에서의 위치는 스트림에서 쓴 바이트 수와 같다(append 모드가 아닐 경우)
// append 모드에서는 파일의 크기와 채널의 위치가 동일하다
InputStream 장식자
FilterInputStream
아무 기능 추가 없는 장식자
BufferedInputStream
버퍼를 이용해 mark(), reset() 지원
DataInputStream
DataInput 구현 제공
PushbackInputStream
이미 읽은 것을 취소하고 다시 읽을 수 있는 기능을 지원한다
이전에 읽은 내용을 저장하지는 않으므로, 덮어쓰기처럼 이용할 수 있다
OutputStream 장식자
FilterOutputStream
아무 기능 추가 없는 장식자
BufferedOutputStream
버퍼를 이용해 쓰기 작업이 빈번하게 일어나지 않게 해준다
DataOutputStream
DataOutput 구현 제공
PrintStream
OutputStream, File에 기본 타입 및 각종 문자열을 쓰는 기능 제공
autoFlush : 바이트 배열을 다 쓰거나, 새 줄 문자, '\n'을 쓰면 자동으로 flush()
↓ java
boolean checkError()
// flush()한 다음 오류 상태를 검사한다. 예외를 던지지 않으므로 이 메서드로 확인해야 한다
// 스트림에 InterruptedIOException이 발생하면 Thread.currentThread().interrupt()를 실행한다
문자 단위 IO 관련
Console
JVM이 컨트롤할 수 있는 문자 기반 콘솔에 대한 접근 제공. 콘솔 존재 여부는 하위 플랫폼에 의존적이며, 싱글톤으로 System.console()을 통해 얻을 수 있다. 만일 가용한 콘솔이 없다면 null이 반환된다.
콘솔에 대한 읽기/쓰기 작업은 모두 원자적으로 이루어지며, 따라서 다른 스레드가 대기할 가능성이 있다
콘솔에 대한 close()는 아무런 영향이 없다
유닉스의 Ctrl+D, 윈도우의 Ctrl+Z와 같은 종료 문자를 만나면 읽기 메서드는 null을 반환한다
보안 유의 : 패스워드와 같은 중요한 데이터를 읽을 때, readPassword(...) 메서드를 이용하고, 반환된 char[]는 사용 후 수동으로 0 초기화
static Reader nullReader()
// 아무 것도 읽지 않는 Reader 객체를 반환한다
int read()
// char 하나를 읽고 int로 반환. 스트림의 끝이라면 -1을 반환한다
boolean ready()
// 다음 read()가 블록되지 않음을 보장하면 true, 보장하지 못하면 false
// 마킹 관련
boolean markSupported() // mark, reset 메서드를 지원하는지 여부 반환. 기본 false
void mark(int readAheadLimit) // 현재 위치 마킹
void reset() // 마지막 마킹 위치로 이동
long transterTo(Writer out)
// 모든 글자를 읽어 out에 쓴다. 전송한 글자 수를 반환한다
Writer
char 단위 쓰기에 대한 취상위 추상 클래스
Appendable하므로 편리함이 크다
↓ java
static Writer nullWriter()
// 아무것도 쓰지 않는 Writer 객체를 반환한다
void write(int c)
// 하위 16비트만 쓴고 나머지는 무시한다
InputStreamReader
InputStream에 대해 Reader 작업을 지원해주는 bridge 클래스
OutputStreamWriter
OutputStream에 Writer 작업을 지원해주는 bridge 클래스
CharArrayReader
내부 버퍼 char[] buf에 대한 읽기 연산을 지원하는 Reader
CharArrayWriter
내부 버퍼 char[] buf에 대해 쓰기 연산을 지원하는 Writer. 버퍼 크기는 자동으로 확장된다
↓ java
void writeTo(Writer out) // out에 버퍼의 모든 내용을 쓴다
void reset() // 버퍼를 처음부터 재활용
char[] toCharArray() // 사본 반환
StringReader
String을 읽는 Reader
StringWriter
StringBuffer에 쓰는 Writer
PipedReader
PipedWriter를 소스로 하는 Reader
PipedWriter
PipedReader로 쓰는 Writer
FileReader
파일을 읽는 Reader
FileWriter
파일에 쓰는 Writer
Reader 장식자
FilterReader
아무 기능 추가 없는 장식자
BufferedReader
버퍼를 이용해 mark(), reset()를 지원하고, 기저 Reader에 대한 읽기 작업이 빈번하게 일어나지 않게 해준다
LineNumberReader
줄 끝을 만날때마다 카운트
↓ java
void setLineNumber(int lineNumber) // 읽고 있는 위치가 이동하는 건 아니다
int getLineNumber()
다른 OutputStream, Writer, 파일에 기본 타입 및 각종 문자열을 쓰는 기능을 제공
PrintStream과 마찬가지로 checkError()로 실패를 확인해야 한다
파일 관련
File
추상화된 파일 및 디렉터리 경로에 대한 추상화된 표현 제공; 물리적 저장 장치 » 경로 문자열 » File 객체
경로 문자열은 절대 경로, 상대 경로 둘 다 허용된다. 상대 경로의 기준 위치는 System속성 "user.dir"로 얻을 수 있다
보다 많은 기능을 제공하는 java.nio.file 패키지가 존재한다
↓ java
public static final char separatorChar
public static final String separator
// 시스템 속성 "file.separator", UNIX : '/', Windows : '\\'
public static final char pathSeparatorChar
public static final String pathSeparator
// 시스템 속성 "path.separator", UNIX : ':', Windows : ';'
boolean mkdirs() // 경로상 필요한 모든 디렉터리들 생성
String[] list() // ls
static File[] listRoots()
static File createTempFile(String prefix, String suffix)
// (특정) 디렉터리에 새로운 빈 파일을 만들어 반환한다
// deleteOnExit()을 통해 자동으로 정리되어야 한다
// prefix : 의미 있는 접두어, suffix : null이면 ".tmp"
RandomAccessFile
읽기(DataInput)/쓰기(DataOutput) 가능한 임의 접근 파일
mode : "r" | "rw" | "rws"(파일 내용 및 메타데이터 변경을 곧바로 반영) | "rwd"(파일 내용 변경을 곧바로 반영)
읽기/쓰기의 기준 위치가 되는 file pointer가 존재
읽기로 예정된 바이트들을 모두 읽기 전에 EOF를 만나면 EOFException 발생
↓ java
long getFilePointer()
void seek(long pos) // file pointer 설정
long length()
void setLength(long newLength)
// 기존 크기 > newLength → 자르기
// getFilePointer() > newLength → file pointer = newLength
// 기존 크기 < newLength → 확장. 확장한 영역의 데이터는 초기화되지 않는다
java.lang
AutoCloseable
자동으로 자원을 해제하는 객체를 표현한다
try-with-resources 블록에 사용되면 close()가 자동으로 호출된다
IO 작업이 없는 것들을 try-with-resources 블록에 이용하는 것은 불필요한 일이다
Comparable<T>
인스턴스를 정렬하는 자연스러운 순서 정의
이를 구현한 클래스 객체들의 List, array는 Collections.sort, Arrays.sort로 각각 정렬할 수 있다
이를 구현한 클래스 객체들은 Comparator 정의 없이 SortedMap, SortedSet의 키로 이용할 수 있다
null은 객체가 아니므로 equals(null)이 false를 리턴하는 것과 달리 compareTo(null)은 NullPointerException을 내보내는 것이 바람직하다
다음 성질을 만족하도록 구현함이 권장된다
↓ java
(e1.compareTo(e2) == 0) == e1.equals(e2)
Iterable<T>
이를 구현한 클래스 객체는 enhanced for statement의 순회 대상이 될 수 있다
SecurityManager의 RuntimePermission("manageProcess")만큼의 제어 권한을 갖는다
ProcessHandle 객체들을 비교할 때는 equals, compareTo 메서드를 이용해야 한다
↓ java
ProcessHandle.Info info()
boolean supportsNormalTermination()
// destroy() 메서드가 정상적으로 프로세스를 종료하는지 여부. false면 프로세스를 강제로 즉시 종료함을 의미
CompletableFuture<ProcessHandle> onExit()
// onExit().get()을 호출하면 프로세스가 종료되는 것을 기다린다
// supportsNormalTermination()이 false일 경우 onExit()에 등록한 후처리들이 진행되지 않을 수 있음
boolean destroy()
// 프로세스 종료에 시간이 걸릴 수 있으므로, isAlive()가 얼마간 true를 반환할 수 있다
// 성공적으로 프로세스를 종료하면 true, 아니면 false를 반환한다
boolean destroyForcibly() // 강제 종료
long pid()
boolean isAlive() // PID가 유효하면 alive로 간주
ProcessHandle.Info
↓ java
Optional<String> command() // 실행가능한 경로 반환
Optional<String> commandLine() // command()와 arguments()의 결과를 공백으로 구분한 결과 반환
Optional<String[]> arguments() // 프로세스의 인자 반환
Optional<Instant> startInstant() // 프로세스의 시작 시각 반환
Optional<Duration> totalCpuDuration() // CPU 사용 시간 반환
Optional<String> user() // 프로세스 유저 반환
Math, StrictMath
↓ java
static double IEEEremainder(double f1, double f2)
static double rint(double d) // round to even
// 오버플로우되면 예외
addExact, substractExact, multiplyExact, incrementExact, decrementExact, negateExact, toIntExact
static long multiplyFull(int x, int y)
static long multiplyHigh(long x, long y) // 상위 64개 비트를 반환
floorDiv(x, y)
// x/y 이하 최대 정수
// Integer.MIN_VALUE, Long.MIN_VALUE를 -1로 나누는 경우는 오버플로우가 발생하고, 각각 Integer.MIN_VALUE, Long.MIN_VALUE를 반환한다
floorMod(x, y)
// x - (floorDiv(x, y) * y)를 반환한다. 부호는 y와 같다
fma(a, b, c)
// a * b + c에 가장 가까운 float, double을 반환
공유 변수 관련
ClassValue<T>
임의 타입에 대하여, 필요할 때에 연산된 값을 가져오도록 지원. 해당 값은 해당 타입에 대해 일관성을 갖는다
↓ java
protected abstract T computeValue(Class<?> type)
// type에 대하여, 최초 get 메서드 호출 시 한 번만 호출되며, 이후 remove 메서드 호출이 없으면 더 이상 불리지 않는다
T get(Class<?> type)
// 값이 계산되지 않은 상태에서 여러 스레드들이 경합을 벌일 경우, 임의 스레드의 결과값을 모두에 반환한다
void remove(Class<?> type)
// 다음 get 호출 시 값을 새로 계산하도록 한다
ThreadLocal<T>
스레드 단위의 지역 변수를 제공한다. 호출 지점과 관계없이 한 스레드 내부에서 변수를 공유한다
↓ java
protected T initialValue()
// 초기값이 설정되지 않은 상태에서 최초 get() 호출에 의해 불린다. remove() 호출 후의 get() 요청으로 다시 불린다
static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)
// supplier로 초기값이 설정되는 ThreadLocal 반환
InheritableThreadLocal<T>
ThreadLocal에 상속성을 부여. 자식 스레드는 부모의 thread-local 변수들을 초기값으로 상속받고 시작한다. childValue 메서드를 재정의함으로써 부모의 값과 다르게 설정할 수도 있다
타입 관련
각 래퍼 클래스의 TYPE 필드는 기본 타입 클래스 인스턴스를 가리킨다
e.g. Boolean.TYPE == boolean.class
각 래퍼 클래스의 valueOf() 함수는 기본 타입에 대해 래핑을 수행하며, 일부는 캐싱을 이용해 빠르게 수행한다
static int highestOneBit(X i) // + lowestOneBit
static int numberOfLeadingZeros(X i) // + numberOfTrailingZeros
static int bitCount(X i)
static X rotateLeft(X i, int distance) // + rotateRight
static X reverse(X i)
static X reverseBytes(X i) // 바이트 단위로 뒤집기
정수 래퍼 클래스들은 아래와 같은 String 파싱을 제공한다
↓ java
static Z parseZ(String s, int radix)
static Z valueOf(String s, int radix)
// 예외
// s가 null이거나 길이가 0
// s에 radix진수가 아닌 문자가 포함(단, s가 2글자 이상일 때 첫 '-', '+'는 가능)
// radix가 [Character.MIN_RADIX, Character.MAX_RADIX] 범위를 벗어날 때
// 값이 Z를 벗어날 때
static Z decode(String nm)
// 다음 문법으로 표현된 10진수, 16진수, 8진수를 parseZ()를 이용해 디코딩한다. 공백 비허용
// (Sign?)(10진수)
// (Sign?)(0x | 0X | #)(16진수)
// (Sign?)0(8진수)
// Sign: '-', '+'
정수 래퍼 클래스들은 몇몇 unsigned 함수를 제공한다
↓ java
static int compareUnsigned(Z x, Z y)
static Z divideUnsigned(Z dividend, Z divisor)
static Z parseUnsigned(...)
static Z remainderUnsigned(Z dividend, Z divisor)
static int toUnsignedInt(Z x)
static long toUnsignedLong(Z x)
static String toUnsignedString(Z i)
CharSequence
일련의 char 값들을 표현
equals(), hashCode()에 대한 규약이 없어, set이나 map의 키로 이용하기에 부적절하다
↓ java
static int compare(CharSequence cs1, CharSequence cs2)
// 사전순으로 비교
default IntStream chars()
// char들을 int로 0패딩하여 스트림 생성. 두 char로 쪼개진 유니코드 보충 평면의 문자를 하나로 합치진 않는다
default IntStream codePoints()
// 유니코드 값들을 스트림으로 생성. 보충 평면의 문자는 Character.toCodePoint 메서드를 통해 하나의 int 값으로 형성
Character
문자 집합(소문자, 숫자 등) 정의, 변환 기능을 제공한다
유니코드 표준을 따른다
유효한 범위는 U+0000(MIN_CODE_POINT)부터 U+10FFFF(MAX_CODE_POINT)까지(== Unicode scalar value)
[U+0000, U+FFFF] == 기본 문자 평면(BMP; Basic Multilingual Plane)
[U+10000 == MIN_SUPPLEMENTARY_CODE_POINT, ~) == 보충 문자 평면(supplementary characters)
자바 플랫폼은 보충 평면의 문자들은 2개의 char의 쌍으로 표현한다
이때 첫번째 char는 high-surrogate([MIN_HIGH_SURROGATE, MAX_HIGH_SURROGATE]), 두번째 char는 low-surrogate([MIN_LOW_SURROGATE, MAX_LOW_SURROGATE]) 범위 안의 값이다
하위 21개 비트를 이용하여 int 하나로 모든 유니코드 code point를 표현할 수 있다
int를 받는 메서드는 모든 유니코드를 처리할 수 있지만, char만을 받는 메서드는 보충 평면 문자를 처리하지 못한다
↓ java
static String getName(int codePoint)
// 이름 반환 : Character.UnicodeBlock.of(codePoint).toString().replace('_', ' ') + " " + Integer.toHexString(codePoint).toUpperCase(Locale.ROOT);
// 정의되어 있지 않으면 null
static int codePointOf(String name)
// 정의되어 있지 않으면 예외
static boolean isValidCodePoint(int codePoint)
// + isBmpCodePoint, isSupplementaryCodePoint, isHighSurrogate, isLowSurrogate
static int getType(int codePoint)
static byte getDirectionality(char ch)
// 문자 표시 순서 : DIRECTIONALITY_UNDEFINED, DIRECTIONALITY_LEFT_TO_RIGHT 등
static boolean isMirrored(char ch)
// 좌우 대칭되는 문자가 존재하는지 여부
static boolean isDigit(char ch)
// getType(ch) == DECIMAL_DIGIT_NUMBER
static boolean isLetter(char ch)
// getType(ch) == *_LETTER, isLetterOrDigit
static boolean isAlphabetic(int codePoint)
// UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, OTHER_LETTER, LETTER_NUMBER, 및 기타 알파벳 문자인지 여부
static boolean isSpaceChar(char ch)
// getType(ch) == *_SEPARATOR
static boolean isWhitespace(char ch)
// 공백 문자 '\t', '\n', 'u000B', '\f', '\r', '\u001C', '\u001D', '\u001E', '\u001F'
// 단, non-breaking space('\u00A0', '\u2007', '\u202F') 제외
static int charCount(int codePoint)
// 표현에 필요한 char 수(1 or 2)
static char[] toChars(int codePoint)
static String toString(int codePoint)
static int toCodePoint(char high, char low)
static int codePointAt(CharSequence seq, int index)
// + codePointBefore, highSurrogate, lowSurrogate
static int codePointCount(CharSequence seq, int beginIndex, int endIndex)
// [beginIndex, endIndex) 사이의 유니코드 문자 수 반환
static int offsetByCodePoints(CharSequence seq, int index, int codePointOffset)
// 지정된 index로부터 offset 개수만큼 유니코드를 건너뛴 위치. +일 경우 index 포함, -인 경우 index 미포함(예시 코드 참고)
static int toLowerCase(int codePoint)
// + toUpperCase, toTitleCase
// isLowerCase(toLowerCase(x))가 항상 true는 아니다
static int digit(int codePoint, int radix)
static char forDigit(int digit, int radix)
static int getNumericValue(int codePoint)
Double
↓ java
public static final double POSITIVE_INFINITY // Double.longBitsToDouble(0x7ff0000000000000L)
public static final double NEGATIVE_INFINITY // Double.longBitsToDouble(0xfff0000000000000L)
public static final double NaN // Double.longBitsToDouble(0x7ff8000000000000L)
public static final double MAX_VALUE // Double.longBitsToDouble(0x7fefffffffffffffL), 0x1.fffffffffffffP+1023
public static final double MIN_NORMAL // Double.longBitsToDouble(0x0010000000000000L), 0x1.0p-1022
// 진수가 1 이상인 가장 작은 양수 표현
public static final double MIN_VALUE // Double.longBitsToDouble(0x1L), 0x0.0000000000001P-1022
// 가장 작은 양수 표현
static String toHexString(double d)
static long doubleToLongBits(double value)
// double 표현 그대로 long으로 전환. 63번 비트는 부호, 62-52번 비트는 지수, 51-0번 비트는 진수
static long doubleToRawLongBits(double value)
// NaN의 경우 각각의 NaN에 대응하는 값으로 반환
static double longBitsToDouble(long bits)
// NaN : [0x7ff0000000000001L, 0x7fffffffffffffffL] or [0xfff0000000000001L, 0xffffffffffffffffL]
int compareTo(Double anotherDouble)
// Double.NaN > Double.POSITIVE_INFINITY
// 0.0d > -0.0d
Integer
↓ java
static String toString(int i, int radix)
// + toUnsignedString, toBinaryString, toOctalString, toHexString
String
로캐일을 고려한 문자열 비교는 Collator 클래스를 이용하면 된다
↓ java
static final Comparator<String> CASE_INSENSITIVE_ORDER
// 대소문자 구분없는 비교자. 직렬화 가능
static String format(String format, Object... args)
String formatted(Object... args)
static String valueOf(Object obj)
boolean isEmpty() // 길이가 0인지 여부
boolean isBlank() // 비거나 공백 문자로만 이루어졌는지 여부
byte[] getBytes(Charset charset)
// 문자셋이 지정되지 않은 경우, 플랫폼 기본 문자셋을 이용한다. 기본 문자셋을 변경하려면 JVM 옵션을 조정하면 된다
// 비교
boolean contentEquals(StringBuffer sb)
boolean equalsIgnoreCase(String anotherString)
int compareToIgnoreCase(String str)
boolean regionMatches(int tooffset, String other, int ooffset, int len)
// 부분 문자열이 일치하는지 여부 반환. t(his's)offset, o(ther's)offset
boolean startsWith(String prefix, int toffset)
boolean endsWith(String suffix)
// 검색
int indexOf(String str, int fromIndex) // + lastIndexOf
boolean matches(String regex) // == Pattern.matches(regex, str)
boolean contains(CharSequence s)
String replaceAll(String regex, String replacement) // + replaceFirst
String replace(CharSequence target, CharSequence replacement)
String[] split(String regex, int limit)
// limit이 음수인 경우, 제한 없이 분리. 0인 경우 빈 문자열로 끝나지 않음
static String join(CharSequence delimiter, CharSequence... elements)
String trim() // 시작과 끝의 공백(<= U+0020) 제거
String strip() // + stripLeading, stripTrailing. 공백 제거
Stream<String> lines() // 줄 끝(\n, \r, \r\n) 기준으로 분리
String indent(int n) // 각 줄이 n개의 공백으로 시작하도록 조정하고, 줄 끝을 \n로 정규화한다. n이 음수인 경우, 최대 n개의 앞선 공백을 제거한다
String stripIndent() // 모든 줄이 공유하는 불필요한 들여쓰기 제거
<R> R transform(Function<? super String, ? extends R> f)
String repeat(int count)
StringBuffer
스레드-안전한 변경 가능한 문자열
↓ java
void trimToSize()
// 버퍼 크기를 줄여 문자열 크기에 맞춘다
void setLength(int newLength)
// 새로운 크기의 문자열에 기존 문자열을 복사. 남는 부분은 '\u0000'(null)로 채워진다
void ensureCapacity(int minimumCapacity)
StringBuffer reverse()
StringBuilder
StringBuffer의 비동기화 버전
클래스 관련
Class<T>
↓ java
// ClassLoader 관련
ClassLoader getClassLoader()
InputStream getResourceAsStream(String name)
URL getResource(String name)
static Class<?> forName(String name, boolean initialize, ClassLoader loader)
// 타입 관련
T cast(Object obj)
// obj를 호출한 Class 객체와 같은 타입으로 변환
boolean isInstance(Object obj)
// instanceof 연산자의 동적인 형태. 원시타입 클래스 객체는 false만 반환한다
boolean isAssignableFrom(Class<?> cls)
// cls 타입 객체를 현재 클래스의 참조 변수로 참조할 수 있는지 여부 반환
boolean isInterface()
// + isArray, isPrimitive, isAnnotation, isEnum, isAnonymousClass, isLocalClass, isMemberClass, isRecord
// wrapper 클래스는 원시타입이 아님에 유의 : Integer.class != Integer.TYPE == int.class
// 클래스 이름 관련
String toGenericString()
// 접근한정자 및 타입 포함하여 반환
String getName()
// 배열의 경우 차원마다 '['를 붙이며, 배열 원소 타입을 아래와 같이 인코딩한다
// boolean : Z, byte : B, char : C, class : L{className};, double : D, float : F, int : I, long : J, short : S
String getSimpleName()
// 익명 클래스면 빈 문자열 반환
String getCanonicalName()
// Local class, 익명 클래스, 또는 이들의 배열은 canonical name이 없어 null을 반환한다
// 리플렉션 관련
Class<?>[] getClasses()
// public 멤버로 정의된 클래스, 인터페이스 Class 객체 배열 반환
// + getFields, getMethods, getConstructors
Class<?>[] getDeclaredClasses()
// 상속된 것을 제외하고, 호출하는 클래스 내부에 정의된 public, protected, default, private 클래스와 인터페이스들을 반환한다
// + getDeclaredFields, getDeclaredMethods, getDeclaredConstructors
Class<?> getComponentType()
// 배열 원소 타입 클래스 객체 반환. 배열이 아닌 경우 null 반환
Method getEnclosingMethod()
// 이 클래스가 메서드 내부에서 정의된 경우, 해당 메서드를 반환한다
// + getEnclosingConstructor, getDeclaringClass, getEnclosingClass
<A extends Annotation> A getAnnotation(Class<A> annotationClass)
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// record 관련
RecordComponent[] getRecordComponents()
Nest
Nest는 같은 런타임 패키지 안의, private member에 접근 가능한 클래스와 인터페이스의 집합
Nest에 속한 클래스, 인터페이스를 nestmate라 부르고, 하나의 nest에서 하나의 nestmate는 host 역할을 하고 나머지 nestmate 목록을 갖는다
↓ java
Class<?> getNestHost()
Class<?>[] getNestMembers()
boolean isNestmateOf(Class<?> c)
ClassLoader
전형적으로, 로드할 클래스 이름을 파일명으로 변환하여 ".class"파일을 읽어온다
모든 Class 객체들은 ClassLoader에 대한 참조를 갖고 있다
배열의 경우 런타임에 Class 객체가 생성되며, 이때 Class.getClassLoader()는 원소의 것과 동일하다
클래스를 로드하는 것 외에, 자원(.class 파일, 구성 파일, 이미지 등)을 배치하는 책임도 진다
Delegation model : ClassLoader 객체들은 각기 parent class loader를 갖는다. 클래스나 자원을 찾기 전에 parent를 먼저 조사하게 된다
동시 로딩을 지원하는 parallel capable class loader들은 클래스 초기화 시 registerAsParallelCapable()를 통해 등록해야 한다. ClassLoader 클래스는 기본적으로 등록되나, 서브클래스들도 자신을 등록해야 한다
계층구조가 약한 delegation model의 경우 클래스 로더들이 parallel capable하지 않으면 deadlock 발생 가능성이 있다
Run-time Built-in Class Loaders
Bootstrap class loader : JVM 내장 클래스 로더. 보통 null이며, parent가 없다
Platform class loader : Java SE APIs, JDK-specific run-time classes
System class loader, a.k.a Application class loader : Used to define classes on the application class path, module path, and JDK-specific tools
파일이 아닌 네트워크 같은 다른 소스로부터 클래스를 로드할 경우, defineClass()를 통해 Class 객체를 얻고 Constructor.newInstance()를 통해 클래스 객체를 생성하면 된다
네트워크 클래스 로더는 findClass(), loadClassData() 메서드를 반드시 작성해야 한다
↓ java
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) { /**/ }
Binary names
ClassLoader 메서드에 전달하는 String 타입 클래스 이름은 아래와 같은 형식을 따라야 한다
"java.lang.String"
"javax.swing.JSpinner$DefaultEditor"
"java.security.KeyStore$Builder$FileBuilder$1"
"java.net.URLClassLoader$3$1"
↓ java
static ClassLoader getPlatformClassLoader()
static ClassLoader getSystemClassLoader()
// 시스템 클래스 로더를 반환하며, 이는 새롭게 정의되는 클래스 로더들의 default delegation parent다
Class<?> loadClass(String name)
// == loadClass(name, false)
protected Class<?> loadClass(String name, boolean resolve)
// 1. findLoadedClass(String)로 이미 로드됐나 확인
// 없으면 : parent 혹은 VM의 클래스 로더의 loadClass를 호출
// 없으면 : findClass(String) 호출
// 2. 위를 통해 클래스를 찾았고, resolve가 true면 resolveClass(Class) 호출
// 3. ClassLoader의 서브클래스들은 이 메서드가 아닌 findClass(String)을 재정의하면 된다
// 4. 재정의되지 않은 이상, getClassLoadingLock()을 통해 메서드는 동기화된다
protected final void resolveClass(Class<?> c)
// 클래스를 링크(초기화)한다
// 리소스 관련
? *Resource*(String name)
// name은 '/'으로 구분된 경로
스레드는 실행 우선순위를 가지며, 그 초깃값은 스레드를 생성한 스레드의 것과 같다. 데몬 스레드로부터 생성된 스레드도 데몬 스레드다
JVM이 시작되면 하나의 non-daemon 스레드가 존재하며, 전형적으로 main 메서드를 호출한다. JVM은 다음의 상황 중 하나라도 일어나기 전까지 실행을 계속한다
Runtime 클래스의 exit 메서드 호출, 또는 SecurityManager의 exit 허용
모든 데몬 스레드가 아닌 스레드들의 종료 : run 메서드의 반환이든 예외 발생이든 관계없이
↓ java
public static final int MIN_PRIORITY
public static final int NORM_PRIORITY
public static final int MAX_PRIORITY
final void setDaemon(boolean on)
// 스레드를 daemon 또는 user 스레드로 변경. 스레드가 시작되기 전에 호출돼야한다
// user 스레드가 하나도 없으면 프로그램은 종료된다
void start() // JVM이 run() 호출. 스레드를 재시작하는 것은 허용되지 않는다
void run() // 관련된 Runnable의 run() 호출
void interrupt()
// 1. checkAccess()가 호출된다. wait, join, sleep으로 블록된 경우 인터럽트 상태가 초기화되고, InterruptedException 발생
// 2. InterruptibleChannel로 I/O 작업 중 블록된 경우, 인터럽트 상태가 설정되고 채널은 닫힌다. ClosedByInterruptException 발생
// 3. Selector에서 블록된 경우, 인터럽트 상태가 설정되고 selection 연산에서 즉시 반환된다. 그 외의 경우 인터럽트 상태가 설정된다
static Thread currentThread()
ClassLoader getContextClassLoader()
long getId()
Thread.State getState()
static boolean interrupted() // 현재 스레드가 인터럽드됐는지 여부. 스레드의 인터럽트 상태는 이 메서드로 인해 초기화된다
boolean isInterrupted() // 스레드의 인터럽트 상태를 변경하지 않고 반환한다
final boolean isAlive()
final void join(long millis) // 이 스레드가 중지되기까지 일시 대기. 0이면 무기한 대기. 지정 되지 않은 경우 0
static void dumpStack()
// 현재 스레드의 스택 추적을 표준 에러 출력
final void checkAccess()
// 현재 스레드가 이 스레드를 변경할 수 없으면 SecurityException 발생
static boolean holdsLock(Object obj)
// 특정 객체를 lock으로 갖는지 확인
static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
static void onSpinWait()
Spin-wait 루프에서 조건이 충족되어 루프를 벗어나기를 기다린다
↓ java
class EventHandler {
volatile boolean eventNotificationNotReceived;
void waitForEventAndHandleIt() {
while ( eventNotificationNotReceived ) {
java.lang.Thread.onSpinWait();
}
readAndProcessEvent();
}
void readAndProcessEvent() {
// Read event from some source and process it
...
}
}
처리되지 않은 예외로 인해 스레드가 종료되는 상황을 대비한 핸들러. 그러한 상황에서, 먼저 Thread.getUncaughtExceptionHandler()를 통해 얻은 핸들러에 해당 스레드와 예외 객체를 전달한다
만일 스레드에 핸드러가 설정되지 않은 경우, ThreadGroup의 핸들러를 이용하며, ThreadGroup에도 없는 경우 default 핸들러를 이용할 수 있다
Process
ProcessBuilder.start, Runtime.exec으로 시작된 native process들에 대한 제어 제공
↓ java
abstract OutputStream getOutputStream()
// + getInputStream, getErrorStream
abstract int waitFor()
// 현재 스레드가 이 프로세스의 종료를 기다린다. 프로세스의 종료 값을 반환
boolean waitFor(long timeout, TimeUnit unit)
// 시간 내에 프로세스가 종료되었다면 true 반환
abstract int exitValue()
abstract void destroy() // 정상 종료
Process destroyForcibly() // 강제, 즉시 종료
boolean isAlive()
long pid()
boolean supportsNormalTermination()
CompletableFuture<Process> onExit()
ProcessHandle toHandle()
ProcessHandle.Info info()
Stream<ProcessHandle> children()
Stream<ProcessHandle> descendants()
ProcessBuilder
이 클래스는 스레드-안전하지 않다
↓ java
ProcessBuilder command(String... command)
ProcessBuilder directory(File directory)
ProcessBuilder redirectInput(ProcessBuilder.Redirect source)
// + redirectOutput, redirectError
ProcessBuilder inheritIO()
ProcessBuilder redirectErrorStream(boolean redirectErrorStream)
// true면 서브프로세스들의 에러 출력이 표준 출력으로 나온다
Process start()
static List<Process> startPipeline(List<ProcessBuilder> builders)
// 프로세스들의 표준 출력을 다음 프로세스의 표준 입력으로 연결한다
ProcessBuilder.Redirect
서브프로세스의 입력 소스 또는 출력 방향을 표현한다
↓ java
public static final ProcessBuilder.Redirect PIPE // 현재 프로세스와 파이프로 연결
public static final ProcessBuilder.Redirect INHERIT // 현재 프로세스의 것과 동일
public static final ProcessBuilder.Redirect DISCARD // 출력 버림
static ProcessBuilder.Redirect from(File file)
static ProcessBuilder.Redirect to(File file) // file의 이전 내용은 새로운 쓰기 작업에 의해 버려진다
static ProcessBuilder.Redirect appendTo(File file)
static Runtime getRuntime()
void exit(int status)
// 현재 실행중인 JVM을 종료
void addShutdownHook(Thread hook)
// + removeShutdownHook
// JVM이 종료 절차에 진입하면 등록된 모든 hook를 실행
void halt(int status)
// 강제종료
Process exec(String[] cmdarray, String[] envp, File dir)
int availableProcessors()
long freeMemory()
// + totalMemory, maxMemory
void gc()
void runFinalization()
// 소멸 대기중인 모든 객체 소멸
System
↓ java
public static final InputStream in // + out, err
static void setIn(InputStream in) // + setOut, setErr
static long currentTimeMillis() // + nanoTime
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
static int identityHashCode(Object x)
static String lineSeparator()
static void setProperties(Properties props) // getProperties
static String setProperty(String key, String value)
static String clearProperty(String key)
static String getenv(String name) // 환경변수
static void exit(int status)
StackWalker
현재 스레드의 StackFrame에 대한 스트림을 열고 특정 작업을 수행한다. 스트림은 실행 지점인 맨 위 frame부터 아래로 내려가면서 작업한다
↓ java
static StackWalker getInstance(...)
// 기본 설정 : 숨겨진 프레임 생략. 클래스 정보 미포함
<T> T walk(Function<? super Stream<StackWalker.StackFrame>, ?
// 예. 현재 스레드의 상위 10개 스택 프레임 가져오기
StackWalker.getInstance().walk(s -> s.limit(10).collect(Collectors.toList()));
void forEach(Consumer< super StackWalker.StackFrame> action)
Class<&?> getCallerClass()
// 이 메서드를 호출하는 호출자의 클래스 객체를 반환
// Util::getResourceBundle 메서드는 이 메서드를 통해 얻은 호출자의 클래스로부터 클래스 로더를 얻고, 클래스 로더를 통해 리소스를 로드한다
StackWalker.Option
↓ java
RETAIN_CLASS_REFERENCE // StackFrame에 클래스 정보 유지
SHOW_HIDDEN_FRAMES // 숨겨진 프레임 표시
SHOW_REFLECT_FRAMES // reflection 프레임 표시
다른 객체(referent)를 참조하는 reference object를 이용해 GC 절차 일부와 상호작용할 수 있다
3단계의 참조 레벨을 제공한다 : Soft > Weak > Phantom
Strongly reachable
Reference object 없이 객체에 직접 접근 가능한 스레드가 존재
e.g. 객체를 생성한 스레드, 객체를 매개변수로 받아 실행 중인 스레드 등
Softly reachable
Not strongly reachable && Soft reference object가 객체를 참조 중
마지막으로 strongly reachable한 이후 기간, 여유 힙 크기, JVM 옵션(-XX:SoftRefLRUPolicyMSPerMB)에 따라 GC 여부가 결정된다
ReferenceQueue를 지정한 경우, GC 대상으로 판별된 즉시(약간의 지연은 있을 수 있다) 등록된다
Weakly reachable
Not strongly reachable && Not softly reachable && Weak reference object가 객체를 참조 중
Referent는 GC 대상이며, 따라서 get()은 null을 반환할 수 있다
ReferenceQueue를 지정한 경우, GC 대상으로 판별된 즉시(약간의 지연은 있을 수 있다) 등록된다
Phantom reachable
Not strongly reachable && Not softly reachable && Not weakly reachable && 객체는 소멸(finalize)됐지만 Phantom reference object가 참조 중
Finalization 이후 ReferenceQueue에 등록된다
객체 소멸 감지를 위해 존재하므로, get()은 항상 null을 반환한다
ReferenceQueue에서 꺼낸 뒤, 메모리 해제를 위해 clear()를 호출해야 한다
Unreachable
참조 불가능하며, 따라서 GC 대상이 된다
Cleaner
객체 참조와 관련 정리 작업을 관리한다
객체가 phantom reachable 상태로 변했음을 통지받으면 정리 작업이 실행된다. 참조 레벨의 변경을 통지받기 위해 PhantomReference와 ReferenceQueue를 이용한다
객체 참조와 정리 작업을 등록하면 Cleanable 인스턴스가 반환된다
가장 효과적인 사용법은 객체의 close() 메서드나, 객체가 필요없는 시점에 명시적으로 clean()을 호출하는 것
등록하는 객체를 객체 정리 작업이 참조하면 안 된다
참조하는 경우, 객체는 Phantom reachable 레벨에 도달할 수 없고, 따라서 자동으로 정리 작업이 호출될 수 없다
정리 작업은 Runnable이며, 실행 중 발생하는 모든 예외는 무시된다. 발생한 예외는 Cleaner와 다른 정리 작업에 영향을 미치지 않는다 Cleaner 인스턴스와 관계된 스레드가 정리 작업을 실행하며, 모든 정리 작업이 실행된 후엔 Cleaner 인스턴스가 GC에 의해 정리된다
void clean()
// cleanable을 등록 취소하고 정리 작업을 실행한다. 반복 호출되도 정리 작업은 최대 1번만 실행된다
ReferenceQueue<T>
참조 큐. 참조 레벨 변화를 감지하면 GC가 reference object를 큐에 추가한다
↓ java
Reference<?
// reference object가 즉시 사용 가능하면 큐에서 제거하고 반환한다. 그 외의 경우 즉시 null을 반환한다
Reference<?
// 다음 reference object를 규에서 제거하고 반환한다. 그 다음 reference object가 사용 가능해질 때까지 최대 timeout 만큼 대기한다
Reference<T>
GC와 상호작용하기 위한 메서드들을 정의한다. 이 클래스를 직접 상속하지 않아야 한다
↓ java
static void reachabilityFence(Object ref)
// ref가 가리키는 객체를 strongly reachable하게 고정하여
// 적어도 이 메서드 호출이 끝날 때 까지는 GC 대상이 아니게 한다
T get() // referent를 반환한다(즉, hard reference)
final boolean refersTo(T obj) // referent == obj ?
void clear()
boolean enqueue() // clear() 후 지정된 큐에 넣는다
class SoftReference<T> extends Reference<T>
class WeakReference<T> extends Reference<T>
class PhantomReference<T> extends Reference<T>
java.lang.reflect
자바 제네릭 제약사항
자바의 제네릭은 컴파일 과정에서 모두 Object 또는 바운드된 클래스로 교체(type erasure)된다
따라서 List<T> 참조 변수만 가지고 T가 어떤 타입인지 런타임에 알아내는 방법은 없다
다만, 원소가 존재한다면 instanceof, Class::isInstanse, Class::isAssignableFrom을 이용한 판별은 가능하다
따라서 제네릭 타입에 대한 직접적인 연산은 모두 무효하다
제네릭에 대한 익명 클래스는 정의에 사용된 타입 인자를 알 수 있다
↓ java
(ParameterizedType) new ArrayList<String>().getClass().getGenericSuperclass();
// java.util.AbstractList<E>
((ParameterizedType) new ArrayList<String>().getClass().getGenericSuperclass()).getActualTypeArguments()[0];
// E
(ParameterizedType) new ArrayList<String>() {}.getClass().getGenericSuperclass();
// java.util.ArrayList<java.lang.String>
((ParameterizedType) new ArrayList<String>() {}.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
// class java.lang.String
Modifier
↓ java
public static final int PUBLIC, PRIVATE, PROTECTED, STATIC,
FINAL, SYNCHRONIZED, VOLATILE, TRANSIENT,
NATIVE, INTERFACE, ABSTRACT, STRICT
static int classModifiers()
// 사용할 수 있는 제한자들을 OR하여 반환
// + interfaceModifiers, constructorModifiers, ...
지원 타입 종류
↓ java
interface Type // 모든 타입의 공통 super interface
interface ParameterizedType extends Type // Collection<String>처럼 파라미터화된 타입을 표현
interface GenericArrayType extends Type // 원소 타입이 parameterized type 또는 type 변수인 배열 타입을 표현
interface WildcardType extends Type // ?, ? extends Number, ? super Integer와 같은 와일드카드 타입을 표현
interface AnnotatedElement // 애너테이트된 요소를 표현
interface AnnotatedType extends AnnotatedElement {
default AnnotatedType getAnnotatedOwnerType();
// 이 타입을 멤버로 갖는, 애너테이트된 타입 반환.
// e.g. 이 타입이 @XXX O<T>.I<S>라면, @XXX O<T>를 반환
// null이 반환되는 경우 ↓
// 타입이 top-level이거나 local 클래스, 익명 클래스, 기본 자료형, void인 경우
// 타입이 AnnotatedArrayType, AnnotatedTypeVariable, AnnotatedWildcardType의 인스턴스인 경우
Type getType();
// 이 애너테이트된 타입의 기저 타입
}
interface AnnotatedArrayType extends AnnotatedType // 원소가 애너테이트된 배열을 표현
interface AnnotatedParameterizedType extends AnnotatedType // 타입 인자들이 애너테이트된 parameterized type을 표현
interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement // 타입 변수에 관한 공통 superinterface
interface GenericDeclaration extends AnnotatedElement // 모든 타입 변수 정의들에 대한 공통 인터페이스
interface AnnotatedTypeVariable extends AnnotatedType // 애너테이트된 바운드를 가진 타입 변수를 표현
interface AnnotatedWildcardType extends AnnotatedType // 애너테이트된 upper 또는 lower 바운드들에 대한 와일드카드 타입을 표현
클래스 멤버 관련
Member
하나의 멤버(필드나 메서드) 또는 생성자를 가리킨다
↓ java
boolean isSynthetic() // 컴파일러에 의해 만들어진 멤버인지 여부
AccessibleObject
Field, Method, Constructor의 base 클래스. 리플렉트된 객체를 사용하기 전에 suppressing check 표시한다
↓ java
void setAccessible(boolean flag)
static void setAccessible(AccessibleObject[] array, boolean flag)
// 배열의 각 원소들을 setAccessible(boolean)으로 설정할 수 있을 때, 한번에 하기 위한 메서드
final boolean canAccess(Object obj)
final boolean trySetAccessible()
// accessible flag 값을 반환한다. 실패할 경우 예외를 발생하지 않고 false를 반환
Proxy는 인터페이스 익명 객체처럼 행동하면서 사용자 정의 메서드를 호출할 수 있는 객체를 생성하는 static 메서드를 제공한다
↓ java
// 예. 인터페이스 Foo의 프록시 인스턴스 생성
InvocationHandler handler = new MyInvocationHandler(...);
var f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[] { Foo.class }, handler);
프록시 클래스 속성
"$Proxy"로 이름이 시작. final and non-abstract. java.lang.reflect.Proxy를 상속. 생성시 주어진 인터페이스들을 차례대로 구현. ProtectionDomain은 bootstrap 클래스 로더가 로드한 시스템 클래스들과 동일
public static final BigDecimal ZERO, ONE, TEN
public BigDecimal(String val)
// val ::= (부호)?(진수부)(지수부)?
// 진수부 ::= 정수부.(소수부) or .소수부 or 정수부
// 지수부 ::= (e|E)정수
BigDecimal add(BigDecimal augend) // + subtract, multiply, divide
BigDecimal divideToIntegralValue(BigDecimal divisor) // 몫
BigDecimal remainder(BigDecimal divisor) // 나머지
BigDecimal[] divideAndRemainder(BigDecimal divisor)
// + sqrt, pow, abs, negate, scale, precision, unscaledValue, round, movePointRight, scaleByPowerOfTen, ...
BigInteger
변경할 수 없는 임의 길이의 정수. -2^(Integer.MAX_VALUE) ~ 2^(Integer.MAX_VALUE)
↓ java
public static final BigInteger ZERO, ONE, TWO, TEN
public BigInteger(int signum, byte[] magnitude, int off, int len)
public BigInteger(String val, int radix)
public BigInteger(int numBits, Random rnd) : [0 ~ 2^numBits) 사이 난수
public BigInteger(int bitLength, int certainty, Random rnd)
// rnd를 통해 난수를 생성하고, 특정 비트 길이의 양의 정수(아마도 소수) 반환. 소수일 확률은 (1 - 0.5^certainty) 초과
static BigInteger probablePrime(int bitLength, Random rnd)
// 합성수일 가능성은 2^(-100)을 넘지 않는다
BigInteger nextProbablePrime()
// 이 BigInteger보다 큰 첫 소수(아마도)를 반환한다. 합성수일 가능성은 2^(-100)을 넘지 않는다
// BigDecimal에는 없는 메서드
sqrtAndRemainder(), gcd(BigInteger), modPow(BigInteger, BigInteger), shiftLeft(int), and(BigInteger), testBit(int), setBit(n), flipBit(int)
MathContext
정밀도, 반올림 모드를 캡슐화한 변경 불가능한 객체
↓ java
public static final MathContext UNLIMITED
// precision=0 && roundingMode=HALF_UP
public static final MathContext DECIMAL32, DECIMAL64, DECIMAL128
// 각각 7/16/34digits && roundingMode=HALF_EVEN
int getPrecision()
RoundingMode getRoundingMode()
RoundingMode
CEILING, FLOOR, UP : 0에서 멀어지도록 선택
DOWN : 0에 가까워지도록 선택
HALF_UP, HALF_DOWN, HALF_EVEN : 가장 인접한 두 이웃들이 같은 거리에 있는 경우(.5인 경우), 각각 큰/작은/짝수 이웃을 선택
UNNECESSARY : 올림이나 내림이 필요없는 상태. 그 외엔 ArithmeticException 발생
java.net
Address
InetAddress
IP 주소를 표현하며, IPv4, IPv6 각각에 대응하는 서브 클래스가 있다. 서브 클래스를 직접 이용하는 일은 별로 없을 거라고 한다
public InetSocketAddress(int port) // port가 0이면 바인드시 자동 할당
public InetSocketAddress(InetAddress addr, int port) // addr이 null이면 와일드카드 할당
public InetSocketAddress(String hostname, int port)
Registry-based authority : not server-based authority
Operations on URI instances
Normalization : "."과 ".."을 제거
Resolution : 상대 URI와 base URI를 이용해 단일 URI를 찾는 작업
Relativization : Resolution의 역
임의의 정규화된 두 URI u, v에 대하여, u.relativize(u.resolve(v)).equals(v)와 u.resolve(u.relativize(v)).equals(v)는 항상 성립한다
URL
인스턴스 생성 시, URI와 다르게, 정의된 scheme에 대한 핸들러를 찾기 때문에, 핸들러를 찾지 못하면 예외가 발생한다
↓ java
boolean sameFile(URL other) // fragment(#) 제외하고 같은 파일인지 여부
URI toURI()
URLConnection openConnection()
final InputStream openStream() // == openConnection().getInputStream()
final Object getContent() // == openConnection().getContent()
URLClassLoader
URL을 이용한 클래스 로더를 제공한다
NetworkInterface
이름과 할당된 IP 주소들로 구성된 Network Interface 표현
↓ java
static Stream<NetworkInterface> networkInterfaces()
Stream<InetAdress> inetAddresses()
byte[] getHardwareAddress() // 보통 MAC 주소
java.nio
Buffer
버퍼는 유한 길이의 기본 자료형 원소 나열
Capacity : 저장하고 있는 원소들의 개수
Limit : 읽거나 쓸 수 없는 최초의 인덱스. 0보다 작거나 capacity보다 클 수 없다
Position : 다음에 읽거나 쓸 대상의 인덱스. 0보다 작거나 limit보다 클 수 없다
0<=mark<=position<=limit<=capacity // 마킹은 지원하지 않을수도 있다
get/put 연산의 Relative/Absolute 구분
Relative : 버퍼의 현재 position에 대한 연산
Absolute : 버퍼의 특정 위치를 지정한 연산
Additional operations
clear() : 새로운 채널-읽기 또는 relative put 연산을 준비; limit<-capacity, position<-0
flip() : 새로운 채널-쓰기 또는 relative get 연산을 준비; limit<-position, position<-0
rewind() : 이미 읽은 것을 다시 읽도록; position<-0
slice() : 기존 버퍼의 부분 시퀀스 생성
duplicate() : 기존 버퍼의 얕은 복사본 생성
↓ java
abstract boolean hasArray()
// 기저 배열의 존재 유무. true면 array()와 arrayOffset() 사용가능
abstract boolean isDirect()
// Direct 버퍼(즉시 읽기/쓰기)인지 여부
ByteBuffer
다음 연산을 정의
바이트 하나에 대한 absolute/relative get/put
바이트 시퀀스에 대한 bulk get/put
다른 원시 타입에 대한 absolute/relative get/put
다른 원시 타입으로 읽기 가능한 view 버퍼 생성; asCharBuffer, ...
compact : 인덱스 [0, position) 사이의 데이터가 버려진다(Optional operation)
Direct 버퍼
읽기/쓰기 연산이 직접적으로 이루어지며, 별개의 복사본을 이용하는 non-direct 버퍼에 비해 할당/제거 비용이 크다. Direct 버퍼는 allocateDirect 팩토리 메서드로 생성된다
Access to binary data
버퍼의 byte order는 해당 버퍼에 대한 연산의 기준이 된다. 기본값은 ByteOrder.BIG_ENDIAN
인덱싱
ByteBuffer에 대한 absolute get/put의 인덱스는 바이트 단위
뷰 버퍼의 인덱스는 해당 타입 크기 단위
↓ java
final ByteBuffer alignedSlice(int unitSize)
// 현재 버퍼를 unitSize 크기씩 잘라 view 버퍼를 생성(BIG_ENDIAN)한다
// 현재 위치가 unitSize의 배수가 아니라면 바로 다음 배수 위치부터 포함하며, limit도 unitSize 배수에 맞춰 끊는다
int mismatch(ByteBuffer that)
// 두 바이트 버퍼의 현재 읽기 위치들을 시작 위치로 하여, 바이트 값이 다른 최초 index를 반환한다
ByteOrder
↓ java
public static final ByteOrder BIG_ENDIAN, LITTLE_ENDIAN
static ByteOrder nativeOrder()
int write(ByteBuffer src)
// src.remaining() 부분을 채널에 쓴다
InterruptibleChannel
"instanceof InterruptibleChannel" IFF "비동기적으로 close() 메서드를 통해 인터럽트되고 닫을 수 있는 채널"
ScatteringByteChannel
채널의 바이트들을 여러 버퍼에 순서대로 저장. 네트워크 헤더나 파일 메타데이터처럼 고정 길이의 헤더를 읽는 데 유용
↓ java
long read(ByteBuffer[] dsts, int offset, int length)
// dsts[offset]부터 length개의 버퍼가 각각의 remaining()만큼씩 바이트를 읽어 가져간다
GatheringByteChannel
↓ java
long write(ByteBuffer[] srcs, int offset, int length)
// srcs[offset]부터 length개의 버퍼의 remaining() 부분을 채널에 쓴다
SeekableByteChannel
현재 위치를 기억하는 바이트 채널
↓ java
long position()
SeekableByteChannel position(long newPosition)
SeekableByteChannel truncate(long size)
// 채널에 연결된 개체의 크기를 size로 조정
// size가 현재보다 작은 경우 나머지는 버려진다(position이 size보다 큰 경우 size로 조정된다)
// size가 현재 이상인 경우 아무 변경 없다
비동기 I/O를 지원하는 채널. close()도 비동기적으로 수행되며, close 도중/이후 작업은 AsynchronousCloseException 발생
↓ java
// 전형적인 메서드 형태
Future<V> operation(...)
void operation(..., A attachment, CompletionHandler<V,? super A> handler)
CompletionHandler<V, A>
비동기 I/O 작업 결과를 소비
↓ java
void completed(V result, A attachment) // 성공시 호출
void failed(Throwable exc, A attachment) // 실패시 호출
AsynchronousByteChannel
비동기 바이트 채널
↓ java
Future<Integer> read(ByteBuffer dst)
Future<Integer> write(ByteBuffer src)
// 반환된 Future::get 메서드로 읽은/쓴 바이트 수를 얻을 수 있다
AsynchronousChannelGroup
시스템 속성에 따라 생성된 ThreadFactory가 비동기 작업을 실행할 데몬 스레드들을 만든다
그룹이 지정되지 않은 비동기 채널들은 시스템 기본 그룹에 묶인다
AsynchronousFileChannel
파일에 대한 비동기 채널. I/O의 기준이 되는 위치는 메서드에서 지정한다
생성된 채널들은 스레드-안전하며, 완료 핸들러들은 별개의 스레드에서 실행됨이 보장된다
연산에 사용되는 ByteBuffer 자체는 스레드-안전하지 않음에 유의
↓ java
static AsynchronousFileChannel open(Path file, Set<? extends OpenOption> options, ExecutorService executor, FileAttribute<?>... attrs)
// 파일을 열거나 생성한 뒤 비동기 채널을 하나 반환한다
// options에 java.nio.file.StandardOpenOption 이용
abstract AsynchronousFileChannel truncate(long size)
// size() > size인 경우 파일을 자른다. return this;
abstract void force(boolean metaData)
// true면 StandardOpenOption.SYNC를, false면 StandardOpenOption.DSYNC를 적용하는 것과 같다
// 기저 파일이 로컬에 존재하는 경우에만 유효
abstract Future<FileLock> lock(long position, long size, boolean shared)
// 기저 파일 일부에 대한 잠금을 얻는다
// size는 고정이므로, 파일 크기가 커질 것도 고려하여 필요한 만큼 신청해놔야 한다
// shared : 잠금 영역에 대한 추가 잠금 허용 여부
AsynchronousServerSocketChannel
스트림 지향 서버 소켓 채널
스레드-안전하지만 최대 accept 가능한 스레드는 하나 뿐이며, accept 도중 중복되는 요청은 AcceptPendingException
클라이언트 채널은 동일한 채널 그룹에 속하게 된다
지원하는 소켓 옵션
SO_RCVBUF : 수신 버퍼 크기
SO_REUSEADDR : 주소 재사용
구현에 따라 추가될 수 있다
AsynchronousSocketChannel
스트림 지향 클라이언트 소켓 채널
스레드-안전하지만 최대 하나의 읽기/쓰기만 각각 동시에 존재할 수 있다
도중에 중복되는 요청은 각각 ReadPendingException, WritePendinException 발생
읽기/쓰기 시 양수의 타임아웃을 지정한 경우, 시간 내에 완료되지 못하면 InterruptedByTimeoutException으로 종료되고, 이후 상태는 비결정적이며, 따라서 사용된 채널, 버퍼들은 버리는 게 낫다
지원하는 소켓 옵션
SO_SNDBUF : 전송 버퍼 크기
SO_RCVBUF : 수신 버퍼 크기
SO_KEEPALIVE : 기본 false, keep-alive 작동은 구현체에 의존적이다
new SimpleDateFormat(subformatPattern, getLocale())
choice
SubformatPattern
new ChoiceFormat(subformatPattern)
java.time
Clock
시간대(time-zone)을 이용한 현재의 date와 time 제공. 지정하지 않는 이상, 시계 내부의 시각은 계속 변한다
↓ java
static Clock system(ZoneId zone)
// 특정 시간대의 시계 반환
// systemUTC() == system(ZoneOffset.UTC)
// systemDefaultZone() == system(ZoneId.systemDefault())
static Clock tick(Clock baseClock, Duration tickDuration)
// 지정된 시계의 tick 단위를 조정. 예를 들어 1분이 지정된 경우, 1분 미만의 값은 버려진다
// tickMillis(ZoneId zone) == tick(system(zone), Duration.ofMillis(1))
static Clock fixed(Instant fixedInstant, ZoneId zone)
// 현재 시각으로 멈춘 시계 반환
static Clock offset(Clock baseClock, Duration offsetDuration)
// 시각을 조정한 새로운 시계 반환
abstract Clock withZone(ZoneId zone)
// 지정된 시간대에 현재 시계의 복사본을 생성하여 반환한다. 따라서 시각 자체는 조정하지 않는다
Duration
↓ java
static Duration of(long amount, TemporalUnit unit)
static Duration from(TemporalAmount amount)
// amount 그대로 Duration으로 변환
static Duration parse(CharSequence text)
// ISO-8601 duration format PnDTnHnMn.nS
// 추가로 접두 부호 가능
static Duration between(Temporal startInclusive, Temporal endExclusive)
Duration withSeconds(long seconds)
// 나노초 단위만 남기고 seconds로 변경
Duration withNanos(int nanoOfSecond)
// 나노초 단위만 nanoOfSecond로 변경
Instant
Epoch(1970-01-01 00:00:00)를 기준으로 한 초(long)와 나노초(int)로 시각을 표현한다. 음수면 epoch 이전
↓ java
public static final Instant EPOCH, MIN(아주 먼 옛날), MAX(아주 먼 미래)
static Instant now()
static Instant parse(CharSequence text)
// DateTimeFormatter.ISO_INSTANT
// 예. 2007-12-03T10:15:30.00Z)
DayOfWeek
↓ java
public static final DayOfWeek MONDAY ~ SUNDAY
int getValue() // ISO-8601. 1(MONDAY) ~ 7(SUNDAY)
Month
↓ java
public static final Month JANUARY ~ DECEMBER
int getValue() // ISO-8601. 1(JANUARY) ~ 12(DECEMBER)
Formatter with a style for date and time from the locale
'3 Jun 2008 11:05:30'
ofLocalizedDateTime(dateStyle,timeStyle)
Formatter with date and time styles from the locale
'3 Jun 2008 11:05'
BASIC_ISO_DATE
Basic ISO date
'20111203'
ISO_LOCAL_DATE
ISO Local Date
'2011-12-03'
ISO_OFFSET_DATE
ISO Date with offset
'2011-12-03+01:00'
ISO_DATE
ISO Date with or without offset
'2011-12-03+01:00'; '2011-12-03'
ISO_LOCAL_TIME
Time without offset
'10:15:30'
ISO_OFFSET_TIME
Time with offset
'10:15:30+01:00'
ISO_TIME
Time with or without offset
'10:15:30+01:00'; '10:15:30'
ISO_LOCAL_DATE_TIME
ISO Local Date and Time
'2011-12-03T10:15:30'
ISO_OFFSET_DATE_TIME
Date Time with Offset
'2011-12-03T10:15:30+01:00'
ISO_ZONED_DATE_TIME
Zoned Date Time
'2011-12-03T10:15:30+01:00[Europe/Paris]'
ISO_DATE_TIME
Date and time with ZoneId
'2011-12-03T10:15:30+01:00[Europe/Paris]'
ISO_ORDINAL_DATE
Year and day of year
'2012-337'
ISO_WEEK_DATE
Year and Week
'2012-W48-6'
ISO_INSTANT
Date and Time of an Instant
'2011-12-03T10:15:30Z'
RFC_1123_DATE_TIME
RFC 1123 / RFC 822
'Tue, 3 Jun 2008 11:05:30 GMT'
java.util
Collection API
컬렉션 자료형 인터페이스
Collection<E>
컬렉션 최소 연산을 정의
서브 컬렉션을 작성할 때, 인자없는 생성자와 Collection 인자 하나만 받는 생성자를 각각 작성하도록 권장한다
정의하지 않아도 되는 선택적 메서드들에 대하여, 구현하지 않는 경우 UnsupportedOperationException을 던져야 한다
컬렉션이 자기 자신을 요소로 갖는 경우 일부 메서드 실행 중 예외가 발생할 수 있다
↓ java
int size()
boolean isEmpty()
boolean add(E e)
boolean addAll(Collection<? extends E> c)
boolean contains(Object o)
boolean containsAll(Collection<?> c)
boolean retainAll(Collection<?> c)
// c에 속한 원소만 남기고 모두 제거한다. 이 연산으로 컬렉션이 변경됐다면 true 반환
boolean remove(Object o)
boolean removeAll(Collection<?> c)
default boolean removeIf(Predicate<? super E> filter)
void clear()
<T> T[] toArray(T[] a)
// 사용 : toArray(new Clazz[0])
default <T> T[] toArray(IntFunction<T[]> generator)
// 사용 : toArray(Clazz[]::new)
default Stream<E> stream()
default Stream<E> parallelStream()
Queue<E>
↓ java
boolean add(E e) // 추가할 수 없으면 예외 발생. 따라서 반환이 있다면 그 값은 항상 true
boolean offer(E e) // 추가하면 true, 실패하면 false
E remove() // 앞쪽 원소 하나 제거. 없으면 예외
E poll() // 앞쪽 원소 하나 제거. 없으면 null
E element() // 앞쪽 원소 하나 제거하지 않고 가져오기. 없으면 예외
E peek() // 앞쪽 원소 하나 제거하지 않고 가져오기. 없으면 null
static <E> List<E> of(E... elements)
static <E> List<E> copyOf(Collection<? extends E> coll)
// 변경 불가 리스트 반환
default void replaceAll(UnaryOperator<E> operator)
// 모든 원소를 연산 결과로 대체
default void sort(Comparator<? super E> c)
int indexOf(Object o)
// + lastIndexOf
ListIterator<E> listIterator()
List<E> subList(int fromIndex, int toIndex)
Set<E>
↓ java
static <E> Set<E> of(E... elements)
static <E> Set<E> copyOf(Collection<? extends E> coll)
// 변경 불가 집합 반환
SortedSet<E>
원소가 정렬된 Set. 다음 4가지 생성자를 구현할 것을 권장. (void), (Comparator), (Collection), (SortedSet)
↓ java
SortedSet<E> subSet(E fromElement, E toElement)
// 부분집합 반환. toElement는 미포함
// + headSet, tailSet
E first() // + last
NavigableSet<E>
인접 원소 탐색이 가능한 SortedSet
↓ java
E lower(E e)
// e보다 작은 원소들 중 최댓값을 반환. 없으면 null
// + floor: <=e, ceiling: >=e, higher: >e
E pollFirst() // + pollLast()
NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
NavigableSet<E> descendingSet()
Iterator<E> descendingIterator()
Map<K, V>
↓ java
default V getOrDefault(Object key, V defaultValue)
default V putIfAbsent(K key, V value)
default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
// 값을 다시 계산하여 덮어쓴다
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) + computeIfPresent
// key가 맵에 없거나, 대응하는 값이 null인 경우 새로운 값을 계산하여 넣고 반환
// 계산된 값이 null이면 null 반환. 그 외의 경우 현재값 반환
// + computeIfPresent : key가 존재하고, 대응하는 값이 null이 아닌 경우 새로운 값을 계산하여 넣고 반환
default V replace(K key, V value)
// key가 있을 때만 대체. 없으면 null 반환
// + replaceAll
default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
// if (key가 맵에 없거나, 대응하는 값이 null인 경우) => value로 연결
// else => 주어진 함수를 통해 새로운 값에 연결
// 결과가 null인 경우 맵에서 제거
static <K,V> Map<K,V> of(), ofEntries(), copyOf()
// 변경 불가능한 맵 반환; 키와 값 모두 null 비허용
Map.Entry<K, V>
↓ java
static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey()
// 키를 기준으로 엔트리를 비교하는 비교자 반환. 인자 있는 함수의 경우 해당 비교자를 이용
// + comparingByValue
SortedMap<K, V>
키가 정렬된 Map. 다음 4가지 생성자를 구현할 것을 권장. (void), (Comparator), (Map), (SortedMap)
↓ java
SortedMap<K, V> subMap(K fromKey, K toKey)
// 지정된 범위의 키만으로 구성된 서브 맵 반환. toKey는 미포함
// + headMap, tailMap
NavigableMap<K, V>
인접 키 탐색이 가능한 SortedMap
↓ java
Map.Entry<K, V> lowerEntry(K key)
// key보다 작은 키들 중 최댓값에 대한 entry 반환. 없으면 null
// + floorEntry: <=key, ceilingEntry: >=key, higherEntry: >key
NavigableMap<K, V> descendingMap()
NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
// + headMap, tailMap
컬렉션 순회 인터페이스
Iterator<E>
↓ java
boolean hasNext()
E next()
default void remove()
// 마지막으로 반환된 원소를 제거. next() 호출 뒤 한 번만 호출 가능
default void forEachRemaining(Consumer<? super E> action)
ListIterator<E>
양방향으로 이동 가능한 iterator
↓ java
boolean hasPrevious()
E previous()
int nextIndex() // + previousIndex
void set(E e) // 마지막으로 반환된 요소를 변경
void add(E e) // next()로 반환될 요소 바로전에 삽입
PrimitiveIterator<T, T_CONS>
기본 타입의 박싱을 회피하기 위한 PrimitiveIterator.OfInt, OfLong, OfDouble 제공
Spliterator<T>
Iterator와 달리 병렬 순회가 가능하며, 순회 메서드가 hasNext(), next()로 이분화되지 않는다
병렬 순회하려는 경우, 동일 Spliterator 객체를 이용하지 말고, 다른 스레드는 trySplit()을 통해 얻은 객체로 순회해야 한다
박싱을 피하기 위한 Spliterator.OfInt, OfLong, OfDouble 제공
↓ java
static int CONCURRENT, DISTINCT, IMMUTABLE, NONNULL, ORDERED, SIZED, SORTED, SUBSIZED
boolean tryAdvance(Consumer<? super T> action)
// 남은 원소가 존재하면 하나를 소비하고 true 반환. 그 외엔 false
default void forEachRemaining(Consumer<? super T> action)
Spliterator<T> trySplit()
// 이 spliterator를 분리할 수 있다면, 일부분을 분리하여 반환하고, 이 spliterator는 나머지 원소들을 순회한다. 그 외엔 null
long estimateSize()
// forEachRemaining() 메서드에서 순회할 원소의 수를 예측하여 반환한다
// 무한하거나, 알 수 없거나, 계산하는 연산이 비싼 경우 Long.MAX_VALUE를 반환하면 된다
default long getExactSizeIfKnown()
// 이 spliterator가 SIZED인 경우 estimateSize()를 반환한다. 그 외엔 -1
default Comparator<? super T> getComparator()
// 이 spliterator의 소스가 Comparator를 이용해 정렬된(SORTED) 경우, 해당 Comparator를 반환한다
// 그 외엔 null, 또는 IllegalStateException
컬렉션 자료형 콘크리트 클래스
ArrayDeque<E>
가변 길이 배열로 구현한 Deque. 스레드-안전하지 않음
ArrayList<E>
가변 길이 배열로 구현한 List. 스레드-안전하지 않음
Vector<E>
ArrayList와 달리 스레드-안전하다
BitSet
n개의 비트열 표현. 각 비트의 기본값은 false. 스레드-안전하지 않음
↓ java
void andNot(BitSet set)
// set에 true로 설정된 모든 index에 대해 false 설정
boolean intersects(BitSet set)
// 하나라도 true로 일치하는 경우
int size() // 총 비트 수
int cardinality() // true 비트 수
int length() // the index of the highest set bit
스레드-안전한 해시 테이블 구현. 스레드-안전할 필요가 없으면 HashMap, 높은 동시성이 요구되는 경우엔 ConcurrentHashMap을 이용
유틸리티
Collections
↓ java
// 리스트 연산
static <T extends Comparable<? super T>> void sort(List<T> list)
// T 자체가 Comparable하거나, T에 대한 Comparator를 넘기거나
static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
static void reverse(List<?> list)
// + shuffle, swap, fill, rotate
static <T> void copy(List<? super T> dest, List<? extends T> src)
static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)
static int indexOfSubList(List<?> source, List<?> target)
// + lastIndexOfSubList
// 컬렉션 연산
static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
static int frequency(Collection<?> c, Object o)
static boolean disjoint(Collection<?> c1, Collection<?> c2)
// 공통 원소가 없는지 여부
// 컬렉션 장식
static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c)
static <T> Collection<T> synchronizedCollection(Collection<T> c)
// 반환된 컬렉션에 대해 synchronized 제약을 걸고 이용하는 것이 좋다
static <E> Collection<E> checkedCollection(Collection<E> c, Class<E> type)
// 타입 체킹 추가
// 팩터리
static <T> Set<T> singleton(T o)
static <T> List<T> nCopies(int n, T o)
static <T> List<T> singletonList(T o)
static <K, V> Map<K, V> singletonMap(K key, V value)
Spliterators
↓ java
static <T> Spliterator<T> spliterator(Object[] array, int additionalCharacteristics)
// Arrays.spliterator()가 제공하는 것에 특성을 추가하고 싶을 때 사용. 전형적으로 IMMUTABLE, ORDERED
static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator, int characteristics)
// Spliterator로 래핑한 후, 원본 iterator를 사용하면 안 된다
static <T> Iterator<T> iterator(Spliterator<? extends T> spliterator)
// Iterator로 래핑한 후, 원본 spliterator를 사용하면 안 된다.
Spliterators.AbstractSpliterator<T>
estimateSize(), characteristics(), trySplit()을 구현한 추상 클래스
Arrays
↓ java
// 정렬, 검색
static void sort(int[] a)
static void parallelSort(byte[] a)
// ForkJoin common pool을 이용해 병합 정렬을 병렬로 수행
static int binarySearch(long[] a, long key)
// 변경, 변환
static void fill(long[] a, long val)
static <T> void setAll(T[] array, IntFunction<? extends T> generator)
static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator)
static <T> void parallelPrefix(T[] array, BinaryOperator<T> op)
// 전체 원소에 순차적으로 연산 적용하여 값 변경. 큰 배열은 루프보다 이게 더 빠르다
static String toString(?[] a)
static String deepToString(Object[] a)
// deep : 원소가 배열인 경우 "[]"를 추가하고 해당 배열의 원소들에 대해 같은 작업을 한다
static <T> List<T> asList(T... a)
static <T> Spliterator<T> spliterator(T[] array)
// characteristics()에서 SIZED | SUBSIZED | ORDERED | IMMUTABLE를 반환하는 Spliterator 인스턴스를 반환한다
static <T> Stream<T> stream(T[] array)
// 복사
static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType)
static <T> T[] copyOf(T[] original, int newLength)
static <T, U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType)
static <T> T[] copyOfRange(T[] original, int from, int to)
// 비교
static int mismatch(?[] a, ?[] b)
// 처음으로 일치하지 않는 인덱스 반환
static boolean equals(?[] a, int aFromIndex, int aToIndex, ?[] b, int bFromIndex, int bToIndex)
// Object의 경우, Objects.equals(e1, e2)일 때 같다고 간주한다
static boolean deepEquals(Object[] a1, Object[] a2)
// null일 수 있는 각 배열의 두 원소 e1, e2에 대하여, 다음 4가지 경우에 대해 둘이 같다고 판단한다
// 1. e1 == e2
// 2. 둘 모두 참조변수에 대한 배열이고, Arrays.deepEquals(e1, e2)가 true
// 3. 둘 모두 원시타입에 대한 배열이고, Arrays.equals(e1, e2)가 true
// 4. e1.equals(e2)가 true
// 해싱
static int hashCode(?[] a)
// 동일 원소를 가진 List의 해시코드와 동일. null이면 0 반환
static int deepHashCode(Object[] a)
// 원소가 배열인 경우, 해당 원소의 해시를 deepHashCode로 구한다
// 자기 자신을 포함하는 배열 등은 적합하지 않다
Objects
↓ java
// 비교
static boolean deepEquals(Object a, Object b)
// 둘 다 null이면 true
// 둘 다 배열이면 Arrays.deepEquals()
// 나머진 a.equals(b)
static <T> int compare(T a, T b, Comparator<? super T> c)
// hashCode
static int hash(Object... values)
// Arrays.hashCode(Object[])를 이용한다. Object.hashCode()의 간편한 구현으로 이용할 수 있다
// 주의. o.hashCode() != Objects.hash(o)
// toString
static String toString(Object o, String nullDefault)
// null
static boolean isNull(Object obj)
// Predicate, filter(Objects::isNull)에 이용
static <T> T requireNonNull(T obj)
// 메서드나 생성자에서 null검사를 하도록 설계되었다
static <T> T requireNonNullElse(T obj, T defaultObj)
static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
// index
static int checkIndex(int index, int length)
// index가 [0, length)에 존재하면 그대로 반환. 아니면 예외 발생
static int checkFromToIndex(int fromIndex, int toIndex, int length)
// subrange [fromIndex, toIndex)가 [0, length)에 포함되면 fromIndex 반환. 아니면 예외 발생
static int checkFromIndexSize(int fromIndex, int size, int length)
// subrange [fromIndex, fromIndex + size)가 [0, length)에 포함되면 fromIndex 반환. 아니면 예외 발생
시간 관련
Date
↓ java
long getTime()
boolean before(Date when) + after, compareTo
static Date from(Instant instant) + toInstant
Calendar
관대함(Leniency) : 범위를 벗어나는 값도 받아들이며, 나중에 정규화한다. 예를 들어 1월 32일은 2월 1일이 된다
add와 roll : add는 오버플로되면 다음 단위가 변하지만, roll은 modulo연산처럼 해당 단위만 변한다
Field Detail
시간 단위
public static final int ERA, YEAR, MONTH, WEEK_OF_YEAR, WEEK_OF_MONTH_, DATE, ...
단위 상수
public static final int SUNDAY, ..., JANUARY, ...AM, PM
스타일
public static final int ALL_STYLES, SHORT, LONG, NARROW_FORMAT, ...
↓ java
static Calendar getInstance()
// 달력의 현재 시점을 저장하고 있으므로, 시각 비교, 설정 등의 연산 제공
final Date getTime()
int get(int field)
abstract void add(int field, int amount)
void roll(int field, int amount)
boolean isLenient()
int getWeekYear()
void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek)
int getWeeksInWeekYear()
final Instant toInstant()
int getActualMaximum(int field)
int getActualMinimum(int field)
Timer
백그라운드 스레드에서 미래에 실행될 작업들을 스케쥴링하는 기능을 제공한다. 작업은 일회용일수도, 일정한 주기를 가지고 반복될 수도 있다. 한 타이머의 모든 작업들은 하나의 백그라운드 스레드를 공유하기 때문에, 작업의 실행은 직렬적이며, 따라서 각 작업들은 가능한 한 빠르게 종료되어야 한다. 그렇지 않은 경우, 뒤에 대기하는 모든 작업이 밀려 제대로 실행되지 않을 수 있다
스레드-안전하다. 정시성을 보장하지 않는다. 스케쥴은 Object.wait(long) 메서드를 통해 이루어진다. java.util.concurrent 패키지의 ScheduledThreadPoolExecutor가 더 나은 대안으로 이용될 수 있다
기본적으로 타이머의 백그라운드 스레드는 데몬 스레드가 아니다. 따라서 타이머의 작업이 전체 프로그램의 종료를 지연시킬 수 있다. 백그라운드 스레드는 타이머 임의의 생성자에 의해 시작된다
↓ java
void schedule(TimerTask task, long delay)
// delay밀리초 이후 task가 실행되도록 스케쥴
void schedule(TimerTask task, Date time)
// time에 task가 실행되도록 스케쥴. time이 과거라면 즉시 실행
void schedule(TimerTask task, long delay, long period)
// delay밀리초 이후 period 주기를 갖고 task가 실행되도록 스케쥴
void schedule(TimerTask task, Date firstTime, long period)
// firstTime 이후 period 주기를 갖고 task가 실행되도록 스케쥴
void scheduleAtFixedRate(TimerTask task, long delay, long period)
// period가 이전 task 종료가 아닌 최초 실행 시점을 기준으로 작동한다. 따라서 어떤 이유로 이전 작업이 지연된 경우, 시간당 작업률을 맞추기 위해 이후 작업이 연속적으로 실행될 수 있다
void cancel()
// 타이머를 종료한다. 스케쥴된 모든 작업을 버리고, 현재 실행중인 작업에는 간섭하지 않는다. 타이머 종료 후 백그라운드 스레드도 우아하게 종료되어 GC 대상이 된다. 이후 더 이상의 스케쥴은 불가능하다
TimerTask
Timer 작업으로 사용하기 위한 Runnable
boolean cancel()
작업을 취소한다
작업이 1회용으로 스케쥴되었지만 아직 실행되지 않은 경우, 또는 아직 스케쥴되지 않은 경우 작업은 결코 실행되지 않는다
반복 작업으로 스케쥴된 경우, 작업은 결코 반복되지 않는다
작업 도중에 호출된 경우, 작업은 마무리까지 실행된다
반복 호출 가능하며 2회째 호출부터는 아무런 영향이 없다
true 반환 : 1회용으로 스케쥴되었지만 아직 실행되지 않은 경우, 반복 작업으로 스케쥴된 경우
false 반환 : 1회용으로 스케쥴되어 이미 실행된 경우, 아직 스케쥴되지 않은 경우, 이미 취소된 경우
long scheduledExecutionTime()
가장 최근에 스케쥴된 ─ 또한 실제로 실행된 ─ 시점을 반환한다. 전형적으로 run 메서드에서, 작업이 너무 길어지는 것을 방지하기 위해 사용된다
숫자 관련
DoubleSummaryStatistics
double에 관한 통계를 모은 상태 객체. 스트림과 함께 사용되도록 설계되었다
↓ java
var stats = doubleStream.collect(DoubleSummaryStatistics::new, DoubleSummaryStatistics::accept, DoubleSummaryStatistics::combine);
var stats = people.stream().collect(Collectors.summarizingDouble(Person::getWeight));
+ IntSummaryStatistics, LongSummaryStatistics
↓ java
public DoubleSummaryStatistics()
// 개수 0, 합계 0, 최솟값 Double.POSITIVE_INFINITY, 최댓값 Double.NEGATIVE_INFINITY, 평균 0인 객체 생성
// + (long count, double min, double max, double sum)
void accept(double value)
// 요약 정보에 value를 추가
Random
의사난수 생성기. 스레드-안전하지만 성능 저하 가능성이 있으므로 ThreadLocalRandom을 고려
↓ java
void nextBytes(byte[] bytes)
double nextGaussian()
// 평균 0, 표준분산 1인 정규분포 난수 반환
// 난수 스트림 : + Long, Double 버전 존재
IntStream ints(long streamSize)
IntStream ints() // == ints(Long.MAX_VALUE)
IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound) // [origin, bound)
SplittableRandom
분열하는 의사난수 생성기. 스레드-안전하지 않으며, 분열하여 스레드들이 각자 하나씩 갖도록 설계되었다
↓ java
SplittableRandom split()
// 분열. 상태를 공유하진 않지만, 생성한 난수는 통계적으로 유사한 속성을 갖는다
public static final Locale US, ENGLISH, KOREA, KOREAN, ...
static Locale getDefault()
static Locale[] getAvailableLocales()
Scanner
정규 표현식을 통해 원시 타입과 String을 분리해내는 간단한 text scanner
지정되지 않은 경우, 기본 구분자 패턴은 공백 문자(Character::isWhitespace)
기저 스트림으로부터 입력을 대기하는 동안 스레드가 블록될 수 있다
기저 Readable의 read()에서 IOException이 발생한 경우 소스의 끝에 도달했다고 판단하며, 가장 최근의 예외는 ioException()을 통해 얻을 수 있다
기저 스트림이 Closeable인 경우, Scanner에 대해 close()가 호출되면 기저 스트림도 닫힌다
↓ java
public Scanner(Readable source)
public Scanner(InputStream source)
public Scanner(File source)
public Scanner(Path source)
public Scanner(String source)
public Scanner(ReadableByteChannel source)
Pattern delimiter() // + useDelimiter
Locale locale() // + useLocale
int radix() // + useRadix
String findInLine(Pattern pattern)
// 구분자를 무시하고 pattern을 검색한다. 줄 바꿈 문자 전에 문자열을 찾으면 해당 문자열을 반환하고 다음 라인으로 넘어간다. 줄 바꿈 문자를 만날 때까지 매칭이 없으면 읽기 위치는 변경없이 null을 반환한다
String findWithinHorizon(Pattern pattern, int horizon)
// 구분자를 무시하고 pattern을 검색한다. 현재 위치로부터 최대 horizon개의 code point만을 검색에 이용한다. horizon == 0인 경우, 제한없이 검색을 수행한다. 매칭된 문자열이 없으면 읽기 위치 변경없이 null을 반환한다
Scanner skip(Pattern pattern)
// 구분자를 무시하고 pattern을 검색한다. 매칭된 문자열이 있으면 건너뛰고, 없으면 읽기 위치 변경 없이 NoSuchElementException 발생
MatchResult match()
// 가장 최근의 매칭 결과를 반환한다. MatchResult는 각종 next, findInLine, findWithinHorizon, skip 메서드의 성공적인 실행으로 설정된다
Stream<MatchResult> findAll(Pattern pattern)
// 스트림의 MatchResult 순서는 findWithinHorizon(pattern, 0), match()를 반복적으로 호출한 것과 동일하다
Stream<String> tokens()
// 구분자로 자른 문자열들의 스트림을 반환한다
Scanner reset()
// scanner.useDelimiter("\\p{javaWhitespace}+").useLocale(Locale.getDefault(Locale.Category.FORMAT)).useRadix(10);
etc
Comparator<T>
↓ java
default Comparator<T> reversed()
default Comparator<T> thenComparing(Comparator<? super T> other)
// 이 비교자가 두 객체를 같다고 판단하면, other가 새로 판단한다
// + thenComparingInt, Long, Double
static <T extends Comparable<? super T>> Comparator<T> naturalOrder()
// 자연스러운 비교자를 반환한다
// + reverseOrder
static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
// null은 모든 non-null 값보다 작다고 간주한다. null끼리는 서로 같다고 간주한다
// + nullsLast
static <T, U> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator)
// 정렬에 이용할 키를 생성하는 함수와, 키를 이용해 비교하는 비교자를 넘기면 둘을 포함하는 T타입 비교자를 반환
// + comparingInt, Long, Double
static <T> Optional<T> empty()
static <T> Optional<T> of(T value)
// null이면 예외
static <T> Optional<T> ofNullable(T value)
// null이면 empty(), 아니면 of(value)
T get()
T orElse(T other)
T orElseGet(Supplier<? extends T> supplier)
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
// 값이 존재하면 그대로 반환. 없으면 제공되는 값 반환
T orElseThrow()
// 값이 없으면 NoSuchElementException
boolean isPresent()
// + isEmpty
void ifPresent(Consumer<? super T> action)
void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
Optional<T> filter(Predicate<? super T> predicate)
// 값이 존재하고 필터를 통과하면 그대로 반환. 아니면 empty()
Stream<T> stream()
// 값이 존재하면 해당 값 하나만 포함하는 스트림 반환. 없으면 빈 스트림 반환
<U> Optional<U> map(Function<? super T, ? extends U> mapper)
<U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
Properties
stream을 통해 로드/저장되는 영구적인 속성값들을 표현. 기본값으로 이용하기 위해 다른 Properties를 포함할 수 있다. 스레드-안전하다
public UUID(long mostSigBits, long leastSigBits)
// 2개 long을 이용해 128비트 UUID 생성
static UUID randomUUID()
// version 4 UUID 생성
static UUID nameUUIDFromBytes(byte[] name)
// version 3 UUID 생성
static UUID fromString(String name)
int version()
// 1 Time-based UUID
// 2 DCE security UUID
// 3 Name-based UUID
// 4 Randomly generated UUID
int variant()
// 0 Reserved for NCS
// 2 RFC 4122(이 클래스에서 사용)
// 6 Reserved for Microsoft
// 7 Reserved for future
long timestamp()
// 60비트로 구성된 Time-based UUID의 시각을 반환한다. 1582-10-15 00:00:00 UTC로부터 몇 100ns가 흘렀는지를 의미한다
long node()
//Time-based UUID의 48비트 Mac address를 반환한다
java.util.concurrent
비동기 연산
Future<V>
비동기적 계산의 결과를 표현
↓ java
V get()
// 결과가 준비될 때까지 대기
V get(long timeout, TimeUnit unit)
// 결과가 준비될 때까지 최대 timeout만큼 대기
boolean cancel(boolean mayInterruptIfRunning)
// 작업을 취소한다. 결과를 기다리고 있던 스레드들은 CancellationException 발생
// 작업이 완료됐거나 이미 취소된 경우 false 반환
// 이 메서드가 종료된 후의 isDone()은 항상 true
CompletableFuture<T>
(비)동기 연산들의 파이프라인을 구성할 수 있는, 명시적으로 종료(값과 상태를 설정)되는 Future
둘 이상의 스레드가 complete, completeExceptionally, cancel을 호출할 경우, 하나만 성공한다
non-async 메서드로 등록된 작업은 현재 CompletableFuture의 스레드, 또는 호출자에서 실행된다
명시적인 Executor 없이 async 메서드로 등록된 작업은 ForkJoinPool::commonPool에서 실행
CompletionStage 메서드들을 독립적으로 구현했기 때문에, 하나를 재정의해도 다른 메서드에 영향이 없다
CompletionStage 메서드들만 이용하도록 하려면 minimalCompletionStage()를, future를 변경하지 못하도록 하려면 copy()를 이용
전반적인 계산에 대한 직접적인 제어를 할 수 없어서, cancel()의 호출은 completeExceptionally(new CancellationException()) 호출과 동일하다
↓ java
static Executor delayedExecutor(long delay, TimeUnit unit)
// 주어진 딜레이 이후에 executor로 작업을 제출하는 새로운 Executor 반환
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
// supplier의 결과를 가지고 비동기 종료되는 CompletableFuture 반환
static CompletableFuture<Void> runAsync(Runnable runnable)
// runnable을 실행하고 비동기 종료되는 CompletableFuture 반환
static <U> CompletableFuture<U> completedFuture(U value)
// 이미 특정 값으로 종료된 CompletableFuture 반환
static <U> CompletionStage<U> completedStage(U value)
// 주어진 value로 이미 종료된 새로운 CompletionStage 반환
static <U> CompletableFuture<U> failedFuture(Throwable ex)
// 주어진 예외로 이미 종료된 새로운 CompletableFuture 객체 반환
static <U> CompletionStage<U> failedStage(Throwable ex)
// 주어진 예외로 이미 종료된 새로운 CompletionStage 반환
<U> CompletableFuture<U> newIncompletableFuture()
// 완료되지 않은 새로운 CompletableFuture 객체를 반환
// 서브클래스들은 각자의 클래스 인스턴스를 반환하도록 재정의해야 한다
static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
// 모든 cfs가 완료하면 완료되는 새로운 CompletableFuture 객체 반환
// 하나라도 예외 종료되면 반환된 CompletableFuture도 그러하다
// cfs가 빈 경우, null로 종료된다
static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
// 하나라도 완료되면, 그 결과와 같은 값으로 완료되는 CompletableFuture 객체 반환
// cfs가 빈 경우, 완료되지 않는다
// this 완료 후 실행
<U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn)
CompletableFuture<Void> thenAccept(Consumer<? super T> action)
CompletableFuture<Void> thenRun(Runnable action)
// this 완료 후 실행 + 값 대신 CompletionStage 직접 반환
<U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)
// this와 other 모두 완료 후 실행
<U, V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn)
<U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)
CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action)
// this나 other 둘 중 하나라도 완료하면 실행
<U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action)
// this 예외 발생/완료 후 실행
<U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action)
// this 예외 발생 시 실행
CompletionStage<T> exceptionally(Function<Throwable, ? extends T> fn)
default CompletionStage<T> exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> fn)
T join()
// 종료되면 결과 값 반환, 또는 발생한 예외 던지기
// 예외는 CompletionException이고, 기저 예외를 cause로 설정한다
T getNow(T valueIfAbsent)
// 종료되었다면 결과 값 반환, 또는 발생한 예외 던지기. 아니면 valueIfAbsent 반환
boolean complete(T value)
// 종료되지 않았다면 get()과 연관 메서드들의 반환값을 value로 설정
// 이 호출로 CompletableFuture가 종료하면 true 반환
CompletableFuture<T> completeAsync(Supplier<? extends T> supplier)
// 이 CompletableFuture를 supplier의 결과값으로 종료한다
CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
// 이 CompletableFuture가 주어진 시간 내에 종료되지 않은 경우, TimeoutException으로 예외 종료한다
CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
// 이 CompletableFuture가 주어진 시간 내에 종료되지 않은 경우, value로 종료한다
boolean completeExceptionally(Throwable ex)
// 종료되지 않았다면 get()과 연관 메서드들이 주어진 예외를 던지도록 한다
// 이 호출로 CompletableFuture가 종료하면 true 반환
boolean isCompletedExeptionally()
void obtrudeValue(T value)
// 강제로 get()과 연관 메서드들의 반환값 설정. 에러 복구를 위해 설계됨
// + obtrudeException
int getNumberOfDependents()
// 종료 대기중인 CompletableFuture의 개수 추정
// 동기화가 아니라, 시스템 모니터링을 위해 설계됨
CompletableFuture<T> copy()
// 정상적으로 종료되었다면, 같은 값을 갖는 종료된 CompletableFuture 반환
// 예외 종료되었다면, 해당 예외를 원인으로 한 CompletionException으로 예외 종료된 CompletableFuture 반환
CompletionStage<T> minimalCompletionStage()
// CompletionStage에 정의된 메서드만 이용 가능
// 재정의되지 않았다면 toCompletableFuture() 메서드를 통해 다시 다른 메서드에 접근 가능
Executor
전달받은 Runnable을 실행하는 객체. Executor 자체가 스레드의 병행성을 부여하진 않으며, 구현체에서 다른 스레드 공간을 마련해주어야 한다
ExecutorService
Executor + Runnable 관리 기능
↓ java
void shutdown()
// 작업을 더 이상 받지 않는다. 이전에 추가된 것은 마저 실행한다
List<Runnable> shutdownNow()
// 실행중인 모든 작업을 중지. 실행 대기중이었던 작업들은 반환
boolean isTerminated()
// shutdown, shutdownNow 호출 이후 모든 작업이 끝났는지 여부
boolean awaitTermination(long timeout, TimeUnit unit)
// shutdown 요청 후 모든 작업이 종료되기를 기다리며 블록한다. timeout 발생한 경우 false 반환
<T> Future<T> submit(Callable<T> task)
// 결과를 반환하는 작업을 등록한다. 작업이 성공적으로 종료되면 Future::get으로 결과를 확인할 수 있다
<T> Future<T> submit(Runnable atask, T result)
// 작업을 등록한다. 작업이 성공적으로 종료되면 Future::get으로 result를 얻을 수 있다
Futur<?> submit(Runnable task)
// 작업을 등록한다. 작업이 성공적으로 종료되면 Future::get은 null을 반환한다
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
// 모든 작업이 종료되면 Future 리스트를 반환한다. 따라서 리스트 안의 각 Future::isDone은 true다
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timout, TimeUnit unit)
// 모든 작업이 종료되거나 timeout이 발생하면 반환. 리스트 안의 각 Future::isDone은 true. timeout 발생 시 완료되지 않은 작업들은 취소된다
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
// 성공적으로 완료된 첫 작업의 결과를 반환한다. 완료되지 않은 작업들은 취소된다
<T> T invokeAny(Collection<? extends Callable<>> tasks, long timeout, TimeUnit unit)
// timeout되면 TimeoutException 발생
ScheduledExecutorService
↓ java
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
// 주어진 delay 이후 command가 1회 실행되도록 한다
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
// 반복되는 작업은 반환된 Future를 통해 취소할 수 있다
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
// scheduleAtFixedRate와 달리, 이전 작업이 완료된 후 다음 작업이 시작된다
ThreadPoolExecutor
스레드 풀 각 스레드들이 서로 다른 작업을 실행
corePoolSize
이 값에 도달할 때까지 신규 작업에 대해 신규 스레드 할당
maxPoolSize
대기 중인 스레드가 없으면, 이 값에 도달할 때까지 신규 작업에 대해 신규 스레드 할당
keepAliveTime
corePoolSize를 초과한 스레드들은 대기 상태가 이 값을 초과하면 종료된다. allowCoreThreadTimeOut() 메서드로 코어 스레드에도 적용할 지 설정 가능
Queuing
처리를 기다리는 작업들은 BlockingQueue에서 대기한다
corePoolSize 이상의 스레드가 활성 상태라면 작업은 우선 큐에 진입된다. 큐에 자리가 없으면 신규 스레드가 생성되어 작업을 처리한다
큐에 자리도 없고 활성 스레드 수가 maximumPoolSize와 같다면 추가 작업은 거부된다
큐잉 전략 1. Direct handoff
SynchronousQueue. 작업 가능한 스레드가 없으면 신규로 생성한다. 제한없는 maximumPoolSize 필요
큐잉 전략 2. Unbounded queue
무제한으로 큐에 작업을 추가하므로, 활성 스레드의 수는 항상 corePoolSize 이하
큐잉 전략 3. Bounded queue
큐의 크기와 maxPoolSize의 적절한 trade off 필요
Rejected tasks
거부된 작업에 대하여 RejectedExecutionHandler::rejectedExecution 메서드가 실행된다
ThreadPoolExecutor.AbortPolicy(defaullt) : 핸들러가 RejectedExecutionException 발생
ThreadPoolExecutor.CallerRunsPolicy : 작업을 제출한 스레드가 직접 작업을 실행한다
ThreadPoolExecutor.DiscardPolicy : 거부된 작업은 버려진다
ThreadPoolExecutor.DiscardOldestPolicy : 신규 작업이 아닌, 큐에서 가장 오래된 작업이 버려진다. 신규 작업은 다시 시도된다
Hook methods
beforeExecute, afterExecute, terminated 메서드를 재정의하여 작업 전후에 필요한 부분을 실행할 수 있다
↓ java
void execute(Runnable command)
// command를 언젠가 실행한다. 작업 스레드가 실행하지 못하면, RejectedExecutionHandler가 처리한다
// ↔ remove
void shutdown()
// 순차적 종료 절차에 진입한다. 추가 작업은 받지 않고, 이미 제출된 작업들은 마저 처리한다
List<Runnable> shutdownNow()
// 대기 중인 작업에 더해 실행 중인 작업들도 모두 중지한다. 대기중이었던 작업들은 리스트로 반환한다
// 실행 중인 작업들에 유예 시간을 주고 싶다면 ExecutorService::awaitTermination 이용
boolean isTerminating()
// shutdown 또는 shutdownNow 메서드가 호출되었지만, 아직 중지가 완료되지 않았다면 true
void setThreadFactory(ThreadFactory threadFactory)
// + set/getRejectedExecutionHandler, set/getCorePoolSize, set/getMaximumPoolSize, set/getKeepAliveTime
BlockingQueue<Runnable> getQueue()
// 직접 조작하진 말고, 모니터링/디버깅 용도로 이용함이 바람직하다
int getPoolSize() // 현재 풀 안의 스레드 수 반환
int getActiveCount() // 현재 실행 중인 스레드 수 추정치 반환
int getLargestPoolSize() // 풀에 동시에 존재했던 스레드 최대 개수 반환
long getTaskCount() // 실행 스케쥴된 작업의 총 개수의 근사치 반환
long getCompletedTaskCount() // 실행 완료된 작업의 총 개수의 근사치 반환
ScheduledThreadPoolExecutor
↓ java
void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value)
// 기본값 false. true면 shutdownNow가 호출되거나 이 정책이 false가 될 때까지 주기 작업을 계속 실행한다
void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value)
// 기본값 true. true면 shutdownNow가 호출되거나 종료 후 이 정책이 false가 되기 전까지는 지연 작업을 실행한다
void setRemoveOnCancelPolicy(boolean value)
// 기본값 false. 취소된 작업을 즉시 큐에서 제거할 것인지, 또는 해당하는 딜레이 후 제거할 것인지 설정
Future<V> submit(Callable<V> task)
Future<V> submit(Runnable task, V result)
Future<V> take()
// 완료된 작업을 가져온다. 없으면 대기한다
Future<V> poll()
// 완료된 작업을 가져온다. 없으면 null
Futur<V> poll(long timeout, TimeUnit unit)
Executors
↓ java
static ExecutorService newFixedThreadPool(int nThreads)
// 최대 동시 실행 가능한 스레드 수 제한. 나머지 스레드는 큐에서 대기. 스레드들은 명시적으로 shutdown되기 전까지 풀에 존재한다
static ExecutorService newWorkStealingPool()
// 사용 가능한 프로세서 수를 parallelism level로 이용. 반환되는 객체는 ForkJoinPool 인스턴스
static ExecutorService newCachedThreadPool()
// 스레드 재사용. 60초 동안 이용되지 않으면 풀에서 삭제된다
static ScheduledExecutorService newSingleThreadScheduledExecutor()
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
onNext, onSubscribe 안에서 동기적으로 request를 호출하는 것은 허용된다
cancel의 호출은 멱등이어야 하고, 그 실행은 스레드-안전해야 한다
Subscription이 취소됐다면, 이후의 request, cancel의 호출은 아무 작업도 하지 않아야 한다
0이하에 대한 request 호출은 onError로 IllegalArgumentException을 보내야 한다
Subscription이 취소됐다면, Publisher는 Subscriber에 대한 모든 참조를 제거해야 한다
request, cancel은 항상 정상 종료되어야 한다
Subscription은 반드시 무제한적인 request 호출을 허용해야 한다. n == Long.MAX_VALUE
SubmissionPublisher<T>
↓ java
public SubmissionPublisher(Executor executor, int maxBufferCapacity, BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> handler)
// executor : 비동기적으로 구독자에게 전달하는 데 쓰일 Executor
// maxBufferCapacity : 각 구독자에 대한 버퍼의 한도. 실제 한도는 getMaxBufferCapacity()로 확인
// handler : null이 아니면 onNext에서 발생한 예외를 처리
public SubmissionPublisher()
// executor = ForkJoinPool.commonPool()
// maxBufferCapacity = Flow.defaultBufferSize()
// handler = null
int submit(T item)
// 각 구독자에게 비동기적으로 item을 보낸다(onNext). lag(배포된 item 중에 아직 소비되지 않은 개수) 추정치를 반환한다
int offer(T item, BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop)
// 가능하다면 각 구독자에게 비동기적으로 item을 보낸다(onNext). 리소스 초과(버퍼가 가득 찼다던지)로 실패한 경우 onDrop이 실행된다. onDrop이 true를 반환하면 onNext를 다시 시도한다
// 반환값이 음수인 경우 drop된 구독자 수를 의미하고, 그 외의 경우 lag(배포된 item 중에 아직 소비되지 않은 개수) 추정치를 의미한다
long estimateMinimumDemand()
// 각 구독자들이 요청한 아이템 수 중, 아직 공급되지 않은 수의 최소값(추정치) 반환
int estimateMaximumLag()
// 각 구독자들에 보낸 아이템 중 아직 소비되지 않은 수의 최대값(추정치) 반환
CompletableFuture<Void> consume(Consumer<? super T> consumer)
// 배포된 모든 아이템에 대해 consumer 실행. 정상적으로 모두 실행되면 onComplete가 호출되고, CompletableFuture도 정상 종료된다
Blocking 컬렉션
BlockingQueue<E>
기본적으로 스레드-안전하지만, addAll 따위의 bulk 연산은 특별히 표시되지 않는 한 그렇지 않다
요소를 획득할 때, 큐가 비어있는 경우 블로킹. 요소를 추가할 때, 큐에 빈 자리가 있을 때까지 블로킹
예외 발생
특별값 반환
블로킹
시간 제한
Insert
add(E)
offer(E)
put(E)
offer(E,long,TimeUnit)
Remove
remove()
poll()
take()
poll(long,TimeUnit)
Examine
element()
peek()
-
-
↓ java
int remainingCapacity()
// 블로킹없이 삽입 가능한 요소의 수. 오차가 있을 수 있다
int drainTo(Collection<? super E> c)
// 모든 원소를 c로 옮긴다
ArrayBlockingQueue<E>
크기가 고정된 기저 배열을 이용한 BlockingQueue
기본적으로 삽입을 기다리는 스레드들 사이의 처리 순서는 보장되지 않지만, fairness를 설정하면 FIFO 순으로 처리된다
Collection, Iterator의 모든 선택적 연산을 구현했다
LinkedBlockingQueue<E>
크기를 고정할 수 있는 연결된 BlockingQueue
Collection, Iterator의 모든 선택적 연산을 구현했다
PriorityBlockingQueue<E>
크기 제한 없고, PriorityQueue와 비슷한 정렬을 이용한 BlockingQueue
Collection, Iterator의 모든 선택적 연산을 구현했다
다만 iterator(), spliterator()로 제공되는 인스턴스들은 순회하는 순서를 보장하지 않는다. 순차적인 순회를 원한다면 Arrays.sort(queue.toArray())를 고려할 것
같은 우선순위의 원소 사이의 정렬은 정의되지 않았다
SynchronousQueue<E>
서로 연관된 삽입 연산과 삭제 연산 한 쌍이 동시에 존재할 때까지 연산을 블로킹한다
DelayQueue<E extends Delayed>
Delayed 요소들로 구성된, 크기 제한없는 BlockingQueue. 요소의 지연 시간이 만료되어야 큐로부터 획득 가능하다
요소가 만료됐음은 getDelay(TimeUnit.NANOSECONDS) 리턴값이 0 이하일 때로 판정
Collection, Iterator의 모든 선택적 연산을 구현했다
BlockingDeque<E>
요소를 획득할 때, 덱이 비어있는 경우 블로킹. 요소를 추가할 때, 덱에 빈 자리가 있을 때까지 블로킹
BlockingQueue와 SynchronousQueue 기능 모두를 선택적으로 이용할 수 있다
↓ java
void transfer(E e)
// 소비자에게 e를 전달한다. 소비자가 소비할 때까지 대기한다
boolean tryTransfer(E e)
// 대기 중인 소비자에게 e를 전달한다. 대기 중인 소비자가 없다면 즉시 false를 반환한다
boolean tryTransfer(E e, long timeout, TimeUnit unit)
// timeout이 지나도록 대기 중인 소비자가 없다면 false를 반환한다
LinkedTransferQueue<E>
크기 제한없고 연결된 TransferQueue
size 계산에 순회가 필요하므로 정확하지 않을 수 있다
addAll 따위의 bulk 연산은 원자적으로 실행되지 않을 수 있다
Collection, Iterator의 모든 선택적 연산을 구현했다
Non-Blocking 컬렉션
CopyOnWriteArrayList<E>
스레드-안전한 ArrayList
add, set 등의 연산마다 새로운 배열을 만든다. 따라서 일반적인 용도로는 매우 나쁘다
iterator는 생성된 시점의 snapshot을 순회함이 보장되지만, iterator를 통한 요소의 변경은 불가하다
CopyOnWriteArraySet<E>
모든 연산에 CopyOnWriteArrayList를 사용하는 Set
ConcurrentLinkedQueue<E>
크기 제한 없고, 스레드-안전한 연결된 Queue
size 계산에 순회가 필요하므로, 오차가 있을 수 있다
addAll 따위의 bulk 연산은 원자적으로 실행되지 않을 수 있다
Collection, Iterator의 모든 선택적 연산을 구현했다
ConcurrentlinkedDeque<E>
크기 제한 없고, 스레드-안전한 연결된 Deque
size 계산에 순회가 필요하므로, 오차가 있을 수 있다
addAll 따위의 bulk 연산은 원자적으로 실행되지 않을 수 있다
Collection, Iterator의 모든 선택적 연산을 구현했다
ConcurrentMap<K, V>
스레드-안전, 작업의 원자성 보장
Map의 각 연산, Map이 반환하는 컬렉션들의 연산 모두 재정의해야 한다
ConcurrentNavigableMap<K, V>
NavigableMap 연산을 지원하는 ConcurrentMap
ConcurrentHashMap<K, V>
읽기 연산에 대해서는 완전한 동시성을, 갱신 연산에 대해서는 높은 수준의 동시성을 제공
Hashtable의 모든 연산을 구현했다. 읽기 연산에 대해 원소를 잠그지는 않으며, 테이블 전체를 잠그는 기능 또한 없다. 가져간 원소를 사용하려고 하는 시점에는 맵에서 제거됐을 수도 있다
카운터로 사용할 수 있다. 예. map.computeIfAbsent(key, x -> new LongAdder()).increment();
Map, Iterator의 모든 선택적 연산을 구현했다
3가지 Bulk 연산을 지원한다 : forEach, search, reduce
인자로 받은 parallelismThreshold보다 맵이 작다고 판단되면 순차적으로 원소를 소비, 그 외엔 병렬로 소비. 1이면 최대 병렬성, Long.MAX_VALUE면 병렬 X
모든 작업 메서드의 매개변수는 non-null이어야 한다
↓ java
long mappingCount()
// 크기가 매우 큰 경우, Map.size() 대신 이용
void forEach(long parallelismThreshold, BiConsumer<? super K, ? super V> action)
// + forEachKey, forEachValue, forEachEntry
<U> U search(long parallelismThreshold, BiFunction<? super K, ? super V, ? extends U> searchFunction)
// 엔트리에 searchFunction를 적용했을 때 결과가 non-null인 것 하나 반환. 없으면 null
// + searchKeys, searchValues, searchEntries
<U> U reduce(long parallelismThreshold, BiFunction<? super K, ? super V, ? extends U> transformer, BiFunction<? super U, ? super U, ? extends U> reducer)
// + reduceToDouble ~ Int, reduceKeys, reduceKeysToDouble ~ Int, reduceValues, reduceValuesToDouble ~ Int, reduceEntries, reduceEntriesToDouble ~ Int
ConcurrentSkipListMap<K,V>
ConcurrentNavigableMap 구현체. 평균 log(n) 시간이 소요되는, 스레드-안전한SkipList 구현을 이용
오름차순 정렬된 뷰와 이터레이터가 내림차순보다 빠르다
putAll과 같은 bulk 연산은 원자적으로 종료되지 않을 수 있다
Map, Iterator의 모든 선택적 연산을 구현했다
ConcurrentSkipListSet<E>
ConcurrentSkipListMap을 이용한 NavigableSet
실행 기법
Semaphore
제한된 수의 접근 권한을 acquire()로 획득, release()로 반환
fairness : acquire()호출 순서대로 권한 획득. default false
↓ java
void acquire()
// 권한을 하나 요구한다. 권한을 얻을 때까지 대기하며, 대기 중인 스레드는 인터럽트될 수 있다
void acquireUninterruptibly()
// 대기 중일 때 인터럽트되더라도 계속 대기한다. 인터럽트되지 않았을 경우와 권한을 얻는 시기가 달라질 수 있다
boolean tryAcquire()
void release()
int availablePermits()
int drainPermits()
// 가용한 모든 권한을 얻는다. 만약 음수라면 release하여 0으로 맞춘다
boolean isFair()
final boolean hasQueuedThreads()
final int getQueueLength()
CountDownLatch
count가 0일 될때까지(원하는 작업들이 완료될 때까지), 1개 이상의 스레드가 대기하는 동기화 제공
↓ java
public CountDownLatch(int count)
void await()
// count가 0이 될때까지 대기한다. 대기 중에 인터럽트될 수 있다
boolean await(long timeout, TimeUnit unit)
// 대기 중에 timeout을 넘으면 즉시 false 반환
void countDown()
// --count, count가 0이면 대기하는 모든 스레드를 깨운다
CyclicBarrier
스레드들이 공통의 목적이 달성되기까지 함께 대기. 그 목적을 barrier라고 하며, barrier를 재사용할 수 있어 cyclic하다
↓ java
public CyclicBarrier(int parties, Runnable barrierAction)
// barrierAction : barrier를 넘을 때 실행. 지정하지 않은 경우, 대기하던 스레드를 깨우기만 한다
int getParties()
int await()
// 마지막 스레드가 await을 호출할 때까지 대기한다. 대기 중에 인터럽트될 수 있다
// 현재 스레드의 대기 순번 반환. getParties() - 1이 첫 번째, 0이 마지막 스레드
int await(long timeout, TimeUnit unit)
// timeout을 초과하여 대기하면 barrier는 부서진다
boolean isBroken()
void reset()
// barrier를 초기 상태로 재설정한다. 이미 대기 중인 스레드가 있다면 BrokenBarrierException 발생
/// 부서진 barrier를 재사용하려면 별도의 동기화가 필요하므로, 차라리 새로 하나 만들자
int getNumberWaiting()
Exchanger<V>
두 스레드가 같은 시점에 값을 서로 교환하도록 해준다
↓ java
V exchange(V x)
// 다른 스레드가 같은 지점에 도달하기까지 기다렸다가, 서로 값을 교환한다
V exchange(V x, long timeout, TimeUnit unit)
// timeout 초과 시 TimeoutException 발생
Phaser
재사용 가능한 동기화 barrier. CyclicBarrier, CountDownLatch 기능에 더해 보다 유연한 메서드 제공
CyclicBarrier와 다르게 각 회전마다 총 대기하는 스레드 수가 다를 수 있다
현재 phase가 완료되기 전에 미리 이후의 phase(들)을 등록할 수 있다. 각 phase는 0부터 시작하는 번호를 가진다(Integer.MAX_VALUE에 도달하면 다음은 다시 0)
계층 구조를 구성할 수 있다. 자식 Phaser의 parties가 0이 아니게 되는 순간 parent에 등록되고, 0이 되는 순간 parent에서 제거된다
↓ java
public Phaser(int parties)
// parties : 다음 phase로 넘어가기 위해 필요한 수
public Phaser(Phaser parent, int parties)
int register()
// 새로운 phase를 등록한다
// + bulkRegister
int arrive()
// 현재 phaser에 도착한다. 다른 스레드의 도착을 기다리지는 않는다. 현재 phase 번호를 반환한다(종료됐다면 음수)
int arriveAndDeregister()
// 현재 phaser에 도착하고, 이후 phase에서는 자신이 빠짐을 알린다
int arriveAndAwaitAdvance()
// 현재 phaser에 도착하고, 현재 phase의 모든 구성원이 도착할 때까지 기다린다 == awaitAdvance(arrive())
int awaitAdvance(int phase) + awaitAdvanceInterruptibly
// 지정한 번호의 phase의 모든 구성원이 도착할 때까지 기다린다. 현재 phase의 번호와 다르거나, phaser가 종료된 경우엔 즉시 반환한다
void forceTermination()
// 계층 구조에 속해있다면, 모든 phaser가 종료된다
final int getPhase()
// 현재 phase 번호를 반환한다. Phaser가 종료됐다면 음수(마지막 phase 번호 + Integer.MAX_VALUE)를 반환한다
TimeUnit
↓ java
NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
long convert(long sourceDuration, TimeUnit sourceUnit)
void timeWait(Object obj, long timeout)
// timeout만큼 obj.wait()
void timedJoin(Thread thread, long timeout)
// timeout만큼 Thread.join()
void sleep(long timeout)
java.util.concurrent.atomic
Package Summary
변수 하나에 대한 잠금 없는 스레드-안전성을 제공한다
VarHandle을 통해 변수를 원자적으로 접근한다
AtomicBoolean, AtomicInteger 등은 일반적인 Boolean, Integer 등을 대신할 수 없다
메모리 장벽을 만나면 CPU 코어의 캐시값이 RAM으로 반영된다
VarHandle
java.lang.invoke 패키지 멤버임
하나의 변수, 매개변수, 필드 등에 대한 동적인 타입 참조. plain 읽기/쓰기, volatile 읽기/쓰기, compare-and-set 접근을 지원한다
↓ java
class AtomInt {
private static final VarHandle V;
private volatile int value = 0;
static {
VarHandle v = null;
try {
v = MethodHandles.lookup().findVarHandle(AtomInt.class, "value", int.class);
} catch (Exception e) {
}
V = v;
}
public int getAndSet(int newValue) {
int v;
do {
v = (int) V.getVolatile(this);
} while (V.compareAndSet(this, v, newValue) == false);
return v;
}
}
public class StandAloneTest {
public static void main(String[] args) throws Exception {
var i = new AtomInt();
IntStream.range(0, 100).parallel()
.forEach(n -> System.out.printf("Before : %d, After : %d\n", i.getAndSet(n), n));
}
}
↓ java
final Object get(Object... args) // 변수가 non-volatile인 것처럼 읽는다(= plain read)
final void set(Object... args) // 변수가 non-volatile, non-final인 것처럼 쓴다(= plain write)
final Object getVolatile(Object... args) // 변수가 volatile인 것처럼 읽는다
final void setVolatile(Object... args) // 변수가 volatile인 것처럼 쓴다
final Object getOpaque(Object... args)
// Opaque : Program order 순서대로 접근한다. 다른 스레드와의 조율은 없다
// + setOpaque
final Object getAcquire(Object... args) // 같은 변수에 대해 이어지는 load/store 연산이 이 접근보다 먼저 발생하지 않는다
final void setRelease(Object... args) // 같은 변수에 대한 이전의 load/store 연산이 이 접근보다 나중에 발생하지 않는다
final boolean compareAndSet(Object... args)
// 원자적으로 다음이 실행된다. getVolatile과 동일한 문맥으로 가져온 값(witness value)이 expectedValue와 동일(==)하면 setVolatile과 동일한 문맥으로 newValue 설정 후 true 반환, 그 외엔 false 반환
final Object compareAndExchange(Object... args)
// 원자적으로 다음이 실행된다. getVolatile과 동일한 문맥으로 가져온 값(witness value)이 expectedValue와 동일(==)하면 setVolatile과 동일한 문맥으로 newValue 설정. 반환값은 witness value
final Object compareAndExchangeAcquire(Object... args)
// 원자적으로 다음이 실행된다. getAcquire와 동일한 문맥으로 가져온 값(witness value)이 expectedValue와 동일(==)하면 set와 동일한 문맥으로 newValue 설정. 반환값은 witness value
final Object compareAndExchangeRelease(Object... args)
// 원자적으로 다음이 실행된다. get와 동일한 문맥으로 가져온 값(witness value)이 expectedValue와 동일(==)하면 setRelease와 동일한 문맥으로 newValue 설정. 반환값은 witness value
final boolean weakCompareAndSetPlain(Object... args)
// 다음이 실행된다. get과 동일한 문맥으로 가져온 값(witness value)이 expectedValue와 동일(==)하면 set과 동일한 문맥으로 newValue 설정 후 true 반환. 그 외엔 false
final boolean weakCompareAndSet(Object... args) + ~Acquire, ~Release
// 다음이 실행된다. getVolatile과 동일한 문맥으로 가져온 값(witness value)이 expectedValue와 동일(==)하면 setVolatile과 동일한 문맥으로 newValue 설정 후 true 반환. 그 외엔 false
final Object getAndSet(Object... args) + ~Acquire, ~Release
// 원자적으로 다음이 실행된다. getVolatile과 동일한 문맥으로 값(witness value)을 가져오고, setVolatile과 동일한 문맥으로 newValue 설정 후 witness value 반환
final Object getAndAdd(Object... args) + ~Acquire, ~Release
// 원자적으로 값을 더한 후 이전 값 반환
final Object getAndBitwiseOr(Object... args)
// 원자적으로 OR 연산 수행 후 이전 값 반환
// + ~Acquire, ~Release, getAndBitwiseAnd~, getAndBitwiseXor~
static void acquireFence() // 장벽 이전의 load 연산이 장벽 이후의 load/store 뒤로 재배치되지 않음
static void fullFence() // 장벽 이전의 load/store 연산이 장벽 이후의 load/store 뒤로 재배치되지 않음
static void releaseFence() // 장벽 이전의 load/store 연산이 장벽 이후의 store 뒤로 재배치되지 않음
static void loadLoadFence() // 장벽 이전의 load 연산이 장벽 이후의 load 뒤로 재배치되지 않음
static void storeStoreFence() // 장벽 이전의 store 연산이 장벽 이후의 store 뒤로 재배치되지 않음
VarHandle.AccessMode
GET
VarHandle.get
SET
VarHandle.set
GET_VOLATILE
VarHandle.getVolatile
SET_VOLATILE
VarHandle.setVolatile
GET_ACQUIRE
VarHandle.getAcquire
SET_RELEASE
VarHandle.setRelease
GET_OPAQUE
VarHandle.getOpaque
SET_OPAQUE
VarHandle.setOpaque
COMPARE_AND_SET
VarHandle.compareAndSet
COMPARE_AND_EXCHANGE
VarHandle.compareAndExchange
COMPARE_AND_EXCHANGE_ACQUIRE
VarHandle.compareAndExchangeAcquire
COMPARE_AND_EXCHANGE_RELEASE
VarHandle.compareAndExchangeRelease
WEAK_COMPARE_AND_SET_PLAIN
VarHandle.weakCompareAndSetPlain
WEAK_COMPARE_AND_SET
VarHandle.weakCompareAndSet
WEAK_COMPARE_AND_SET_ACQUIRE
VarHandle.weakCompareAndSetAcquire
WEAK_COMPARE_AND_SET_RELEASE
VarHandle.weakCompareAndSetRelease
GET_AND_SET
VarHandle.getAndSet
GET_AND_SET_ACQUIRE
VarHandle.getAndSetAcquire
GET_AND_SET_RELEASE
VarHandle.getAndSetRelease
GET_AND_ADD
VarHandle.getAndAdd
GET_AND_ADD_ACQUIRE
VarHandle.getAndAddAcquire
GET_AND_ADD_RELEASE
VarHandle.getAndAddRelease
GET_AND_BITWISE_OR
VarHandle.getAndBitwiseOr
GET_AND_BITWISE_OR_RELEASE
VarHandle.getAndBitwiseOrRelease
GET_AND_BITWISE_OR_ACQUIRE
VarHandle.getAndBitwiseOrAcquire
GET_AND_BITWISE_AND
VarHandle.getAndBitwiseAnd
GET_AND_BITWISE_AND_RELEASE
VarHandle.getAndBitwiseAndRelease
GET_AND_BITWISE_AND_ACQUIRE
VarHandle.getAndBitwiseAndAcquire
GET_AND_BITWISE_XOR
VarHandle.getAndBitwiseXor
GET_AND_BITWISE_XOR_RELEASE
VarHandle.getAndBitwiseXorRelease
GET_AND_BITWISE_XOR_ACQUIRE
VarHandle.getAndBitwiseXorAcquire
AtomicBoolean
↓ java
final boolean get() // VarHandle::getVolatile
final boolean compareAndSet(boolean expectedValue, boolean newValue) // VarHandle::compareAndSet
boolean weakCompareAndSetPlain(boolean expectedValue, boolean newValue) // VarHandle::weakCompareAndSetPlain
final void set(boolean newValue) // VarHandle::setVolatile
final void lazySet(boolean newValue) // VarHandle::setRelease
final boolean getAndSet(boolean newValue) // VarHandle::getAndSet
final boolean getPlain() // VarHandle::get
final void setPlain(boolean newValue) // VarHandle::set
final boolean getOpaque() // VarHandle::getOpaque
final void setOpaque(boolean newValue) // VarHandle::setOpaque
final boolean getAcquire() // VarHandle::getAcquire
final void setRelease(boolean newValue) // VarHandle::setRelease
final boolean compareAndExchange(boolean expectedValue, boolean newValue)
// 메모리 영향은 VarHandle::compareAndExchange와 같다
// + ~Acquire, ~Release
final boolean weakCompareAndSetVolatile(boolean expectedValue, boolean newValue)
// 메모리 영향은 VarHandle::weakCompareAndSet와 같다
// + ~Acquire, ~Release
해당 필드를 단일 업데이터로만 접근한다면, compareAndSet 메서드들이 원자적으로 작동됨이 보장된다
지원하는 메서드는 AtomicInteger와 유사하다
AtomicMarkableReference<V>
원자적으로 갱신되는 마커 bit와 객체 참조 쌍
↓ java
public AtomicMarkableReference(V initialRef, boolean initialMark)
V getReference()
V get(boolean[] markHolder)
// 값 V를 반환하고, markHolder[0]에는 마커 bit 설정
boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark)
// 기존 참조와 마커 bit가 모두 예상과 동일(==)하다면 원자적으로 갱신하고 true 반환. 그 외엔 false
// + weakCompareAndSet
void set(V newReference, boolean newMark)
boolean attemptMark(V expectedReference, boolean newMark)
// 기존 참조가 예상과 동일(==)하다면, 마커 bit를 원자적으로 갱신하고 true 반환. 그 외엔 false
AtomicStampedReference<V>
원자적으로 갱신되는 index와 참조 쌍
↓ java
public AtomicStampedReference(V initialRef, int initialStamp)
V getReference()
V get(int[] stampHolder)
// 값 V를 반환하고, stampHolder[0]에는 index 설정
boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)
// 기존 참조와 인덱스가 예상과 동일(==)하다면 원자적으로 갱신하고 true 반환. 그 외엔 false
// + weakCompareAndSet
void set(V newReference, int newStamp)
boolean attempStamp(V expectedReference, int newStamp)
//기존 참조가 예상과 동일(==)하다면, 인덱스를 원자적으로 갱신하고 true 반환. 그 외엔 false
LongAdder
초깃값 0으로 시작하는 스레드-안전한 합계
합의 순서는 정의되지 않으므로 순서에 상관 없는 경우에 이용해야 한다
+ DoubleAdder
↓ java
void add(long x)
void increment()
void decrement()
long sum() // 현재 합계
void reset()
long sumThenReset()
LongAccumulator
특정 값과 특정 함수로 갱신되는 long 값 유지
주어진 accumulatorFunction은 부작용이 없어야 한다
+ DoubleAccumulator
↓ java
void accumulate(long x)
long get()
void reset()
long getThenReset()
java.util.function
Consumer : void accept(T)
IntConsumer : void accept(int)
BiConsumer : void accept(T, U)
ObjIntConsumer : void accept(T, int)
Supplier : T get()
IntSupplier : int getAsInt()
Function : R apply(T)
IntFunction : R apply(int)
DoubleToIntFunction : int applyAsInt(double)
+ double, int, long 간의 모든 상호 변환
UnaryOperator : T apply(T)
IntUnaryOperator : int applyAsInt(int)
ToIntFunction : int applyAsInt(T)
BiFunction : R apply(T, U)
ToIntBiFunction : int applyAsInt(T, U)
BinaryOperator : T apply(T, T)
IntBinaryOperator : int applyAsInt(int, int)
Predicate : boolean test(T)
IntPredicate : boolean test(int)
BiPredicate : boolean test(T, U)
java.util.regex
MatchResult
정규표현식 매칭 결과. group의 의미에 대해선 Pattern 참고
↓ java
int start() // 매치된 결과의 시작 인덱스 반환
int start(int group) // group번째 매치된 결과의 시작 인덱스 반환
int end() // 매치된 결과의 마지막 글자 다음 인덱스 반환
int end(int group) // group번째 매치된 결과의 마지막 글자 다음 인덱스 반환
String group() // 이전 매치된 결과 반환
String group(int group) // group번째 매치된 결과 반환
int groupCount() // 매치된 group 개수 반환
Pattern
↓ java
public static final int UNIX_LINES // 줄끝 '\n'만 ., ^, $에서 동작. (?d) 플래그도 같은 의미
public static final int CASE_INSENSITIVE // 대소문자 구분 없음. (?i) 플래그도 같은 의미
public static final int COMMENTS // 공백과 주석 허용. 공백과 #부터 줄 끝까지의 주석이 무시된다. (?x) 플래그도 같은 의미
public static final int MULTILINE // ^, $이 각 줄의 끝을 기준으로도 작동; 기본 동작은 입력 시작과 끝에서만 작동. (?m) 플래그도 같은 의미
public static final int LITERAL // 표현식 전체를 상수 문자열 취급
public static final int DOTALL // .이 줄 끝도 포함하여 매치; 기본 동작은 줄 끝 문자는 미포함. (?s) 플래그도 같은 의미
public static final int UNICODE_CASE // CASE_INSENSITIVE 플래그가 유니코드 표준 상에서 동작한다; 기본은 US-ASCII에서만 동작. (?u) 플래그도 같은 의미
static Pattern compile(String regex)
static boolean matches(String regex, CharSequence input) // 1회용
static String quote(String s) // s를 매칭할 수 있는 정규표현식 리터럴 문자열 표현을 반환
Predicate<String> asPredicate()
Stream<String> splitAsStream(CharSequence input)
Line terminator
↓ java
"\n", "\r\n", "\r", "\u0085", "\u2028", "\u2029"
// UNIX_LINES 모드에서는 "\n"만 줄 끝으로 인식
Groups and capturing
Group : 괄호로 감싸인 정규표현식 (X)
Capturing group : 괄호 순서에 따라 그룹에 ID가 매겨지며, 이는 나중에 참조(backreference)될 수 있다
0번 그룹은 항상 전체 표현을 가리킨다 (A)(B(C))에 대하여,
Group ID
Pattern
0
(A)(B(C))
1
(A)
2
(B(C))
3
(C)
Non-capturing group : (?:X)는 후참조(backreference)할 수 없다
Pattern.matcher(CharSequence)로부터 만들어지는 매칭 엔진으로, 아래 세 가지 작업을 수행한다
matches() : 전체 입력에 대해 패턴 매칭
lookingAt() : 입력 시작부분 패턴 매칭
find() : 입력의 다음 부분 패턴 매칭
↓ java
MatchResult toMatchResult()
Stream<MatchResult> results()
Matcher usePattern(Pattern newPattern)
Matcher reset()
int start(String name) // 주어진 식별자에 해당하는 그룹의 시작 인덱스 반환
int end(String name)
String group(String name)
static String quoteReplacement(String s)
// appendReplacement 메서드의 replacement로 사용될 s의 리터럴 표기를 반환
Matcher appendReplacement(StringBuffer sb, String replacement)
// 1. 입력 소스의 append position부터 start() 전까지 sb에 추가
// 2. replacement를 sb에 추가
// 3. 현재 matcher의 append position을 end()로 설정
StringBuffer appendTail(StringBuffer sb)
// 입력 소스의 append position부터를 sb에 추가
// appendReplacement 메서드를 호출한 뒤에 이를 호출하여 나머지 부분을 복사할 목적으로 만들어짐
String replaceAll(String replacement)
// 입력 소스의 모든 매칭되는 부분을 replacement로 변경
String replaceAll(Function<MatchResult, String> replacer)
String replaceFirst(String replacement)
Matcher region(int start, int end)
// 입력 소스의 특정 구간을 매칭 대상으로 하도록 초기화한다. transparency, anchoring 속성에 따라 동작이 다르다
Matcher useTransparentBounds(boolean b)
// region의 경계 너머를 패턴 매칭에 보이도록 할지 여부
Matcher useAnchoringBounds(boolean b)
// region의 경계에서 ^, $를 작동하게 할지 여부
java.util.stream
BaseStream<T, S extends BaseStream<T,S>>
↓ java
Iterator<T> iterator()
Spliterator<T> spliterator()
boolean isParallel()
S sequential() // 순차적인 스트림 반환(어쩌면 자기 자신)
S parallel() // 병렬적인 스트림 반환(어쩌면 자기 자신)
S unordered() // 순서 없는 스트림 반환(어쩌면 자기 자신)
S onClose(Runnable closeHandler)
static IntStream range(int startInclusive, int endExclusive)
static IntStream rangeClosed(int startInclusive, int endInclusive)
Stream<T>
2가지 스트림 연산
Terminal Operation
종결 연산. 스트림 연산 파이프라인의 마지막으로, 더 이상 스트림 연산을 수행할 수 없다
Intermediate Operation
중간 연산. 새로운 스트림을 반환한다
2가지 중간 연산
Stateless Operation
요소의 연산 과정에 상태의 보존이 필요 없는 경우. filter, map 등
Stateful Operation
요소의 연산 과정에 상태의 보존이 필요한 경우. sorted, distinct 등 이러한 연산을 사용하기 위해선 스트림 전체 인풋이 필요할 수 있으며, 병렬 스트림에서는 요구되는 버퍼의 크기가 늘어나게 된다
↓ java
static <T> Stream<T> empty()
static <T> Stream<T> of(T t)
static <T> Stream<T> ofNullable(T t)
static <T> Stream<T> of(T... values)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> generate(Supplier<? extends T> s)
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
// 중간 연산
Stream<T> filter(Predicate<? super T> predicate)
// predicate이 true인 요소만 남긴다
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
// mapper : 하나의 T 변수에서 하나의 R 변수로 대응하는 변환
IntStream mapToInt(ToIntFunction<? super T> mapper)
// + long, double
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
// mapper : 하나의 T 변수에서 여러 R 변수(R 스트림)로 대응하는 변환
// mapper를 이용해 만들어진 여러 R 스트림을 일렬로 펴서(flattening) 하나의 R 스트림으로 변환. mapper가 null을 반환하면 빈 스트림을 대신 이용
// 최종적으로 반환되는 스트림 외의 모든 중간 스트림은 닫힌다
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper )
// + long, double
Stream<T> distinct()
// Object.equals(Object)를 이용해 유일한 것들만으로 구성. stateful 중간 연산
Stream<T> sorted()
// 자연스러운 방향으로 정렬. T가 Comparable하지 않으면 예외 발생할 수 있음. stateful 중간 연산
Stream<T> sorted(Comparator<? super T> comparator)
Stream<T> peek(Consumer<? super T> action)
// forEach와 유사한 기능을 하는 중간 연산. 다른 중간 연산 전후의 값을 살펴보는 디버깅 용도로 만들어짐
Stream<T> limit(long maxSize)
// 스트림의 크기가 maxSize 이하가 되도록 한다. short-circuiting stateful 중간 연산
Stream<T> skip(long n)
// n개를 버린 나머지로 스트림을 구성해 반환한다. 더 없으면 빈 스트림이 반환된다
default Stream<T> takeWhile(Predicate<? super T> predicate)
// 요소들을 하나씩 검사하여, predicate을 만족하지 않는 요소가 나오기 전까지로 구성된 스트림을 반환한다
// 순서 있는 스트림에 대하여는 조건을 만족하는 최장 길이 접두 요소들을 얻게 되며, 순서 없는 스트림은 조건을 만족하는 부분 집합을 얻게 된다
// short-circuiting stateful 중간 연산
// 일반적으로 연산이 저렴하지만, 순서 있는 병렬 스트림에 대하여는 최장 길이 접두 요소들을 찾기 위해 연산이 비싸지므로, 허용된다면 순서 없는 스트림 소스(generate(Supplier))를 이용하거나, BaseStream.unordered()를 이용해 순서를 없애는 것이 성능에 도움이 될 것이다
default Stream<T> dropWhile(Predicate<? super T> predicate)
// stateful 중간 연산
// 종결 연산
void forEach(Consumer<? super T> action)
void forEachOrdered(Consumer<? super T> action)
// 순서 있는 스트림의 경우, 이를 이용하면 요소의 순서대로 소비자가 실행된다
Object[] toArray()
<A> A[] toArray(IntFunction<A[]> generator)
// generator : 배열 크기를 먹고 배열을 뱉는 함수. 예: A[]::new
T reduce(T identity, BinaryOperator<T> accumulator)
// 하나의 T 변수로 축약하는 종결 연산. 아래와 동치다
{
var result = identity;
for(T element : stream)
result = accumulator.apply(result, element);
return result;
}
Optional<T> reduce(BinaryOperator<T> accumulator)
// 하나의 T로 축약하는 종결 연산. 처음 연산 결과는 null이며, 스트림 첫 번째 요소를 만나면 치환된다. 이후는 reduce(T, BinaryOperator)와 같다
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
// 하나의 U 변수로 축약하는 종결 연산. 연산은 reduce(T, BinaryOperator)와 동일한데, identity 값은 combiner 연산에 대한 항등원이어야 한다
// 다시 말해, 임의의 U 타입 변수 u에 대하여 u == combiner(identity, u)를 만족해야 한다
// 이는 연산 과정에서 다음의 검사를 통해 검증된다. combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
// 이것보다는 map과 reduce를 쪼개 이용하는 것이 훨씬 간결
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
// 하나의 R 변수로 축약하는 종결 연산. reduce와 다르게 R 자체가 결과값에 대한 가변적인 컨테이너(ArrayList, String 등)가 되어야 한다. 아래와 동치다
// 여기서는 combiner를 사용하지 않는 것처럼 보이지만, combiner는 병렬 스트림 연산을 위해 존재하는 것이므로, 연산 결과 자체는 아래와 동치가 맞다
{
var result = supplier.get();
for(T element : stream)
accumulator.accept(result, element);
return result;
}
// 용례
{
collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
collect(StringBuilder::new, StringBuilder::append, StringBuilder::append);
}
<R, A> collect(Collector<? super T, A, R> collector)
// collect(Supplier, BiConsumer, BiConsumer)의 매개변수를 캡슐화한 Collector를 이용
// Collectors 유틸리티 클래스에 이미 정의된 Collector들이 있으니 편하게 이용 가능
Optional<T> min(Comparator<? super T> comparator)
long count()
// 개수를 반환하는 종결 연산
boolean anyMatch(Predicate<? super T> predicate)
// short-circuiting 종결 연산
// + allMatch, noneMatch
Optional<T> findFirst()
// short-circuiting 종결 연산
// + findAny
static enum Collector.Characteristics {
CONCURRENT, IDENTITY_FINISH, UNORDERED;
}
Supplier<A> supplier()
// 결과 컨테이너인 A를 생성하는 함수 반환
BiConsumer<A, T> accumulator()
// A의 결과에 T 타입 데이터를 축적하는 함수
BinaryOperator<A> combiner()
// 두 결과 컨테이너를 받아 하나로 반환하는 함수
Function<A, R> finisher()
// 결과 컨테이너로부터 최종 결과 R로 변환하는 함수 반환
Set<Collector.Characteristics> characteristics()
static <T, A, R> Collector<T, A, R> of(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher, Collector.Characteristics... characteristics)
public ZipInputStream(InputStream in, Charset charset)
ZipEntry getNextEntry()
void closeEntry()
// 현재 ZipEntry를 닫고 읽기 위치를 다음 entry로 이동
int available()
// EOF를 만났으면 0, 아니면 1
ZipOutputStream
↓ java
public ZipOutputStream(OutputStream out, Charset charset)
void setComment(String comment)
void setMethod(int method)
// ZipEntry에 설정되지 않은 경우 사용하는 압축 방법 : DEFLATED(압축, 기본값), STORED(비압축)
void setLevel(int level)
// 압축 레벨 : 0(BEST_SPEED) ~ 9(BEST_COMPRESSION). 기본은 DEFAULT_COMPRESSION(-1)이며, 보통 6
void putNextEntry(ZipEntry e)
void closeEntry()
// 현재 ZipEntry를 닫고 다음 쓰기 위치로 이동. putNextEntry 메서드는 쓰기 전에 알아서 닫는다
void finish()
// 쓰기를 종료하고 스트림을 닫는다. 동일한 출력 스트림에 여러 필터를 적용한 경우에 사용
ZipEntry
↓ java
public ZipEntry(String name)
public ZipEntry(ZipEntry e) // e로 필드를 채운다
String getName()
ZipEntry setLastModifiedTime(FileTime time)
ZipEntry setLastAccessTime(FileTime time)
ZipEntry setCreationTime(FileTime time)
void setSize(long size)
// 비압축 크기 설정
void setCompressedSize(long csize)
void setCrc(long crc)
void setMethod(int method)
// DEFLATED(압축), STORED(비압축), -1(미설정)
void setExtra(byte[] extra)
void setComment(String comment)
boolean isDirectory()
// 이름이 "/"로 끝나면 디렉터리
ZipFile
↓ java
public ZipFile(File file, int mode)
// UTF-8
// mode : OPEN_READ | OPEN_DELETE(파일이 close 호출 전까지 삭제됨, 내용은 객체를 통해 계속 접근 가능)
public ZipFile(File file, int mode, Charset charset)
ZipEntry getEntry(String name)
InputStream getInputStream(ZipEntry entry)
// ZipFile이 닫히면 이 메서드가 반환한 모든 스트림도 같이 닫힌다
Enumeration<? extends ZipEntry> entries()
Stream<? extends ZipEntry> stream()
int size()
// entry 개수
javax.crypto
비밀키 인스턴스 획득
↓ java
new SecretKeySpec("secret".getBytes(StandardCharsets.UTF_8), "HmacSHA256");
메시지 해시 검사
↓ java
var mac = Mac.getInstance("HmacSHA256");
mac.init(key; e.g. new SecretKeySpec(...);
var hash = new String(mac.doFinal("message".getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
javax.net
SocketFactory
↓ java
static SocketFactory getDefault()
Socker createSocket(String host, int port)