수학에서 자주 사용하는 상수들과 함수들을 미리 구현해 놓은 클래스
(java.lang 패키지에 포함됨)
Math 클래스의 모든 메소드는 클래스 메소드(static method)이므로, 객체를 생성하지 않고도 바로 사용할 수 있다.
Math.PI
원주율로 3.14를 의미함
random 메소드
0.0 이상 1.0 미만의 범위에서 임의의 double형 값을 하나 생성하여 반환
System.out.println((int)(Math.random() * 100)); // 0 ~ 99
// double형을 리턴하기 떄문에 int형으로 바꾸어서 소수 자리수를 버린다.
Random ran = new Random();
System.out.println(ran.nextInt(100)); // 0 ~ 99
추가로 java.util 패키지에 포함된 Random 클래스의 nextInt() 메소드를 사용해도 난수를 생성할 수 있다
abs 메소드
절대값을 반환한다
floor(), ceil(), round() 메소드
floor(): 첫째 자리에서 버림한 값을 반환한다
ceil(): 첫째 자리에서 올림한 값을 반환한다
round(): 첫쨰 자리에서 반올림한 값을 반환한다
max(), min() 메소드
두 값 중 큰/작은 값을 반환한다
System.out.println(Math.max(3.14, 3.14159)); // 3.14159
System.out.println(Math.min(3.14, 3.14159)); // 3.14
pow(), sqrt() 메소드
pow(): 제곱한 값을 반환한다
sqrt(): 제곱근을 한 값을 반환한다
System.out.println((int)Math.pow(5, 2)); // 25
System.out.println((int)Math.sqrt(25)); // 5
sin(), cos(), tan() 메소드
각각 sin, cos, tan 값을 반환한다
이 외에도 다른 Math 클래스에 수학과 관련된 함수가 정의되어 있고 필요 시 이를 찾아보고 사용하면 된다
핵심은 모든 메소드가 static 이기 때문에 객체를 생성하지 않고 사용해야 한다는 점!
8개의 기본 타입에 해당하는 데이터를 객체로 포장해주는 클래스
각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어 줌
언제 쓰는가?
종류:
Byte, Short, Integer, Long, Float, Double, Character, Boolean
래퍼 클래스(Wrapper class)는 산술 연산을 위해 정의된 클래스가 아니므로, 인스턴스에 저장된 값을 변경할 수 없다
단지, 값을 참조하기 위해 새로운 인스턴스를 생성하고, 생성된 인스턴스의 값만을 참조할 수 있습니다.
위의 그림과 같이 기본 타입의 데이터를 래퍼 클래스의 인스턴스로 변환하는 과정을 박싱(Boxing)이라고 하고 래퍼 클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정을 언박싱(UnBoxing)이라고 한다
JDK 1.5부터는 박싱과 언박싱이 필요한 상황에서 자바 컴파일러가 자동으로 이를 처리해줌
Integer num = new Integer(17); // 박싱
int n = num.intValue(); // 언박싱
Character ch = 'X'; // Character ch = new Character('X'); : 오토박싱
char c = ch; // char c = ch.charValue(); : 오토언박싱
따라서 Wrapper 클래스끼리의 연산은 auto unboxing을 통해서 기본 데이터로 변경 후 연산을 수행하는 거라고 이해하면 됨
래퍼 클래스도 객체이기 때문에 동등 연산자(==)를 사용하게 되면, 두 인스턴스의 값을 비교하는 것이 아니라 두 인스턴스의 주소값을 비교하게 되므로 값 비교시 equals() 메소드를 사용해야 한다
enum Rainbow { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
System.out.println(Rainbow.RED) // 0이 출력됨
열거체 기본적으로 0부터 시작하여 1씩 증가되며 설정된다.
하지만, 불규칙한 값을 상숫값으로 설정하고 싶으면 상수의 이름 옆에 괄호(())을 추가하고, 그 안에 원하는 상숫값을 명시할 수 있다.
하지만 이때는 불규칙한 변수의 값을 저장할 수 있는 instance 변수와 생성자를 지정해 줘야 한다
enum Rainbow {
RED(3), ORANGE(10), YELLOW(21), GREEN(5), BLUE(1), INDIGO(-1), VIOLET(-11);
private final int value;
Rainbow(int value) { this.value = value; }
public int getValue() { return value; }
}
그렇다면 열거체 왜 쓰는가?
- 타입 안전성 (Type Safety): enum은 특정한 값들만을 허용하기 때문에 잘못된 값이 들어가는 것을 컴파일 타임에 방지할 수 있다
- 코드 가독성: 의미 있는 이름을 갖는 상수를 정의할 수 있다
- 리팩토링 용이성: enum 값들은 중앙에서 관리되므로, 변경이 필요할 때 중앙의 enum 정의만 변경하면 된다
- 기능 확장: enum은 클래스와 유사하므로, 필드, 메서드, 생성자 등을 가질 수 있고 이 떄문에 각 enum 값에 특정한 기능이나 데이터를 연결시킬 수 있다
- 싱글턴 패턴: 해당 클래스의 인스턴스가 단 1개만 존재하도록 하는 객체지향프로그래밍의 패턴중 하나인 싱글턴 패턴을 구현하는 안전한 방법이다
- Switch 문과의 호환성: enum 값들은 switch 문에서 사용하기 용이하다
Enum 클래스
모등 열거체의 조상 클래스로 열거체를 조작하기 위한 메소드들을 포함한다
jdk 1.5 부터 java.lang 패키지에 포함되었다
values() 메소드
해당 열거체의 모든 상수를 저장한 배열을 생성하여 반환한다
enum Rainbow { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
public class Enum01 {
public static void main(String[] args) {
Rainbow[] arr = Rainbow.values();
for (Rainbow rb : arr) {
System.out.println(rb);
}
}
}
// 실행결과
// RED
// ORANGE
// YELLOW
//GREEN
// BLUE
// INDIGO
// VIOLET
valueOf() 메소드
전달된 문자열과 일치하는 열거체의 상수를 반환한다
enum Rainbow { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
public class Enum02 {
public static void main(String[] args) {
Rainbow rb = Rainbow.valueOf("GREEN");
System.out.println(rb);
}
}
// 실행결과
// Green
ordinal() 메소드
해당 열거체 상수가 열거체 정의에서 정의된 순서(0부터 시작)를 반환한다
enum Rainbow {
RED(3), ORANGE(10), YELLOW(21), GREEN(5), BLUE(1), INDIGO(-1), VIOLET(-11);
private final int value;
Rainbow(int value) { this.value = value; }
public int getValue() { return value; }
}
public class Enum04 {
public static void main(String[] args) {
System.out.println(Rainbow.YELLOW.ordinal());
}
}
// 실행결과
// 2
상수값이 아니라 순서를 반환하기 때문에 위의 예시에서도 상수값인 21이 아니라 순서인 2를 반환한것을 알 수 있다
그러면 불규칙한 설정값을 리턴 받고 싶을때는 어떻게 해야하지?
-> 클래스에서 작성한 getValue() 함수를 사용하면 된다
배열을 다루기 위한 다양한 메소드들을 포함한다
Arrays 클래스의 모든 메소드도 Math 클래스와 마찬가지로 클래스 메소드(static method)이므로, 객체를 생성하지 않고도 바로 사용할 수 있다
(java.util 패키지에 포함됨)
binarySearch() 메소드
전달받은 배열에서 특정 객체의 위치를 이진 검색 알고리즘을 사용하여 검색한 후, 해당 위치를 반환한다
이 메소드는 이진 검색 알고리즘을 사용하므로, 매개변수로 전달되는 배열이 sort() 메소드 등을 사용하여 미리 정렬되어 있어야만 제대로 동작한다
int[] arr = new int[1000];
for(int i = 0; i < arr.length; i++) {
arr[i] = i;
}
System.out.println(Arrays.binarySearch(arr, 437));
// 실행결과
// 437
copyOf() 메소드
앞서 배열파트에서 소개한 메소드로 전달 받은 배열을 복사하여 반환
첫 번째 매개변수로 원본 배열을 전달받고, 두 번째 매개변수로 원본 배열에서 새로운 배열로 복사할 요소의 개수를 전달 받는다
이때 새로운 배열의 길이가 원본 배열보다 길면, 나머지 요소는 배열 요소의 타입에 맞게 다음과 같은 기본값으로 채워진다
int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = Arrays.copyOf(arr1, 3);
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + " ");
}
System.out.println();
int[] arr3 = Arrays.copyOf(arr1, 10);
for (int i = 0; i < arr3.length; i++) {
System.out.print(arr3[i] + " ");
}
// 실행결과
// 1 2 3
// 1 2 3 4 5 0 0 0 0 0
copyOfRange() 메소드
전달받은 배열의 특정 범위에 해당하는 요소만을 새로운 배열로 복사하여 반환한다
두번째 매개변수로 시작 인덱스, 세번째 매개변수로 마지막 복사할 값의 인덱스 바로 다음 인덱스를 받는다
int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = Arrays.copyOfRange(arr1, 2, 4);
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + " ");
}
// 실행결과
// 3 4
fill() 메소드
전달받은 배열의 모든 요소를 특정 값으로 초기화한다
즉 원본 배열을 변경한다
int[] arr = new int[10];
Arrays.fill(arr, 7);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 실행결과
// 7 7 7 7 7 7 7 7 7 7
sort() 메소드
전달받은 배열의 모든 요소를 오름차순으로 정렬한다
즉 원본 배열의 순서를 변경한다
int[] arr = {5, 3, 4, 1, 2};
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 실행결과
// 1 2 3 4 5
Calender 클래스
프로젝트를 하면서도 날짜를 다룰 때 java.time 패키지에 속한 LocalDate, LocalDateTime을 사용하였다
java.time 패키지는 그러면 왜 생긴걸까?
Java 8에서 도입된 java.time 패키지는 날짜와 시간을 처리하는데 더 현대적이고 직관적인 API를 제공한다
Calender 객체와 달리 불변적이여서 스레드 안정성을 향상시키고 사이드 이펙트를 최소화해줌
Period 나 Duration 같은 연산 및 처리기능을 쉽게 처리할 수 있음
따라서 java.time 패키지를 사용하면 되고 나중에 이를 다룰 예정!