도도한 개발자

[Java] #20-1. java.lang - 특별한 자바랭, 숫자처리 본문

Backend/Java

[Java] #20-1. java.lang - 특별한 자바랭, 숫자처리

Kiara Kim 2022. 4. 3. 20:00

* 특별한 java.lang

 

자바의 패키지 중 유일하게 java.lang 패키지에 있는 클래스들은 import를 안해도 사용할 수 있다. java.lang과 java.util 패키지를 제외한 대부분의 java로 시작하는 패키지들은 패키지 이름만 보고도 어떤 일을 할 때 사용하는지를 알 수 있다. java.lang 패키지에서 제공하는 인터페이스, 클래스, 예외 클래스 등은 다음과 같이 분류할 수 있다.

 

º 언어 관련 기본

º 문자열 관련

º 기본 자료형 및 숫자 관련

º 쓰레드 관련

º 예외 관련

º 런타임 관련

 

각 분류에는 어떤 인터페이스, 클래스, 예외 및 에러가 있는지 알아보자.

 

구분 타입 항목들
언어 관련 기본 인터페이스 Cloneable, Comparable, Iterable, Readable
클래스 Class, ClassLoader, Compiler, Enum, Object, Package, SecurityManager, StackTraceElement, System, Void
예외 및 에러 ArrayIndexOutOfBoundsException, ArrayStoreException, ClassCastException, ClassNotFoundException, CloneNotSupportedException, EnumConstantNotPresentException, IllegalAccessException, IllegalArgumentException, IndexOutOfBoundsException, InstantiationException, NegativeArraySizeException, NoSuchFieldException, NoSuchMethodException, NullPointerException, RuntimeException, SecurityException, TypeNotPresentException, UnsupportedOperationException
문자열 관련 인터페이스 Appendable, CharSequence
클래스 String, StringBuffer, StringBuilder
예외 및 에러 StringIndexOutOfBoundsException
기본 자료형 및 숫자 관련 클래스 Boolean, Byte, Character, Character.Subset, Character.UnicodeBlock, Double, Float, Integer, Long, Math, Number, Short, StrictMath
예외 및 에러 ArithmaticException, NumberFormatException
쓰레드 관련 인터페이스 Runnable, Thread.UncaughtExceptionHandler
클래스 InheritableThreadLocal, Thread, ThreadGroup, ThreadLocal, Thread.State(Enum 타입)
예외 및 에러 IllegalMonitorStateException, IllegalThreadStateException, InterruptedException
예외 관련 클래스 Throwable
예외 및 에러 Exception
런타임 관련 클래스 Process, ProcessBuilder, Runtime, RuntimePermission
예외 및 에러 IllegalStateException

 

Bold체 항목들의 90% 이상은 알고 있자. 추가로 java.lang 패키지에 정의되어 있는 "에러" 중 가끔 볼 수 있는 에러가 있는데 바로 OutOfMemoryError(OOME)와 StackOverflowError다. OOME의 경우 메모리가 부족하여 발생하는 에러다. 자바는 가상 머신에서 메모리를 관리하지만, 프로그램을 잘못 작성하거나 설정이 제대로 되어 있지 않을 경우 이러한 에러가 발생할 수 있다. 

StackOverflowError는 호출된 메소드의 깊이가 너무 깊을 때 발생한다. 자바에서 스택이라는 영역에 어떤 메소드가 어떤 메소드를 호출했는지에 대한 정보를 관리한다. 예를 들어 메소드가 자기 자신을 호출하는 재귀 메소드를 잘못 작성했다면 스택에 쌓을 수 있는 메소드 호출 정보의 한계를 넘어설 수 있다.

 

그리고 java.lang 패키지에는 기본 어노테이션이 선언되어 있다.

 

º Deprecated

º Override

º SuppressWarnings

 

이제 java.lang 패키지에 선언되어 있는 클래스들을 살펴보자.

 

 

* 숫자 처리 클래스

 

자바에서 간단한 계산을 할 때는 대부분 기본 자료형을 사용한다. 기본 자료형은 자바의 힙(Heap)이라는 영역에 저장되지 않고, 스택이라는 영역에 저장 및 관리된다. 그런데 이런 기본 자료형의 숫자를 객체로 처리해야 할 필요가 있을 수도 있다.

 

º Byte

º Short

º Integer

º Long

º Float

º Double

º Character

º Boolean

 

Character 클래스 제외하고 나머지 클래스들은 각 기본 자료형의 이름에서 첫 문자만 대문자로 바뀌었다고 보면 된다. 그러나 Character와 Boolean을 제외한 숫자를 처리하는 클래스들은 감싼 클래스라고 불리며, 모두 Number라는 abstract 클래스를 확장한다. 그리고 겉으로 보기에는 참조 자료형이지만, 기본 자료형처럼 사용할 수 있다. 왜냐하면 자바 컴파일러에서 자동으로 형 변환을 해주기 때문이다. 

 

그리고 Character 클래스를 제외하고는 공통적인 메소드를 제공한다. parse타입이름() 메소드와 valueOf()라는 메소드다. 

다음과 같이 JavaLangNumber 클래스를 만들고 숫자 타입을 테스트 할 numberTypeCheck() 메소드도 만들어 자동 형 변환이 발생하는 것을 확인해보자.

 

public class JavaLangNumber {

	public static void main(String[] args) {
		JavaLangNumber sample = new JavaLangNumber();
		sample.numberTypeCheck();
	}
	public void numberTypeCheck() {
			String value1 = "3";
			String value2 = "5";
			byte byte1 = Byte.parseByte(value1);	// 1
			byte byte2 = Byte.parseByte(value2);	// 1
			System.out.println(byte1 + byte2);		// 2
			
			Integer refInt1 = Integer.valueOf(value1);	// 3
			Integer refInt2 = Integer.valueOf(value2);	// 3
			System.out.println(refInt1 + refInt2 + "7");	// 4
	}
}

 

1 : 3과 5라는 String 값을 parseByte() 메소드를 사용하여 byte로 변환하고

2 : 두 값을 더한 결과를 출력했다.

3 : valueOf() 메소드를 사용하며 Integer 타입으로 변환한 후 두 값을 더한 후

4 : "7"이라는 String을 더하여 출력했다.

 

이 두 메소드는 모두 static 메소드가. 따라서 따로 객체를 생성할 필요 없이 바로 사용할 수 있다. 둘 다 String과 같은 문자열을 숫자 타입으로 변환한다는 공통점이 있지만, parse타입이름() 메소드는 기본 자료형을 리턴하고, valueOf() 메소드는 참조 자료형을 리턴한다.

 

결과는 어떨끼?

 

8
87

 

첫 번째 결과가 byte 타입을 더한 것이니 8로 출력되는 것은 납득할 수 있다. 그러나 두 번째 결과가 87로 나온 것은 조금 의아하다. 왜냐하면 참조 자료형은 두 값을 더할 수 없는데 숫자 연산이 된 8이라는 값이 출력되고, "7"이 그 뒤에 붙었기 때문이다. 참조 자료형 중 더하기 연산이 가능한 것은 String 뿐이라고 했는데, 참조 자료형 중 Byte, Stort, Integer, Long, Float, Double 타입들은 필요시 기본 자료형처럼 사용할 수 있다. 따라서 new를 사용하여 객체를 만들지 않아도 값을 할당할 수 있다. 

 

따라서 다음과 같이 사용해도 전혀 문제 되지 않는다.

 

public void numberTypeCheck2() {
	Integer refInt1;
	refInt1 = 100;
	System.out.println(refInt1.doubleValue());
}

 

컴파일도, 실행도 모두 잘 된다. 그렇다면 왜 혼란스럽게 이러한 숫자를 처리하는 참조 자료형을 만들었을까?

 

º 매개 변수를 참조 자료형으로만 받는 메소드를 처리하기 위해서

º 제네릭과 같이 기본 자료형을 사용하지 않는 기능을 사용하기 위해서.

º MIN_VALUE(최소값)나 MAX_VALUE(최대값)와 같이 클래스에 선언된 상수 값을 사용하기 위해서

º 문자열을 숫자로, 숫자를 문자열로 쉽게 변환하고, 2, 8, 10, 16 진수 변환을 쉽게 처리하기 위해서

 

기본 자료형을 참조 자료형으로 만든 클래스들은 Boolean 클래스를 제외하고 모두 MIN_VALUE와 MAX_VALUE라는 상수를 갖고 있다. 해당 타입이 나타낼 수 있는 값의 범위를 확인하려면 static으로 선언된 이 상수들을 다음과 같이 사용하면 된다.

 

public void numberMinMaxCheack() {
    System.out.println("Byte min = " + Byte.MIN_VALUE + " max = " + Byte.MAX_VALUE);
    System.out.println("Short min = " + Short.MIN_VALUE + " max = " + Short.MAX_VALUE);
    System.out.println("Integer min = " + Integer.MIN_VALUE + " max = " + Integer.MAX_VALUE);
    System.out.println("Long min = " + Long.MIN_VALUE + " max = " + Long.MAX_VALUE);
    System.out.println("Float min = " + Float.MIN_VALUE + " max = " + Float.MAX_VALUE);
    System.out.println("Double min = " + Double.MIN_VALUE + " max = " + Double.MAX_VALUE);
    System.out.println("Character min = " + (int)Character.MIN_VALUE 
    + " max = " + (int)Character.MAX_VALUE);
}

 

마지막의 Character의 경우 그냥 출력할 경우char 타입으로 출력되므로 알아보기 힘들다. 따라서 int 타입으로 변환하여 그 값을 확인하도록 해놨다.  결과를 보자.

 

Byte min = -128 max = 127
Short min = -32768 max = 32767
Integer min = -2147483648 max = 2147483647
Long min = -9223372036854775808 max = 9223372036854775807
Float min = 1.4E-45 max = 3.4028235E38
Double min = 4.9E-324 max = 1.7976931348623157E308
Character min = 0 max = 65535

 

Integer 타입과 Long 타입을 읽기가 어려워 보인다. 이 값을 2진수나 16진수로 표현해서 봐보자. Integer의 최소값과 최대값을 2진수와 16진수로 나타낸 결과를 보려면, Integer에서 제공하는 toBinaryString()라는 메소드를 사용하면 된다.

 

public void integerMinMaxCheckBinary() {
    System.out.println("Integer BINARY min = " + Integer.toBinaryString(Integer.MIN_VALUE));
    System.out.println("Integer BINARY max = " + Integer.toBinaryString(Integer.MAX_VALUE));

    System.out.println("Integer HEX min = " + Integer.toHexString(Integer.MIN_VALUE));
    System.out.println("Integer HEX max = " + Integer.toHexString(Integer.MAX_VALUE));
}

 

결과는 다음과 같다.

 

Integer BINARY min = 10000000000000000000000000000000
Integer BINARY max = 1111111111111111111111111111111
Integer HEX min = 80000000
Integer HEX max = 7fffffff

 

어떤 값을 원하는 진수의 숫자로 표현하고 싶을 때에는 직접 구현하는 것보단 이렇게 숫자 클래스에서 제공되는 메소드를 사용하면 된다.

 

돈 계산과 같이 중요한 연산을 수행할 때, 정수형은 BigInteger, 소수형은 BigDecimal을 사용하여야 정확한 계산이 가능하다. 이 두 클래스들은 모두 java.lang.Number 클래스의 상속을 받았으며, java.math 패키지에 선언되어 있다.

'Backend > Java' 카테고리의 다른 글

[Java] #21. Generic(제네릭)  (0) 2022.04.05
[Java] #20-2. java.lang - System 클래스  (0) 2022.04.04
[Java] #19. 자바의 역사  (0) 2022.04.02
[Java] #18-3. 중간 점검 및 실습  (0) 2022.04.01
[Java] #18-2. 기본 문법 정리(2)  (0) 2022.03.31