시작하며


 알고리즘 공부를 하다보면 여러 숫자들을 비교해야하는 경우가 다분히 생기는데, 그 때마다 형변환을 해준다던지 Integer.valueOf나 Integer.parseInt를 사용해서 숫자를 비교하며 조건문을 넣어주는 경우가 많이 생긴다. 알고리즘을 공부하면서 그 둘의 차이점이 무엇인지 문득 궁금해졌는데 그 차이에 대해 알아보도록 하자.



들어가며

우선 parseInt와 valueOf의 주된 차이점에 대해 알아보자.


  • Integer.parseInt : Primitive type인 int형을 반환


1
2
3
public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
}

cs



  • Integer.valueOf : Wrapper Object인 Integer를 반환

1
2
3
public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
}

cs




  위의 두 가지 코드의 차이에 대해서 알아보자.

 


우선, 코드상에서 보이는 가장 큰 차이는 

  • 반환 타입이 int와 Integer Obejct로 다르다는 것이다.



♤그렇다면 여기서 int와 Integer는 어떻게 다른가?


간단하게 말하자면 int는 기본자료형(unboxed primitive type)

Integer는 참조자료형 또는 기본자료형들에 대응되는 객체화된 자료형(boxed primitive type) 이라고 할 수가 있겠다.

아니, 그동안 int형만 자주 쓰느라 참조자료형이랑 말은 생소한데 이건 또 뭐지.... 하는 의문이 생겼고


또, 그렇다면 기본 자료형과 객체화 된 자료형은 어떻게 다른가?로 귀결될 수 있는데!

보통 흔히 쓰는 int, long, boolean등의 자료형들을 기본 자료형이라 하고 Integer, Long, Boolean 등을 객체화 된 자료형이라고 한다.


이렇게만 설명을 들으면 이해하기가 힘들기 때문에 몇 가지 예시를 통해서 기본 자료형과 객체화 된 자료형의 차이를 보도록 하자.


1. 기본자료형은 값만 가지지만 객체환 된 자료형은 각각의 신원(identity)을 가진다.

 -> 즉, int a = 42, b = 42; 일때 a==b는 같지만 c==d는 다를 수 있다는것


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int a = 42;
int b = 42;
 
Integer c = new Integer(42);
Integer d = new Integer(42);
 
if(a==b){
    System.out.println("Success");
}
 
if(c==d){
    System.out.println("Success too");
}else{
    System.out.println("They have different identity");
}

cs




2. 기본 자료형은 int형 값을 가지기 때문에 산술연산을 할 수 있지만 객체화 된 자료형은 Integer클래스을 받기 때문에 

    unboxing(wrapper 클래스 -> primitive 자료형)을 해주지 않으면 산술연산을 할 수 없다. 하지만, 기본자료형과 달리 null값으로 처리할 수 있기

    때문에 SQL과 연동할 경우 처리가 용이하다.


1
2
int a = null;           // null값으로 초기화 할 수 없음
Integer b = null;       // null값으로 초기화 할 수 있음
cs



3. 굳이 객체화된 자료형을 사용할 이유가 없다면 primitive 타입을 쓰는 것이 공간효율적인 측면에서 좋다.


Integer의 사이즈 : 20byte

int의 사이즈 : 4byte



그렇다면 Integer(객체화 된 자료형)는 언제 쓰는가?

 

 Integer와 같은 객체화 된 자료형들은 아까 위에서 보았듯이,


첫째, null값으로의 처리가 유용하기 때문에 SQL과 연동할 경우 즉, DB를 사용해서 쿼리문을 짜줘야하는 경우에 유용하다.

둘째, ArrayList나 List등의 요소, 키, 값으로 사용할 때 이다. 다시 말해서 ArrayList<int>는 안되지만 ArrayList<Integer>로 사용할 수 있다는 말이다.


끝마치며

 처음에는 단순히 valueOf와 parseInt의 차이점에 대해서만 간단히 쓰고 넘어가고자 했는데 공부하면서 Integer(Wrapper Class)와 int(Primitive type)의 차이에 대해서 알아야된다는 것을 알게 되었고, 기본 자료형과 참조 자료형의 차이에 대해 비교를 하게 되었다. 그리고 결국엔 돌고돌아 parseInt와 valueOf의 정확한 return 타입과 그 쓰임새에 대해 이해할 수 있게 되었다.


 처음에는 단순히 이렇게 마냥 쓰는거구나 하면서 아무생각 없이 선언했었지만 이렇게 점점 깊게 파보게 되니 Auto-boxing, Auto-unboxing의 개념에 대해서도 알게 되었고 쓸데없이 객체를 만들거나 자바에서 객체화 비객체화가 일어나며 리소스를 낭비될 수 있다는 것도 이해하게 되어 시간은 오래걸렸지만 좀 더 기본기에 대한 이해도가 높아진 것에 대해 만족한다.

'알고리즘 공부 > 알고리즘 지식' 카테고리의 다른 글

Scanner와 BufferReader의 차이  (0) 2018.10.09

시작하며


 Java에서는 흔히들 출력을 할 때, java.util 패키지에 있는 Scanner 클래스를 import하여 Scanner sc = new Scanner(System.in); 형식으로 출력을 하도록 배운다. 하지만, 위의 방식보다 java.io 패키지에서 BufferedReader클래스를 import하여 사용하는 것이 속도면에서 우월하다는 것을 알게 되었고 그에 대해 정리해보고자 한다.



들어가며


  • Scanner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Scanner;
 
public class prac1 {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
 
        int a = sc.nextInt();
        float b = sc.nextFloat();
        String str = sc.next();
        String strWithSpace = sc.nextLine();        //공백을 포함
 
        sc.close();
 
        System.out.println(a);
        System.out.println(b);
        System.out.println(str);
        System.out.println(strWithSpace);
    }
}
 

cs


  • BufferedReader


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.*;
 
public class prac1 {
    public static void main(String[] args){
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
 
        OutputStreamWriter osw = new OutputStreamWriter(System.out);
        BufferedWriter bw = new BufferedWriter(osw);
 
        try {
            String str = br.readLine();     //입력
 
            bw.write(str);                  //출력
            bw.flush();
            bw.close();
 
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
cs


  위의 두 가지 코드의 차이에 대해서 알아보자.

 

우선, 코드상에서 보이는 가장 큰 차이는 

  • InputStreamReader를 인자로 갖는 BufferedReader
  • try/catch문의 유무이다.


1. InputStreamReader는 입력을 character로 받아오기 때문에 줄단위의 문자열을 입력으로 받아올 떄 불편한 점이 생기고, 이에 따라서 BufferedReader가 생겨나 함께 쓰이기 시작했다.

BufferedReader는 이런 InputStreamReader에 버퍼 기능을 추가한 것인데, 데이터를 한 번에 읽어서 버퍼에 보관시킨 후에 사용자의 요청에 따라 버퍼에서 읽어오게 된다.


2. BufferedReader는 throws Exception을 선언해주어야만 에러없이 사용할 수 있다.


장단점 비교를 하자면


Scanner의 장점은 쓰기 간략하고 편하다(?)를 생각할 수 있겠고, 단점은 속도가 BufferedReader보다 느리다.

BufferedReader의 장점은 Scanner에 비해 처리속도가 빠르다는 것이고, 단점은 InputStreamReader클래스와 BufferedReader클래스 두 가지를 불러오며 try/catch문으로 써야해서 Scanner보다 불편할 수 있다는 것이다.


이렇게 장단점만 비교한다면 Scanner가 하기쉽고 편해서 좋아보이지만


<백준 알고리즘 1000번 문제를 풀었을 때>


<출처 : algospot>


위의 사진들을 보면 알 수 있듯이 시간이 상당히 절약되는 것을 쉽게 알 수 있다.


왜 이러한 결과가 나타나는 걸까?

 

 그 이유는 Scanner는 Regex(Regular Expression)을 많이 사용하여 알아서 Tokenizing과 Parsing을 해주기 때문에 패턴을 분석하는 데에 있어서 시간을 많이 잡아먹기 때문인데, Regex를 이용하면 패턴을 이용해 문자열을 좀 더 세밀히 분석할 수 있다고 한다.



끝마치며

 알고리즘 문제를 풀다보면 str.toString()을 이용해 문자열에 문자를 추가하는 방법과 StringBuilder를 이용해 append로 붙이는 방법처럼 메모리나 시간을 절약해서 풀어야하는 경우가 많았고, 실제로 협업해서 코드를 진행할 때 위와 같은 요소들을 항상 체크하고 서로의 약속으로 만드는 경우가 많았다. 이처럼 항상 메모리와 런타임 시간을 고려하면서 푸는것이 앞으로를 위해 도움이 될 것 같다.


(※위의 toString()과 StringBuilder의 append의 차이에 대한 코드는 추후 작성 예정입니다.)

+ Recent posts