-
[자바의 정석] Ch.9-2. java.lang패키지와 유용한 클래스스터디플래너/공부하기 2022. 4. 6. 22:30
2. 유용한 클래스
2.1. java.util.Objects클래스
Object클래스의 보조 클래스로 Math클래스처럼 모든 메서드가 'static'
isNull() / nonNull() / requireNonNull() 은 객체의 비교나 널 체크에 유용함.
static boolean isNull(Object obj){ /*null이면 true, null이 아니면 false*/ } static boolean nonNull(Object obj) {/* null이 아니면 true, null이면 false */ } static <T>T requireNonNull(T Obj){ /*null이 아니면 실행, null이면 NullPointerException */ }
compare()는 두 비교대상이 같으면 0, 크면 양수, 작으면 음수를 반환
Objects클래스의 equals()는 내부에서 두 매개변수의 널 검사를 한 다음 조건식 검사를 하기 때문에 널 체크를 하지 않아도 됨. deepEquals()는 객체를 재귀적으로 비교하기 때문에 다차원 배열의 비교도 가능. 기존 equals()와 반복분을 사용하던 것을 deepEquals()를 사용하면 간단하게 해결할 수 있음.
toString()도 동일하게 널 체크 후 문자열로 변환하고, hashCode()도 널 검사 후 Object의 hashCode()를 호출. Null이면 0 반환.
static int compare(Object a, Object b, Comparator c){ } static booelan equals(Object a, Object b){ } static String toString(Object o){ } static String toString(Object o, String nullDefault){ /* nullDefault = null일 때 반환할 메세지*/ } static int hashCode(Object o){ } static int hash(Object... values ){ }
import java.util.Comparator; import java.util.Objects; public class ObjectsTest { public static void main(String[] args) { String[][] str2D = new String[][]{{"abc", "efg"}, {"ABC", "EFG"}}; String[][] str2D_2 = new String[][]{{"abc", "efg"}, {"ABC", "EFG"}}; String[][] str2D_3 = new String[][]{{"def", "abc"}, {"DEF", "ABC"}}; System.out.println(Objects.deepEquals(str2D, str2D_2)); System.out.println(Objects.deepEquals(str2D, str2D_3)); System.out.println(); Comparator comp = String.CASE_INSENSITIVE_ORDER; //대소문자 구분 안 하는 비교 System.out.println(Objects.compare("aa", "bb", comp)); System.out.println(Objects.compare("bb", "aa", comp)); System.out.println(Objects.compare("aa", "AA", comp)); } }
2.2. java.util.Random클래스
Math.random()이 내부적으로 Random클래스의 인스턴스를 생성하여 사용하여 Random클래스를 이용해서 난수를 얻을 수 있음.
Random클래스는 종자값을 설정할 수 있는데, 종자값이 같은 Random인스턴스는 항상 같은 난수를 같은 순서대로 반환함.
Random클래스의 생성자와 메서드
public Random(){ this(System.currentTimeMillis()); //Random(long seed)를 호출 }
메서드 설명 Random() 현재시간(System.currentTimeMillis())을 종자값(seed)으로 이용하는 Random인스턴스를 생성 Random(long seed) 매개변수seed를 종자값으로 하는 Random인스턴스를 생성 boolean nextBoolean() boolean타입의 난수를 반환 void nextBytes(byte[] bytes) bytes배열에 byte타입의 난수를 채워 반환 double nextDouble() double타입의 난수를 반환 float nextFloat() float타입의 난수를 반환 double nextGaussian() 평균 0,0이고 표준편차는 1.0인 가우시안(Gaussian)분포에 따른 double형의 난수를 반환 int nextInt() int타입의 난수를 반환 int nextInt(int n) 0~n의 범위에 있는 int값을 반환 long nextLong() long타입의 난수를 반환 void setSeed(long seed) 종자값을 주어진 값(seed)으로 변경 2.3. 정규식(Regular Expression) - java.util.regex패키지
정규식이란 텍스트 데이터 중에서 원하는 조건(패턴, pattern)과 일치하는 문자열을 찾아내기 위해 사용하는 것으로 미리 정의된 기호와 문자를 이용해서 작성한 문자열. 정규식을 이용하면 많은 양의 텍스트 파일 중 원하는 데이터를 손쉽게 뽑아낼 수 있고 입력된 데이터가 형식에 맞는지 체크할 수 있음.
// 1.정규식을 매개변수로 Pattern 클래스의 static메소드인 Pattern compile(String regex)을 호출하여 Pattern 인스턴스를 얻는다. Patttern pattern = Pattern.compile("c[a-z]*"); // 2.정규식으로 비교할 대상을 매개변수로 Pattern클래스의 Matcher matcher(CharSequence input)를 호출해서 Matcher인스턴스를 얻는다. Matcher matcher = pattern.matcher(data[i]); // 3.Matcher인스턴스에 boolean matches()를 호출해서 정규식에 부합하는지 확인한다. if(matcher.matches())
정규식 패턴 설명 결과 c[a-z]* c로 시작하는 영단어 c, ca, co, car, combat, count c[a-z] c로 시작하는 두 자리 영단어 ca, co c[a-zA-Z] c로 시작하는 두 자리 영단어(a~z 또는 A~Z, 대소문자 구분 안 함) cA, ca, co c[a-zA-Z0-9]c\w c로 시작하고 숫자와 영어로 조합된 두 글자 ca, cA, co, c0 .* 모든 문자열 bat, baby, bonus, c, cA, ca, co, c., c-, c#, car, combat, count, date, disc c. c로 시작하는 두 자리 문자열 cA, ca, co, c., c0. c# c.* c로 시작하는 모든 문자열(기호 포함) cA, ca, co, c., c0. c#, car, combat, count c\. c.와 일치하는 문자열. '.'은 패턴작성에 사용되는 문자이므로 escape문자인 '\'를 사용해야 함 c. c\d
c[0-9]c와 숫자로 구성된 두 자리 문자열 c0 c.*t c로 시작하고 t로 끝나는 모든 문자열 combat, count [b|c].*
[bc].*
[b-c].9*b 또는 c로 시작하는 문자열 bat, baby, bonus, c, cA, ca, co, c., c0. c#, car, combat, count [^b|c].*
[^bc].*
[^b-c].*b 또는 c로 시작하지 않는 문자열 date, disc .*a.* a를 포함하는 모든 문자열
*: 0 또는 그 이상의 문자bat, baby, ca, car, combat, date .*a.+ a를 포함하는 모든 문자열
+: 1 또는 그 이상의 문자.bat, baby, car, combat, date [b|c].{2} b 또는 c로 시작하는 세 자리 문자열. (b 또는 c 다음에 두 자리이므로 모두 세 자리) bat, car 정규식의 일부를 괄호로 나누워 묶어서 그룹화할 수 있음. 그룹화된 부분은 group(int i)를 이용해서 나눠 얻을 수 있음
find()는 주어진 소스 내에서 패턴과 일치하는 부분을 찾아내면 true, 못찾으면 false를 반환
Matcher의 find()로 정규식과 일치하는 부분을 찾으면 그 위치를 start()와 end()로 알아낼 수 있고 appendReplacement(StringBuffer sb, String replacement)를 이용해서 원하는 문자열(replacement)로 치환할 수 있음
import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ObjectsTest { public static void main(String[] args) { String source = "A broken hand works, but not a broken heart."; String pattern = "broken"; StringBuffer sb = new StringBuffer(); Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(source); System.out.println("source: " + source); int i=0; while (m.find()){ System.out.println(++i + "번째 매칭: " + m.start() + " ~ " + m.end()); //broken을 drunken으로 치환하여 sb에 저장 m.appendReplacement(sb, "drunken"); } m.appendTail(sb); System.out.println("Replacement count: " + i); System.out.println("result: " + sb.toString() ); } } // 1. 문자열 source에서 "broken"을 m.find()로 찾은 후 처음으로 m.appendReplacement(sb, "drunken");가 호출되면source의 시작부터 "broken"을 찾은 위치까지의 내용에 "drunken"을 더해서 저장한다. // 2. m.find()는 첫 번째로 발견된 위치의 끝에서부터 다시 검색을 시작하여 두 번째 "broken"을 찾게 된다. 다시 m.appendReplacement(sb, "drunken");가 호출 // 3. m.appendTail(sb);이 호출되면 마지막으로 치환된 이후의 부분을 sb에 덧붙인다.
2.4. java.util.Scanner클래스
Scanner는 화면, 파일, 문자열과 같은 입력소스로부터 문자데이터를 읽어오는데 도움을 줄 목적으로 JDK1.5부터 추가됨.
//JDK1.5 이전 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //JDK1.5 이후 Scanner scan = new Scanner(System.in); String input = s.nextLinke(); //JDK1.6 이후 Console console = Systemconsole(); String input = console.readLine(); boolean nextBoolean(){ } byte nextByte(){ } short nextShort(){ } int nextInt(){ } long nextLong(){} double nextDouble(){ } float nextFloat(){ } String nextLine(){ }
2.5. java.util.StringTokenizer클래스
StringTokenizer는 긴 문자열을 지정된 구분자(delimiter)를 기준으로 토큰이라는 여러 개의 문자열로 잘라내는 데 사용. String클래스의 split(String regex), Scanner클래스의 useDelimiter(String pattern)를 사용할 수 있지만 이 두 가지 방법은 정규식을 사용해야하므로 StringTokenizer를 사용하면 간단하게 결과를 얻을 수 있음.
StringTokenizer클래스의 생성자와 메서드
생성자 메서드 StringTokenizer(String str, String delim) 문자열(str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성 StringTokenizer(String str, String delim, boolean returnDelims)) 문자열(str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성. returnDelim의 값을 true로 하면 구분자도 토큰으로 간주 int countToken() 전체 토큰의 수를 반환 boolean hasMoreTokens 토큰이 남아있는 아빠를 알려줌 String nextToekn() 다음 토큰을 반환 split()은 빈 문자열도 토큰으로 인식하지만 StringTokenizer는 빈 문자열은 토큰으로 인식하지 않아 split()으로 생성된 배열의 길이와 StringTokenizer로 생성된 토큰의 길이가 다를 수 있음 → split()은 데이터를 토큰으로 잘라낸 결과를 배열에 담아서 반환하기 때문에 토큰을 바롸바로 잘라 재환하여 인식하는 StringTokenizer보다 성능이 떨어짐.
2.6. java.math.BigInteger클래스
long으로 표현할 수 있는 값은 10진수 19자리 → 이보다 더 큰 값을 다뤄야 할 필요가 있음 → long보다 성능이 떨어지지만 long보다 편한값을 구할 수 있는 BigInteger 사용.
BigInteger의 생성
BigInteger val; val = new BigInteger("12345678901234567890"); //문자열로 생성 val = new BigInteger("FFFF", 16); //n진수(radix)의 문자열로 생성 val = BigInteger.valueOf(1234567890L); //숫자로 생성
다른 타입으로의변환
String toString(){ /*문자열로 변환*/ } String toString(int radix){ /*지정된 진법(radix)의 문자열로 변환*/} byte[] toByteArray(){ /*byte배열로 변환*/ } //Number로부터 상속받은 기본형으로 변환하는 메서드 int intValue(){} long longValue(){} float floatValue(){} double doubleValue(){} //변환한 결과가 변환한 타입의 범위에 속하지 않으면 ArithmeticException을 발생 byte byteValueExact(){} int intValueExact(){} long longValueExact(){}
BigIntegerd의 연산
//BigIntege는 불변이므로 연산 후 결과값은 새로운 인스턴스로 반환 BigInteger add(BigInteger val) //덧셈(this + val) BigInteger subtract(BigInteger val) //뺄셈(this - val) BigInteger multiply(BigInteger val) //곱셈(this * val) BigInteger divide(BigInteger val) //나눗셈(this / val) BigInteger remainder(BigInteger val) //나머지(this % val)
비트 연산 메서드
//큰 숫자를 다루기 위한 클래스이므로, 성능을 향상시키기 위해 비트단위로 연산을 수행하는 메서드가 많음 int bitCount(){ /* 2진수로 표현했을 때, 1의 개수(음수는 0의 개수)를 반환 */ } int bitLength(){ /* 2진수로 표현했을 때, 값을 표현하는데 필요한 bit수 */ } boolean testBit(int n){ /* 우측에서 n+1번째 비트가 1이면 true, 0이면 false */ } BigInteger setBit(int n){ /* 우측에서 n+1번째 비트를 1로 변경 */ } BigInteger clearBit(int n){ /* 우측에서 n+1번째 비트를 0으로 변경*/ } BigInteger flipBit(int n){ /* 우측에서 n+1번째 비트가 1이면 0으로, 0이면 1로 전환*/ }
2.7. java.math.BigDecimal클래스
double타입으로 표현할 수 있는 값은 상당히 범위가 넓으나, 10진 실수를 2진 실수로 변환하는 과정에서 정확히 변환할 수 없어 정밀도가 최대 13자리로 오차를 피할 수 없음 → 10진 실수를 오차가 없는 2진 정수로 변환하여 다룸(정수 * 10^-scale)
private final BigInteger intVal; //정수(unscaled value) private final int scale; //지수(scale) private transient int precision; //정밀도(precision) - 정수의 자릿수 BigDecimal val = new BigDecimal("123.45"); //12345 * 10^-2 System.out.println(val.unscaleValue()); //12345 System.out.println(val.scale()); //2 System.out.println(val.precision()); //5
BigDecimal의 생성
BigDecimal val; val = new BigDecimal("123.4567890"); //문자열로 생성 val = new BigDecimal(123.456); //double타입으로 리터럴 생성 val = new BigDecimal(123456); //int, long타입의 리터럴로 생성가능 val = BigDecimal.valueOf(123.456); //생성자 대신 valueOf(double) 사용 val = BigDecimal.valueOf(123456); //생성자 대신 valueOf(int) 사용
다른 타입으로의 변환
String toPlainString() //어떤 경우에도 다른 기호 없이 숫자로만 표현 String toString() //필요하면 지수형태로 표현할 수 있음 // Number로부터 상속받은 기본형으로 변환하는 메소드 int intValue() long llongValue() float floatValue() double doubleValue() // BigDecimal을 정수형으로 변환하는 메서드 중 변환하는 타입의 범위에 속하지 않으면 ArithmeticException 발생 byte byteValueExact() short shortValueExact() int intValueExact() long longValueExact() BigInteger toBigIntegerExact()
BigDecimal의 연산
//BigDecimal이 불변이므로 연산 결과인 반환값도 새로운 인스턴스로 반환 BigDecimal add(BigDecimal val) //덧셈(this + val) BigDecimal subtract(BigDecimal val) //뺄셈(this - val) BigDecimal multiply(BigDecimal val) //곱셈(this * val) BigDecimal divide(BigDecimal val) //나눗셈(this / val) BigDecimal remainder(BigDecimal val) //나머지(this % val)
곱셈에서는 두 피연산자의 scale을 더하고, 나눗셈에서는 빼고, 덧셈과 뺄셈에서는 둘 중자리수가 높은 쪽에 맞추기 위해 scale이 큰 쪽에 맞추기 때문에 연산결과의 정수, 지수, 정밀도가 달라짐
반올림 모드 - divide()와 setScale()
나눗셈의 결과를 어떻게 반올림 처리할 것인가(roundingMode)와 몇 번째 자리(scale)에서 반올림 할 것인지를 지정할 수 있음
BigDecimal divide(BigDecimal divisor) BigDecimal divide(BigDecimal divisor, int roundingMode) BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) BigDecimal divide(BigDecimal divisor, MathContext mc)
상수 설명 CEILING 올림 FLOOR 내림 UP 양수일 때는 올림, 음수일 때는 내림 DOWN 양수일 때는 내림, 음수일 때는 올림 HALF_UP 반올림(5이상 올림, 5미만 버림) HALF_EVEN 반올림(반올림 자리의 값이 짝수면 HALF_DOWN, 홀수면 HALF_UP) HALF_DOWN 반올림(6이상 올림, 6미만 버림) UNNECESSARY 나눗셈의 결과가 딱 떨어지는 수가 아니면 ArithmeticException 발생 java.math.MathContext
BigDecimal의 divide()에서는 scale이 소수점 이하의 자리수를 의미하지만, MathContext클래스에서 precision은 정수와 소수점 이하를 모두 포함한 자리수를 의미함.
scale의 변경
//BigDecimal을 10으로 곱하거나 나누는 대신 setScale()을 이용하여 scale의 값을 변경함으로써 같은 결과를 얻을 수 있음 //setScale()로 scale값을 줄이는 것은 10의 n제곱으로 나누는 것과 같으므로, divide()를 호출할 때처럼 오류가 발생할 수 있고 반올림 모드도 지정해 주어야 함 BigDecimal setScale(int newScale) BigDecimal setScale(int newScale, int roundingMode) BigDecimal setScale(int newScale, RoundingMode mode)
'스터디플래너 > 공부하기' 카테고리의 다른 글
[자바의 정석] Ch.11 컬렉션 프레임웍(Collections Framework) (0) 2022.05.20 [자바의 정석] Ch.11 컬렉션 프레임웍(Collections Framework) (0) 2022.05.10 [자바의 정석] Ch.9 lang패키지와 유용한 클래스 (0) 2022.03.29 [자바의 정석] Ch.8 예외처리 (0) 2022.03.22 [자바의 정석] Chapter07-3. 객체지향 프로그래밍2 (0) 2022.03.15