이펙티브 자바
아이템 6. 불필요한 객체생성을 피하라
똑같은 기능의 객체를 매번 생성하기 보다는 객체하나를 재사용하는 편이 좋을수도 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.github.sejoung.codetest.objects;
public class StringTest { public static void main(String[] args) {
String string1 = "1223"; String string2 = new String("1223");
Boolean true1 = Boolean.valueOf("true"); Boolean true2 = Boolean.valueOf("true"); Boolean true3 = new Boolean("true");
System.out.println(true1 == true2); System.out.println(true1 == true3); System.out.println(true1 == Boolean.TRUE); System.out.println(true3 == Boolean.TRUE);
} }
|
결과
1 2 3 4 5 6 7
| true false true false
Process finished with exit code 0
|
위에서 보면 string을 선언 할때 생성자를 통해서 만든 1223과 기능적으로 완전히 똑같은 생성자를 통하지 않은 객체가 있다.
이것은 생성자를 통해서 만드는것은 불필요 한 일이다.
위 사항과 마찬가지로 Boolean 객체를 만들때 제공하는 Boolean.valueOf로 만든 것과 생성자를 통해서 만든것이 기능적으로는
완벽하게 똑같지만 객체는 계속 생성이 된다 이렇게 만들지 않기 위해서 정적팩토리메소드를 통해서 생성하는것을 권장한다.
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package com.github.sejoung.codetest.objects;
import java.util.regex.Pattern;
public class RomanNumber { private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
static boolean isRomanNumeralCompile(String s) { return ROMAN.matcher(s).matches(); }
static boolean isRomanNumeral(String s) { return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"); }
public static void main(String[] args) {
long start = System.currentTimeMillis();
int max = 100000;
for (int i = 0 ; i <= max ; i++) { RomanNumber.isRomanNumeral("123123"); } System.out.println(System.currentTimeMillis() - start);
start = System.currentTimeMillis(); for (int i = 0 ; i <= max ; i++) { RomanNumber.isRomanNumeralCompile("123123"); } System.out.println(System.currentTimeMillis() - start);
} }
|
결과
1 2 3 4 5 6
| 238 18
Process finished with exit code 0
|
isRomanNumeral 메소드도 매번 정규식을 컴파일하는것보다 위에 처럼 컴파일후에 비교하는것과는 속도 차이가 많이 난다.
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
| package com.github.sejoung.codetest.objects;
import java.util.HashMap; import java.util.Map; import java.util.Set;
public class UsingKeySet {
public static void main(String[] args) { Map<String, Integer> menu = new HashMap<>(); menu.put("Burger", 8); menu.put("Pizza", 9);
Set<String> names1 = menu.keySet(); Set<String> names2 = menu.keySet(); System.out.println(names2.size()); System.out.println(names1.size()); System.out.println(menu.size()); names1.remove("Burger"); System.out.println(names2.size()); System.out.println(names1.size()); System.out.println(menu.size()); } }
|
또다른 잘못된 예로 map에 keySet을 들수 있다. 위에 코드를 실행 해보면 아래의 결과가 나타난다.
1 2 3 4 5 6 7 8 9 10
| 2 2 2 1 1 1
Process finished with exit code 0
|
하나의 셋을 삭제 햇는데 나머지까지 다 영향이 가는것을 볼수가 있다.
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
| package com.github.sejoung.codetest.objects;
public class AutoBoxingExample { public static void main(String[] args) { long start = System.currentTimeMillis(); Long sum = 0l; for (long i = 0 ; i <= Integer.MAX_VALUE ; i++) { sum += i; } System.out.println(sum); System.out.println(System.currentTimeMillis() - start);
start = System.currentTimeMillis(); long sum2 = 0l; for (long i = 0 ; i <= Integer.MAX_VALUE ; i++) { sum2 += i; } System.out.println(sum2); System.out.println(System.currentTimeMillis() - start);
}
}
|
결과
1 2 3 4 5 6 7 8
| 2305843008139952128 7590 2305843008139952128 736
Process finished with exit code 0
|
위에 오토 박싱에 예도 마찬 가지 이다 Long으로 선언해서 오토박싱을 하는것보다 long으로 선언해서 보면 속도차이가 많이 난다.
참조
[이팩티브 자바] #6 불필요한 객체를 만들지 말자