-
primitive type vs wrapper classJAVA 2021. 10. 31. 00:49
Java 에서는 8가지 Primitive Data type 을 제공 합니다.
그리고 Primitive Type에 대한 Wrapper Class 를 제공하는데요.
여기에 대한 차이에 대해서 한번 알아봅시다!
그리고 어떤 경우에 primitive Type을 써야 하고 Wrapper Class 를 사용해야 하는지 알아봐요! 😀
Primitive Type과 Wrapper Class에 대한 Default Value 확인 (Sample Code)
public class Main { byte primitiveTypeByte; short primitiveTypeShort; int primitiveTypeInt; long primitiveTypeLong; float primitiveTypeFloat; double primitiveTypeDouble; char primitiveTypeChar; boolean primitiveTypeBoolean; Byte wrapperByte; Short wrapperShort; Integer wrapperInteger; Long wrapperLong; Float wrapperFloat; Double wrapperDouble; Character wrapperCharacter; Boolean wrapperBoolean; String wrapperString; public static void main(String[] args) { final Main main = new Main(); System.out.println(">>>>>>>>>> Default Values to Primitive Type"); System.out.println("byte : " + main.primitiveTypeByte); System.out.println("short : " + main.primitiveTypeShort); System.out.println("int : " + main.primitiveTypeInt); System.out.println("long : " + main.primitiveTypeLong); System.out.println("float : " + main.primitiveTypeFloat); System.out.println("double : " + main.primitiveTypeDouble); System.out.println("char : " + main.primitiveTypeChar); System.out.println("boolean : " + main.primitiveTypeBoolean); System.out.println(">>>>>>>>>> Default Values to Wrapper Class"); System.out.println("Byte : " + main.wrapperByte); System.out.println("Short : " + main.wrapperShort); System.out.println("Integer : " + main.wrapperInteger); System.out.println("Long : " + main.wrapperLong); System.out.println("Float : " + main.wrapperFloat); System.out.println("Double : " + main.wrapperDouble); System.out.println("Character : " + main.wrapperCharacter); System.out.println("Boolean : " + main.wrapperBoolean); System.out.println("String : " + main.wrapperString); } }
Primitive Type과 Wrapper Class에 대한 Default Value 확인 (Output)
>>>>>>>>>>Default Values to Primitive Type byte : 0 short : 0 int : 0 long : 0 float : 0.0 double : 0.0 char : '\u0000' boolean : false >>>>>>>>>>Default Values to Wrapper Class of Primitive Type Byte : null Short : null Integer : null Long : null Float : null Double : null Character : null Boolean : null String : null
Default Value 의 차이
primitive 에는 초기화 해주지 않아도 기본 값을 가지고 있습니다.
하지만 Wrapper Class의 경우는 초기화를 해주지 않으면 null 을 기본 값으로 가지고 있는 걸 확인할 수 있어요! :)
또한 API Docs 에 가서 보면 해당 Primitive Type 의 Wrapper Class에는 모두(Byte, Short, Integer, Long, Float, Double, Boolean, Character) value-based class 라는 간략한 메모가 포함되어 있습니다.
더보기This is a value-based class; programmers should treat instances that are equal as interchangeable and should not use instances for synchronization, or unpredictable behavior may occur. For example, in a future release, synchronization may fail.
* 참고: value-based class 에는 primitive type의 wrapper class 외에도 java.time 패키지의 Instant, LocalDate, LocalTime.. 등 도 있습니다.
그러면 value-based claas란 무엇일까요?
아쉽게도 제가 분명하게 이해하지 못했기 때문에 정확한 전달은 어려울 것 같지만 여러 문서와 블로깅 한 결과를 조금이나마 요약해서 알려 드리고 싶네요 :)
Java API Docs 도 읽어보고 여러 문서도 참조해 봤지만, 문서에서 말하는 이유들이 와닿지는 않았습니다.
하지만 대략적인 내용을 정리해 보면 다음과 같습니다.
- optional과 관련이 있고 functional programming 으로 진화하기 위함
- final 이어야 하고 immutable(불변) 이어야 함
- 값을 비교할 때 (==) 비교가 아닌 equals() 로 비교해야 함
- equals(), toString(), hashCode() 를 갖고 있어야 함
- 값 비교 시에 id로 값을 비교해서는 안됨
자세한 내용에 대해서 궁금하다면 openjdk 문서에 있는 jep390, oracle jdk 문서에 있는 value-base class 문서를 읽어보면 좋을 것 같습니다.
그리고 여러 타 블로그에서는 해당 문서에 대한 내용을 풀어서 설명하고 있으니 검색해 보면 도움이 될 수도 있을 것 같습니다.
가장 궁금한 것. Primitive Type 을 써야 할까요. Primitive Type을 Wrapping 한 클래스를 써야 할까요?
중요하게 생각하는 부분에 따라 상황에 맞게 사용하면 되는데요. 특정 상황에서 유용한 선택에 대해 정리해 봤습니다.
Memory : primitive
Java JVM의 종류는 다양합니다. JVM 별로 조금씩 메모리 할당량은 다릅니다.. 하지만 분명한 것은
int 와 Integer를 메모리 비교했을 때 int가 훨씬 적은 메모리를 차지합니다.
메모리만 신경 쓴다면 Integer 보다는 primitive type 인 int를 사용해야 합니다.
일반적으로...
- int : 32bit
- Integer : 128bit
Performance : primitive
그리고 또 성능의 문제도 있습니다.
JVM 메모리 구조에 int와 Integer는 각기 다른 공간에 저장됩니다.
primitive 타입은 stack에 있고 reference 타입은 heap 에 위치 합니다.
아래 bealdung 사이트를 참고했습니다. 실제 성능 테스트를 제가 한건 아니지만 해당 블로그 작성을 위해 bealdung 사이트를 벤치마킹했으니 참고해 주시면 감사하겠습니다.
Generic : Wrapper
Java 에서는 Generic Type으로 primitive type을 사용하는 것을 허용하지 않습니다.
Generic Type을 써서 value-base class를 사용해야 하는 경우에는 Wrapper 클래스를 사용해야 합니다.
비즈니스 및 도메인에 대한 상황에 따라 : primitive, Wrapper
절대 null일 수 없는 경우가 있다면 primitive 타입을 써야 하고
null 이 가능해야 하는 경우라면 반드시 Wrapper 클래스를 사용해야 할 수 있습니다.
null로 들어가야 하는 게 맞는데 의도치 않게 0을 기본값으로 갖게 될 경우가 생길 수도 있고
비어있을 수도 있습니다.
Entity를 설계한 의도에 따라 primitive 타입 또는 Wrapper를 선택할 수 있습니다.
Casting, 유연함, 다양한 지원 기능 : Wrapper
아무래도 primitive 타입은 값만 담을 수 있지만, Wrapper 클래스는 말 그대로 클래스이기 때문에 다양한 메서드가 구현되어 있어 여러 가지 유연하고 편리한 기능들이 사용 가능합니다.
WrapperClass가 가진 기능들을 다양하게 사용해야 하는 경우라면 primitive 타입보다는 Wrapper 타입을 사용하는 게 좋습니다.
결론
성능과 메모리만 생각한다면 primitive 타입을 써야 합니다.
하지만, 클래스의 구조(Collection), 유연하고 다양한 기능이 필요할 때면 Wrapper Class를 써야 합니다.
도메인 및 비즈니스 모델 설계에 따라서는 상황에 맞게 primitive Type 또는 Wrapper 클래스를 써야 합니다.
결과적으로는 어떤 상황이냐에 따라 선택할 수밖에 없다고 보일 수 있겠는데요.
하지만 저희가 만들고 있는 시스템은 항상 시간이 지나면 지날수록 거대해지기 마련입니다.
그렇다면 필요하지 않은 곳에는 Wrapper 클래스를 사용하지 않는 편이 좋을 것 같습니다.
아무 의미 없이 모든 필드에 primitive 타입 없이 전부 Wrapper 클래스를 사용하는 것은 좋지 않다고 보입니다.
최종 정리! 항상 primitive 타입을 기본적으로 사용하되, 필요한 경우에 따라 Wrapper 클래스를 사용해 주는 게 Bestpractice이지 않을까 정리해 봅니다.😀
reference
- https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html
- https://openjdk.java.net/jeps/390
- https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
- https://www.tutorialspoint.com/difference-between-an-integer-and-int-in-java
- https://www.baeldung.com/java-primitives-vs-objects
- https://www.baeldung.com/java-stack-heap
'JAVA' 카테고리의 다른 글
TDD 요약 정리 - 테스트 주도 개발/테스팅 패턴, 빨간/초록 막대 (0) 2022.07.04 TDD - 2부 xUnit 간단 정리 (0) 2022.06.27 TDD 17장. Money 회고 요약 및 정리 (0) 2022.06.27 Builder Pattern (0) 2021.06.03 메서드 추출(Extract Method) (0) 2021.05.18