본문 바로가기
  • 기업가 장준영
Java_2

Java_2_1

by 장준영 2020. 1. 23.

 

Java 에서 가장 많이 쓰는 패키지 "자바랭"

 

 

 

 

 

java.lang 패키지는 아주 특별한 패키지다

 

자바의 패키지 중에서 유일하게 java.lang 패키지에 있는 클래스들은 import를 안해도 사용할 수 있기 때문이다

 

java.lang 패키지에서 제공하는 인터페이스, 클래스, 예외 클래스 등은 다음과 같이 분류할 수 있다

  • 언어 관련 기본
  • 문자열 관련
  • 기본 자료형 및 숫자 관련
  • 쓰레드 관련
  • 예외 관련
  • 런타임 관련

각 분류에는 많은 인터페이스, 클래스, 예외 클래스 등이 있다 

 

그 중 자바 개발자로 먹고 살려면 꼭 알아야만 하는 것들은

charSequence, String, stringBuffer, stringBuilder, Boolean, Byte, Character, Double, Float, Integer, Long, Math

Number, Short, Runnable, Thread, ThreadGroup, ThreadLocal, Throwable, Exception

이들이 있다

 

지금 당장은 크게 알 필요는 없고 점점 채워나가자는 마인드로 공부하자 급하면 독이 된다

 

 

java.lang 패키지엔 많은 에러들이 정의되어 있다

 

이러한 에러들은 여러분들이 볼 일은 별로 없다. 그렇지만, 가끔 나타나는 에러는 알고 있어야 한다

 

바로 OutOfMemoryError(OOME) 와 StackOverflowError 다

 

OOME

메모리가 부족하여 발생하는 에러

 

 StackOverflowError

호출된 메소드의 깊이가 너무 깊을 때 발생하는 에러.

자바에서는 Stack이라는 영역에 어떤 메소드가 어떤 메소드를 호출했는지에 대한 정보를 관리한다

Ex) 메소드가 자기 자신을 호출하는 재귀 메소드를 잘못 작성했다면

스택에 쌓을 수 있는 메소드 호출 정보의 한계를 넘어설 수 있다

이 경우에 발생하는 것이 바로 StackOverflowError이다

 

 

java.lang 패키지에는 자바의 기본 어노테이션이 선언되어 있다

  • Deprecated
  • Override
  • SuppressWarnings

 


 

 

 

이제 본격적으로 java.lang 패키지에 선언되어 있는 클래스들을 알아보자

 

 

 

 

숫자를 처리하는 클래스들 of java.lang

 

자바에서 간단한 계산을 할 때에는 대부분 기본 자료형을 사용한다

 

기본 자료형은 Stack이라는 영역에 저장되어 관리된다

 

따라서, 계산할 때 보다 빠른 처리가 가능하다

 

그런데, 이러한 기본 자료형의 숫자를 객체로 처리해야 할 필요가 있을 수도 있다

 

따라서, 자바에는 다음과 같이 기본 자료형으로 선언되어 있는 타입의 클래스들이 선언되어 있다

  • Byte
  • Short
  • Integer
  • Long
  • Float
  • Double
  • Character
  • Boolean

Character과 Boolean을 제외한 숫자를 처리하는 클래스들은 Wrapper 클래스라고 불리며, 모두 Number 이라는

abstract 클래스를 extends 한다

 

이들은 참조 자료형이지만, 기본 자료형처럼 사용할 수 있다

 

왜냐하면, 자바 컴파일러에서 자동으로 형 변환을 해주기 때문이다

 

그리고, Character 클래스를 제외하고는 공통적인 메소드를 제공한다

parse 타입이름 ()

valueOf ()

소스를 통해 이 메소드 들의 기능을 확인해 보자

//Java_2_1_src1

Public void NumberTypeCheck(){

    String value1 = "3";

    String value2 = "5";

 

    byte byte1 = Byte.parseByte(value1); // 1

    byte byte2 = Byte.parseByte(value2); // 2

    System.out.println(byte1 + byte2); // 3

 

    Integer refInt1 = Integer.valueOf(value1); // 4

    Integer refInt2 = Integer.valueOf(value2); // 5

    System.out.println(refInt1 + refInt2  ); // 6

}

 

1, 2 - 3과 5라는 String 값을 parse타입이름() 메소드를 사용하여 byte로 변환

3 - byte로 변환된 두 값을 더한 결과를 출력

 

4, 5 - valueOf() 메소드를 사용하여 Integer 타입으로 변환

6 - Inteter 타입으로 변환된 두 값을 더한 후 출력했다

 

 

둘 다 String과 같은 문자열을 숫자 타입으로 변환하는 기능을 가졌다는 공통점이 있다

 

하지만, parse 타입이름 () 메소드는 기본 자료형을 리턴하고

 

valueOf() 메소드는 참조 자료형을 리턴한다

 

Java_2_1_src1소스의 NumberTypeCheck() 메소드의 사용 결과는 다음과 같다

8

8

 

 

첫 번째 줄의 결과 값은 모두 이해가 가능할 것이다

하지만, 두 번째 줄의 결과는 조금 이해하기 힘들 것이다

 

왜냐하면, 참조 자료형은 두 값을 더할 수 없는데 숫자 연산이 된 8이라는 값을 출력했기 때문이다

Java_1에서 참조 자료형 중에서 더하기 연산이 가능한 것은 String 뿐이라고 강조했다

그런데, 참조 자료형 중에서 Byte, Short, Integer, Long, Float, Double 타입들은 필요시 기본 자료형 처럼 사용할 수 있다

따라서 new를 사용하여 객체를 만들지 않아도 값을 할당할 수 있다

 

다음과 같이 사용하는 것도 전혀 문제되지 않는다

//Java_2_1_src2

Public void NumberTypeCheck2(){

    Integer refInt1;

    refInt1 = 100;

    System.out.println(refInt1);

}

 

그렇다면, 왜 혼동되게 이러한 숫자를 처리하는 참조 자료형을 만들었을까?

 

그 이유는 다음과 같다

  • 매개 변수를 참조 자료형으로만 받는 메소드를 처리하기 위해서
  • 제네릭과 같이 기본 자료형을 사용하지 않는 기능을 사용하기 위해서
  • MIN_VALUE(최솟값) 나 MAX_VALUE(최댓값) 같이 클래스에 선언된 상수 값을 사용하기 위해서
  • 문자열을 숫자로, 숫자를 문자열로 쉽게 변환하고 2, 8, 10, 16진수 변환을 쉽게 처리하기 위해서

이유를 좀 더 자세히 살펴보자

 

기본 자료형을 참조 자료형으로 만든 클래스들은 Boolean 클래스를 제외하고 모두 MIN_VALUE와 MAX_VALUE라는 상수를 갖고 있다.

 

이를 사용하는 방법은 자료형.MIN_VALUE , 자료형.MAX_VALUE처럼 사용하면 된다

 

그리고 10진수 숫자를  2, 8, 16 진수들로 변환하려면 Integer클래스에서 제공하는

Integer.toBinaryString(int i), // 10진수를 2진수로 변환

Integer.toOctalString(int i) // 10진수를 8진수로 변환

Integer.toHexString(int i) //10진수를 16진수로 변환

메소드를 사용하면 된다

 

여러분들이 어떤 값을 원하는 진수의 숫자로 표현하고 싶을 때에는 직접 구현하는 것보다

이와 같이 숫자 클래스에서 제공되는 메소드를 사용하면 된다

 

혹시나 해서 이야기하지만, 여러분들이 돈 계산과 같이 중요한 연산을 수행할 때

정수형은 BigInteger, 소수형은 BigDecimal을 사용하여야 정확한 계산이 가능하다

이 두 클래스들은 모두 java.lang.Number 클래스의 상속을 받았으며 java.math 패키지에 선언되어 있다

 

여기 까지가 java.lang 클래스의 숫자를 처리하는 클래스들에 대한 이야기였다

 

 

 

 

 

각종 정보를 확인하기 위한 System 클래스 of java.lang

 

System 클래스의 가장 큰 특징은 생성자가 없다는 것이다

 

System 클래스의 3개의 static 변수가 선언되어 있다

          선언 및 리턴 타입           변수명                                     설명
static PrintStreamerr에러 및 오류를 출력할 때 사용한다
static InputStreamin입력값을 처리할 때 사용한다
static PrintStreamout출력값을 처리할 때 사용한다

지금까지 데이터를 출력할 때 아무 생각 없이 System.out.println() 을 사용해 왔지만

 

System은 클래스 이름이다 out은 방금 살펴본 System 클래스에 static으로 선언된 변수 이름이다

out은 PrintStream 타입이다. 그러므로, println() 이라는 메소드는 PrintStream 클래스에 선언되어 있으며 static 메소드다

 

이렇게, out이라는 클래스 변수와 println()이라는 메소드가 모두 static으로 선언되어 있기 때문에 여러분들이 별도의 클래스 객체를 생성할 필요가 없었던 것이다

 

그러므로, 출력과 관련된 메소드는 System 클래스에서 찾으면 안 되고 PrintStream클래스에서 찾아야만 한다

 

출력을 위한 부분들은 out과 err로 선언된 PrintStream과 연관되어 있다

 

실제 System 클래스에 선언되어 있는 메소드들을 살펴보면 출력과 관련된 메소드들은 없다

 

System 클래스는 이름 그대로 시스템에 대한 정보를 확인하는 클래스이며

 

다음과 같은 다양한 역할을 한다

  • 시스템 속성(Property)값 관리
  • 시스템 환경(Environment)값 조회
  • GC 수행
  • JVM 종료
  • 현재 시간 조회
  • 기타 관리용 메소드들

 

 

각 분류에 해당하는 메소드에는 어떤 것들이 있는지 살펴보자

 

 

 

시스템 속성(Property)값 관리 of System class

         리턴 타입             메소드 이름 및 매개 변수                              설명
static StringclearProperty(String key)key에 지정된 시스템 속성을 제거한다
static PropertiesgetProperties()현제 시스템 속성을 Properties 클래스 형태로 제공한다
static StringgetProperty(String key)key에 지정된 문자열로 된 시스템 속성값(value)을 얻는다
static StringgetProperty(String key, String def)key에 지정된 문자열로된 시스템 속성값(value)을 얻고, 만약 없으면 def에 지정된 값을 리턴한다
static voidsetProperties(Properties props)Properties 타입으로 넘겨주는 매개 변수에 있는 값들을 시스템 속성에 넣는다
static StringsetProperty(Stirng key, String value)key에 지정된 시스템 속성의 값을 value로 대체한다

Property와 관련된 이 메소드들에 대해서 이해하려면 먼저 Properties라는 크래스를 알아야 한다

 

Properties는 java.util 패키지에 속하며 Hashtable의 상속을 받은 클래스다

 

아주 간단하게 Hashtable에 대해서 설명하자면 key와 value의 쌍으로 이루어진 여러 개의 값을 갖는 Map 형태의 자료 구조라고 보면 된다

 

Map 형태의 자료 구조는 순서는 거의 없고 key-value 쌍으로 되어있다

 

이 객체에서 원하는 값을 찾으려고 할 때에는 0, 5, n 번째와 같은 위치로 찾는 것이 아니라 key로 찾는다

 

Properties 라는 클래스의 객체는 key-value 로 묶여 있는 여러 개의 데이터를 제공한다고 알고 있으면 된다

 

그리고 원하는 값을 찾으려면 key 값만 알고 있으면 된다

 

여러분들의 필요 여부와 상관 없이 자바 프로그램을 실행하면 지금 이야기한 Properties 객체가 생성되며

 

그 값은 언제, 어디서 든지 같은 JVM 내에서는 꺼내서 사용할 수 있다

 

예를 보면 좀더 이해가 쉬울 것이다

//Java_2_1_src3

public void systemPropertiesCheck(){

    System.out.println("java.version = "+System.getProperty("java.version"));

}

위 메소드의 사용 결과는 다음과 같다

java.version = 1.8.0_92

 

결과는 여러분들이 갖고 있는 자바의 버전에 따라서 결과는 다르게 나올 것이다

 

 

 

 

 

 

시스템 환경(Environment)값 조회 of System class

                    리턴타입         메소드 이름 및 매개 변수                       설명
static Map<Stirng, Stirng>getenv()현재 시스템 환경에 대한 Map 형태의 리턴값을 받는다
static Stringgetenv(String name)지정한 name에 해당하는 값을 받는다

위에 살펴본 Properties라는 것은 추가할 수도 있고, 변경도 할 수 있다. 하지만, 환경값 env라는 것은 변경하지 못하고 읽기만 할 수 있다

 

이 값들은 대부분 OS나 장비와 관련된 것들이다

 

예를 보면 좀더 이해가 쉬울 것이다

//Java_2_1_src4

public void systemPropertiesCheck(){

    System.out.println("JAVA_HOME= "+System.getenv("JAVA_HOME"));

}

위 메소드의 사용 결과는 다음과 같다

JAVA_HOME = c:\jdk1.8.92

 

보통 자바를 사용할 때 JAVA_HOME 이라는 값은 JDK가 설치되어 있는 경로를 말한다

 

 

 

 

 

 

GC 수행  of System class / 사용 금지

          리턴 타입       메소드 이름 및 매개 변수                                 설명
static voidgc()가비지 컬랙터를 실행한다.
static voidrunFinalization()GC 처리를 기다리는 모든 객체에 대하여 finalize() 메소드를 실행한다

자바는 메모리 처리를 개발자가 별도로 하지 않는다

 

따라서 System.gc()라는 메소드를 호출하면 가비지 컬랙션을 명시적으로 처리하도록 할 수 있다

 

Object 클래스에 선언되어 있는 finalize() 메소드를 명시적으로 수행하도록 하는 runFinalization() 메소드가 있다

 

이 두 개의 메소드들을 여러분들이 호출하지 않아도

 

알아서 JVM이 더 이상 필요 없는 객체를 처리하는 GC 작업과 finalization 작업을 실행한다

 

여러분들이 JVM한테 GC를 하라고 강요하지 마라.

 

GC는 JVM이 알아서 필요할 때 한다

 

그러니, 절대로 여러분들의 개발 코드에는 이 메소드들을 넣지 말아라

 

 

 

 

 

 

JVM 종료  of System class / 사용 금지

          리턴 타입           메소드 이름 및 매개 변수                             설명
static voidexit(int status)현재 수행중인 JVM을 멈춘다

이 메소드는 절~~~대 호출하면 안 되는 것 중 하나다

 

안드로이드 앱이나, 웹 애플리 케이션에서 이 메소드를 사용하면 해당 애프리케이션의 JVM이 죽어버린다

 

그러면, 바로 장애로 직결되고 팀장에게 끌려가서 온갖 정신적인 고통을 받게 될 것이다. 절대 쓰지마라

 

 

 

 

 

 

현재 시간 조회 of System class

            리턴 타입          메소드 이름 및 매개 변수                         설명
static longcurrentTimeMillis()현재 시간을 밀리초 단위로 리턴한다
static longnanoTime()현재 시간을 나노초 단위로 리턴한다

currentTimeMillis() 메소드는 UTC라는 Universal time 기준으로 1970년 1월 1일 00:00부터 지금까지의 밀리초 단위의 차이를 출력한다

nanoTime() 메소드는 현재 시간을 알아내기 위해서 사용하는 메소드는 절대 아니고 시간의 차이를 측정하기 위한 용도의 메소드다

 

예를 보면 좀더 이해가 쉬울 것이다

//Java_2_1_src5

long startTime = System.currentTimeMillis();

long startNanoTime = System.nanoTime();

System.out.println("Milli second = " + (System.currentTimeMillis() - startTime));

System.out.println("Nano second = " + (System.nanoTime() - startNanoTime ));

위 메소드의 사용 결과는 다음과 같다

Milli second = 0

Nano second = 513650

 

밀리초는 0 으로 출력되지만, 나노초는 매우 큰 숫자들로 출력된다

 

실제로 나노초를 밀리초로 확인하기 위해서 1/1,000,000으로 나누면 0.5ms다

 

어떤 값이 더 정확하다고 이야기하기는 어렵지만, 시간을 측정할 필요가 있을 때 나노초를 이용하는 것을 권장한다

 

왜냐하면 nanoTime() 메소드는 시간 측정을 위해서 만들었기 때문이다

 

System.currentTimeMillis() 메소드는 현재 시간을 확인하기 위한 메소드라고 생각하는 것이 이해하기 쉬울 것이다

 

 

 

 

 

 

System.out 을 살펴보자 of System class

 

System 클래스에 선언되어 있는 out과 err 변수는 PrintStream 이라는 동일한 클래스의 객체다

 

단지, 정상적인 출력인지, 에러가 났을 때의 출력 결과인지의 차이만 존재한다

 

PritnStream 클래스는 static 하게 사용하므로, 지금은 생성자를 살펴볼 필요가 없다

 

대신 이 클래스에 선언되어 있는 출력을 위한 메소드들에는 어떤 것들이 있는지 알아보자

 

PrintStream 클래스의 출력을 위한 주요 메소드의 이름은 다음과 같다

  • print()
  • println()
  • format()
  • printf()
  • write()

가장 많이 사용하는 메소드가 print()와 println() 메소드다

print() 메소드는 매개 변수에 있는 내용들을 출력하고 줄 바꿈을 하지 않고

println() 메소드는 매개 변수에 있는 내용들을 출력하고 줄 바꿈 처리를 한다

 

만약 줄바꿈만 처리하고 싶을 때에는

println(""); 보다 println(); 으로 처리하는 것이 깔끔하다

 

print() 나 println() 메소드의 매개 변수에는 byte 타입이나 short 타입을 매개 변수로 받는 메소드가 선언되어 있지 않다

 

하지만, 두 개 모두 정수형이기 때문에 전혀 문제 없이 출력된다

 

왜냐하면 여러분들이 byte나 short 타입을 print()나 println() 메소드에 넘겨주면 int 타입을 매개 변수로 받는 메소드에서 알아서 처리해주기 때문이다

 

 

 

마지막으로 꼭 한 가지 짚고 넘어가야할 것이 있다

 

다음과 같이 null을 출력하는 메소드가 있다

//Java_2_1_src6

public void printNull(){

    Object obj = null;

    System.out.println(obj);

    System.out.println(obj+" is object value");

}

여기서 중요한 것은 obj 객체가 null 이라는 점이다

객체를 출력할 때 toString() 메소드를 단순히 호출한다고 생각하고 있었다면, null 인 obj의 toString()을 호출하는 샘이다

null인 obj는 아무런 할당이 되어 있지 않기 때문에 메소드를 호출할 수가 없다

따라서, 컴파일은 재대로 되지만 실행시 예외가 발생한다

 

하지만, 이 printNull() 메소드는 컴파일도 잘 되고 실행하면 다음과 같이 출력된다

null

null is object value

 

"흠,.,. null을 그냥 출력하고, null에 더한 값이 출력되네..."라고 생각할 것이다

뭔가 이상하지 않은가?

 

이런 결과가 출력된 이유는 print() 메소드와 println() 메소드에서는 단순히 toString() 메소드의 결과를 출력하지 않기 때문이다

 

String 클래스의 valueOf()라는 static 메소드를 호출하여 결과를 받은 후 출력한다

 

즉, String.valueOf(obj) 가 호출된 것이다. 그러므로, 아무런 이상 없이 결과가 출력된 것이다

 

다음과 같이 toString()으로 처리한 메소드를 실행해 보자

//Java_2_1_src7

public void printNullToString(){

    Object obj = null;

    System.out.println(obj.toString());

}

 

결과는 예외가 발생해 버린다

 

객체를 출력할 때에는 toString()을 사용하는 것보다 valueOf() 메소드를 사용하는 것이 훨씬 안전하다는 것을 기억하자

 

그러면 이젠 두 번째 줄력문은 null과 문자열을 합쳤는데도 왜 예외가 발생하지 않았을까?

 

그 이유는 컴파일러에서 이 더하기 문장을 StringBuilder로 변환하기 떄문이다

 

두 번쨰 출력문의 괄호 안에 있는 obj+" is object value" 의 내용은 다음과 동일하다

 

new StringBuilder().append(obj).append("is object's value")

 

StringBuilder 의 append() 메소드에 null 을 넣어버린 것과 동일하므로 문제 없이 null을 출력한 것이다

 

 

이 다음에 자주사용하는 메소드가 printf() 와 format() 메소드다 C 언어를 배운 경험이 있는 사람들은  printf() 의 사용법을 다 알 것이다 format() 은 메소드 이름만 다르고 처리하는 것은 동일하다 따라서 편한 대로 선택하여 사용하면 된다

 

 

 

 

 

 

 

 

 

 

 

 

 

오늘은 java.lang 패키지 에 대해 알아 보았다

 

이정도만 알았어도  오늘 하루는 유익한 하루이다

'Java_2' 카테고리의 다른 글

Java_2_3_2  (0) 2020.03.14
Java_2_3_1  (0) 2020.03.01
Java_2_3_0  (0) 2020.02.29
Java_2_2  (0) 2020.02.15
Java_2_0  (0) 2020.01.23

댓글