Search

반응형

'Software/Java'에 해당되는 글 55건

  1. 2020.04.12 [java]System.currentTimeMillis() 와 System.nanoTime() 사용하기. 1
  2. 2020.04.09 [java]비교연산 "==" vs "equals()" 쉽게 이해하기.
반응형

안녕하세요. 올드한 개발자 티보이입니다.

자바 코딩을 하다 보면 시간 관련 기능이 필요할 때가 있습니다.

자바로 개발된 프로그램이 간혹 느려지면 디버깅 시 경과시간을 체크해야 되는 경우가 있습니다.

비슷하면서도 다른 두 개의 메서드인 System.currentTimeMillis() System.nanoTime()에 대해 알아보겠습니다.

public static long currentTimeMillis();

첫번째 메서드인 System.currentTimeMillis() 에 대해 알아봅니다.

현재 시간과 UTC(협정세계시)인 197011일 자정과의 차이로 밀리세컨드(1/1000초) 값을 반환합니다.

다음 예를 통해 사용법을 확인해 봅니다.

1
2
3
4
5
6
7
8
9
10
11
long curLong = System.currentTimeMillis();        
System.out.println(curLong);
 
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); // HH 24시간  hh 12시간
String curTime = sdf.format(new Date(curLong));
 
System.out.println(curTime);
Thread.sleep(5000);
long endLong = System.currentTimeMillis();
 
System.out.println((endLong - curLong)/1000 + "초 걸림");  // 밀리초라 천분의 1로
cs

결과: 

1586618583204
2020-23-12 00:23:03
5초 걸림

두 번째 System.nanoTime()는 JDK1.5부터 추가된 메서드입니다.

public static long nanoTime();

그럼 앞에 설명한 System.currentTimeMillis()어떻게 다를까요?

이 메서드는 현재 시간(시스템 시간)과 관계가 없습니다.

작동중인 JVM의 정밀한 시간 소스의 현재 값을 long타입으로 나노세컨드(1/1000000000초)를 반환합니다.

그래서 현재 시간을 측정하기 위해서 사용하면 안 되겠지요.

그리고 분산 시스템에서 다른 JVM끼리 시간 측정을 위해 사용하면 안 됩니다.

JVM마다 측정하기 위한 기준값이 다르기에 절대값이 될 수 없습니다.

, 서버간 데이터 전송 시간을 측정하기 위해 사용하면 안 된다는 겁니다.

밀리세컨드(1/1000)를 사용하는 System.currentTimeMillis() 보다 더 정밀합니다.

다음 예를 통해 사용법을 확인해 봅니다.

1
2
3
4
5
6
7
long nTime = System.nanoTime();
System.out.println(nTime);
Thread.sleep(5000);
long eTime = System.nanoTime();
System.out.println(eTime);
 
System.out.println((eTime-nTime)/1000000000 + "초 걸림"); // 나노초라 10억분의 1로
cs
 

결과:

94882998233500
94887998455400
5초 걸림

결론은 시스템의 시간을 사용하기 위해서나 오늘 날짜를 알아내기 위해서는 System.currentTimeMillis()를 사용하면 되고

개발한 프로그램의 성능 측정을 위해 나노초로 정밀하게 구간 시간 측정을 위해서는 System.nanoTime() 사용하면 됩니다.

하지만 다른 서버 간 통신 시간 측정 시에는 System.nanoTime()를 사용하면 안 됩니다.

즐 코딩하세요.

반응형
반응형

안녕하세요~ 신기한연구소 티보이입니다.

자바(java) 개발 중 값을 비교해야 하는 경우가 종종 있습니다.

보통 숫자는 비교 연산자인 "=="로 문자열은 문자열 비교 메서드인 equals()를 주로 사용하는데 왜 문자열은 비교 연산자인 "=="를 사용하면 다르게 나오는지 같이 확인해 보겠습니다.

1. 비교연산자 (==)

비교 연산자(==)는 변수의 데이터가 저장된 메모리 위치(해시코드)를 비교합니다.

다음 예를 살펴볼게요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        // 샘플 1
        long long1 = 32L;
        long long2 = 32L;
        
        System.out.println(long1);
        System.out.println(long2);
        System.out.println(System.identityHashCode(long1));
        System.out.println(System.identityHashCode(long2));
        
        
        System.out.println((long1 == long2?"same value" : "diff value")); //결과1
        
        //샘플 2
        String s1 = "te";
        String s2 = "st";
        String s3 = s1 + s2;
        String s4 = "test";
        String s5 = "test";
        
        System.out.println(s3);
        System.out.println(s4);
        System.out.println(s5);
        System.out.println(System.identityHashCode(s3));
        System.out.println(System.identityHashCode(s4));
        System.out.println(System.identityHashCode(s5));
        
        System.out.println((s3 == s4?"same value" : "diff value")); //결과2
        System.out.println((s4 == s5?"same value" : "diff value"));  //결과3
cs

결과 :

32
32
366712642
366712642
same value
test
test
test
1829164700
2018699554
2018699554
diff value
same value

우선 샘플 1을 보면 기본형 long 변수인 long1, long2를 32L 값으로 할당했습니다.

두 값을 비교 연산자인 '=='를 사용한 결과1을 보시면 'same value'가 출력되었습니다.

값은 둘 다 32를 출력했고 해시코드(hashcode)도 동일한 '366712642'값을 출력했습니다.

메모리 위치를 나타내는 해시코드가 같음을 알 수 있습니다.

비교 연산자는 이 해시코드 값을 비교합니다.

샘플 2를 보시면 문자열 비교를 합니다.

S4와 S5 둘 다 'test' 값이 할당되어 있습니다.

결과3에서 비교 연산자를 사용해서 비교해 보면 'same value'로 나옵니다.

두 변수 S4와 S5의 해시코드 값도 '2018699554'로 동일합니다.

그런데 S3와 S4를 보면 값은 둘 다 'test'인데 결과2를 보면 'diff value'로 표출됩니다.

비교 연산자는 이 두 개의 값을 다르게 인식합니다.

두 값의 해시코드를 보면 S3 (1829164700)와 S4 (2018699554)로 서로 다름을 알 수 있습니다.

왜 다르게 나오냐면 S3의 경우 S1과 S2의 결합으로 비록 값은 같지만 새로운 메모리에 객체로 생성되기 때문입니다.

결국 비교 연산자는 눈에 보이는 값으로 비교하는 게 아닌 변수의 값이 저장된 해시코드값으로 비교한다는 것을 확인할 수 있습니다.

효율적인 메모리 사용을 위해 변수에 값을 할당할 때 기존에 같은 값이 있으면 같은 해시코드로 지정됩니다.

2. equals() 메서드로 비교하기

우선 이 메서드는 기본형(primitive type)에서는 사용할 수 없습니다.

이유는 equals()는 객체에서 호출되는 메서드인데 기본형 타입은 객체가 아니라 변수이기 때문입니다.

쩜 찍어보면 아무것도 안 나오거든요. ㅎㅎ

equals() 메서드의 예를 살펴보겠습니다.

1
2
3
4
5
6
7
8
9
//샘플 3
        String s1 = "te";
        String s2 = "st";
        String s3 = s1 + s2;
        String s4 = "test";
        String s5 = "test";
        
        System.out.println((s3.equals(s4)?"same value" : "diff value")); //결과4
        System.out.println((s4.equals(s5)?"same value" : "diff value")); //결과5
cs

위 예제의 결과4와 결과5는 둘 다 'same value'가 나옵니다. 비교 연산자와 다른 결과가 나왔습니다.

그 이유는 equals() 메서드는 두 변수의 메모리(해시코드)에는 관심이 없고 단지 눈에 보이는 글자 그 자체를 비교하기 때문입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        Long rLong1 = new Long(32L);
        Long rLong2 = rLong1;
        Long rLong3 = new Long(rLong1);
        Long rLong4 = new Long(32L);
        
        
        System.out.println(System.identityHashCode(rLong1));
        System.out.println(System.identityHashCode(rLong2));
        System.out.println(System.identityHashCode(rLong3));
        System.out.println(System.identityHashCode(rLong4));
        
        System.out.println((rLong1.equals(rLong2)?"same value" : "diff value")); //결과6
        System.out.println((rLong1.equals(rLong3)?"same value" : "diff value")); //결과7
        System.out.println((rLong1.equals(rLong4)?"same value" : "diff value")); //결과8
        System.out.println((rLong3.equals(rLong4)?"same value" : "diff value")); //결과9
        
        
        System.out.println((rLong1 == rLong2?"same value" : "diff value")); //결과10
        System.out.println((rLong1 == rLong3?"same value" : "diff value"));  //결과11        
        System.out.println((rLong1 == rLong4?"same value" : "diff value"));  //결과12    
        System.out.println((rLong3 == rLong4?"same value" : "diff value"));  //결과13
cs

위 예제에서는 Long 객체를 생성해서 '=='와 'equals()'로 비교를 해봤습니다.

이제 어떤 결과가 나올지 예측이 되시나요?

결과6은 equals()를 사용했기에 값 자체만 비교하므로 'same value'가 나옵니다.

결과7, 결과8, 결과9도 'same value'가 나옵니다.

 

결과10은 rLong1객체를 rLong2에 대입시켰기 때문에 같은 해시코드를 갖게 됩니다. 그래서 'same value'가 나오게 됩니다.

결과 11부터 13까지는 새로운 객체를 생성했기에 눈에 보이는 값은 32로 같지만 다른 해시코드를 갖고 있기에 'diff value'가 나옵니다.

3. 결론

같은 메모리 위치를 참조하는지 확인하기 위해서는 비교 연산자 == 를 사용하면 됩니다.

아래 예와 같이 long1과 long2는 32L 을 할당받게 됩니다. long2의 값이 long1과 같기에 굳이 새로운 메모리에 똑같은 값을 넣고 메모리를 차지할 이유가 없기 때문입니다. 효율적인 자바네요. ㅎㅎ

이런 경우는 비교 연산자 ==로 비교 시 같다고 나옵니다.

하지만 아래와 같이 새로운 객체(참조형 변수)를 만들게 되면 값은 중요하지 않습니다. 새로운 놈이 나타난 것이기 때문에 값이 같더라도 새로운 위치를 하나 내어줍니다.

그래서 long1과 long2의 값이 32L로 같더라도 new로 새로운 객체로 만들어졌기 때문에 해시코드값도 다르게 됩니다.

해시코드값(메모리 위치)이 같은지 비교할 때는 비교 연산자 (==)를 사용하고

해시코드값이 달라도 글자 그 자체를 비교할 때는 equals()메소드를 사용하면 됩니다.

즐 코딩하세요~

반응형