-
자바에서 static의 사용JAVA/Java 2021. 12. 30. 21:18
프로젝트 리팩토링을 진행 중 자바에서의 static메서드를 가진 utility 클래스의 사용은 자제해야 한다는 코드 리뷰를 받게 되었다.
자바에서의 static의 사용
public class FileUploadUtils { //폴더에 사진을 저장 public static void saveFile(String uploadDir, String fileName, MultipartFile multipartFile) throws IOException { ... } //폴더에 파일이 이미 존재한다면 폴더 비워주기 public static void cleanDir(String dir) throws IOException { ... } //폴더 삭제하기 public static void deleteDir(String dir) { ... } //파일 삭제하기 public static void deleteFile(String filePath) { ... } }
자바에서 static variables, static method, static class 등 static 특징을 가진 대상들은 JVM이 시작도리 때 static Method 영역에 저장이 되고 프로그램이 끝날 때 까지 사라지지 않고 메모리에 남아있게 된다. 이와 같은 특징 때문에 반복적으로 사용될 때 별다른 객체 생성 없이 바로 사용할 수 있기 때문에 속도가 빠르다는 장점이 있어 정적 메서드를 지닌 utility를 많이 사용하게 된다. 그러나 이러한 static의 사용은 자바가 추구하는 객체지향에 있어 위배되고 메모리 사용 효율이 줄어들게 만든다.
문제점 ① Message passing 기능 불가 (객체 지향 위반)
static 메서드가 가진 첫번째 문제점은 정적메서드는 객체의 생성주기와 관계가 없기 때문에 객체 지향의 특징인 메세지 전달의 규칙을 위반하게 된다. 객체와 관계를 맺지도 않고 서로 정보를 교환하는 것도 아닌 정적메서드는 함수의 기능을 실행하는 것이 아닌 단지 절차지향적 프로그래밍, 명령형 프로그래밍에 불과 하게 된다.
문제점 ② 다형성 불가 (객체 지향 위반)
또한 static 메서드는 객체지향 함수가 가진 다형성(같은 명령을 내려도 각 객체의 기능과 역할에 맞게 임무를 수행)을 위반하고 있다. 이는 정적메서드가 컴파일 시에 (런타임 이전) 정적 바인딩을 함으로서 late binding이 불가능 하져 오버라이딩 못하기 때문이다. 그렇기 때문에 static 메서드는 Overriding(메서드 재정의) Dynamic Binding(동적바인딩)을 할 수 없어 인터페이스도 구현할 수 없게 되므로 재사용 성도 떨어진다. 또한 인터페이스 사용의 불가로 클래스를 더이상 확장시킬 수도 없을 것이다.
문제점 ③ 캡슐화 불가 (객체 지향 위반)
static은 한 객체가 가지고 있는 데이터들은 외부에서 함부로 접근하여 수정할 수 없도록 해야한다는 캡슐화의 원칙에도 위반이 되고 있다. 또한 static 변수는 global state(전역 상태)로 추론과 테스트가 매우 까다롭게 만든다. 이러한 static 변수의 상태는 코드 여러부분에서 영향을 받기 때문에 어디서 변화가 이루어 졌는지 추적하기가 매우 어려워진다. 반면에 객체화가 된 인스턴스는 그 변수가 어떠한 상태를 가지고 있는지 추론할 수 있다.
문제점 ④ 메모리 낭비
static 키워드가 붙은 메서드 등의 메모리는 garbage collector에 의해서 회수되는 대상이 아니다. 즉 static 변수는 프로그램이 실행되고 있는 내내 살아있게 되어 프로그램이 끝날 때까지 그 영역은 메모리에서 내릴 수 없게 되어 지속적인 메모리가 필요하게 된다. 반면에 인스턴스화 된 객체는 함수의 호출이 끝난 후 소멸하게 되므로 메모리를 훨씬 절약할 수 있다.
해결 방안
우선 최대한 static 대신 다른 방법을 사용하는 것이 좋다. 먼저 transient같은 제어자(modifier) 를 사용할 수 있는지 생각해볼 수 있고 final 같은 메서드 를 사용해서 실제 메소드를 호출하지 않고 바로 결과값을 돌려줌으로서 실행속도를 빠르게 해줄 수 있다. 메서드 파라미터들과 변수들이 final로 선언되면 컴파일러 단에서의 무엇이 그 값을 변경하는지 알수 있는 최적화 작업 가능하고 인스턴스를 사용할 때 마다 새로 생성하는 대신에 여러번 재사용도 가능하다. 만약 여러개의 인스턴스를 만드는 것을 피하고 싶다면 싱글톤 디자인 패턴을 이용하는 것도 대안이 될 수 있다.
public class FileUploadUtils { private FileUploadUtils(){} ... }
그럼에도 불구하고 static 메서드를 가진 utility 클래스를 사용해야만 한다면 utility 클래스는 private 생성자를 구성 하도록 하여 잘못된 사용을 방지하도록 하자.
(참고한 사이트)
https://stackoverflow.com/questions/4002201/why-arent-static-methods-considered-good-oo-practice
https://tecoble.techcourse.co.kr/post/2020-07-16-static-method/
https://slipp.net/questions/360
'JAVA > Java' 카테고리의 다른 글
자바에서 메소드 순서 (0) 2022.01.10 Java Optional의 사용 (0) 2022.01.06 Method Reference (Java 8) (0) 2021.12.19 Refactoring ① : 첫번째 예제 (0) 2021.12.17 DTO와 VO 그리고 Entity (0) 2021.12.13