참고
정적 유틸리티 클래스
NOTE
정적 유틸리티 클래스는 인스턴스를 생성하지 않고, 오직 정적 메서드와 정적 필드만을 포함하는 클래스이며, 관련된 유틸리티 함수들을 그룹화하여 재공합니다!
Static은 메소드 영역에 속한다. (GC가 관리하지 않음)
•
정적 유틸리티 클래스는 인스턴스화 되지 않으며, private 생성자를 가집니다.
•
대부분의 정적 유틸리티 클래스는 상태를 유지 않으며, 입력된 매개변수만으로 작업합니다.
•
단순 메소드만 가지고 있는 구조로 객체지향에 벗어난 개념이되어 좋지 않은 방식으로도 불린다.
정적 유틸리티 클래스의 객체지향 설계
NOTE
유틸리티 클래스들이 객체 지향 설계 원칙에 어긋날 수 있는 몇 가지 문제점을 가지고 있다!
•
유틸리티 클래스는 상태를 저장하지 않는 정적 메서드의 집합이기 때문에, 객체 지향 프로그래밍의 핵심 원칙중 하나인 상태와 행동을 하나의 단위로 묶는 것을 따르지 않습니다.
•
유틸리티 클래스는 확장될 수 없습니다. 즉 정적 메서드를 오버라이드하거나 수정할 방법이 없어 유연하지 못합니다.
•
유틸리티 클래스의 메서드들을 사용하는 코드는 해당 클래스에 강하게 결합됩니다. 이는 테스트와 유지보수를 어렵게 만들 수 있으며, 특히 테스트 시 유틸리티 클래스의 메서드를 모킹하기 어렵습니다.
권장사항
•
유틸리티 클래스를 사용할 때는 객체 지향 설계 원칙을 고려하고 필요한 경우에만 사용하는것이 좋습니다.
•
유틸리티 클래스를 사용해야 할 경우, 클래스가 단일 책임 원칙을 따르도록 하고 너무 많은 기능이나 책임을 하나의 유틸리티 클래스에 넣지 않도록 주의해야 합니다.
•
최신 자바 버전에서는 인터페이스 내에 정적 메서드와 디폴트 메서드를 정의할 수 있습니다.
java.util.Objects
NOTE
Objects는 객체에 대한 일반적인 연산을 수행하는 정적 메서드들을 제공해 다양한 연산을 쉽게 처리할 수 있게 도와주는 유틸리티 클래스입니다.
// requireNonNull 예제
try {
Objects.requireNonNull(null, "객체가 null입니다.");
} catch (NullPointerException e) {
System.out.println(e.getMessage()); // "객체가 null입니다."
}
// isNull 및 nonNull 예제
String e = null;
System.out.println(Objects.isNull(e)); // true
System.out.println(Objects.nonNull(e)); // false
// requireNonNullElse 예제
String str1 = null;
String str2 = "기본 문자열";
System.out.println(Objects.requireNonNullElse(str1, str2)); // "기본 문자열"
// requireNonNullElseGet 예제
String str3 = null;
System.out.println(Objects.requireNonNullElseGet(str3, () -> "Supplier 문자열")); // "Supplier 문자열"
// checkIndex 예제
try {
List<Integer> list = Collections.singletonList(1);
int index = Objects.checkIndex(1, list.size()); // IndexOutOfBoundsException 발생
} catch (IndexOutOfBoundsException e) {
System.out.println("유효하지 않은 인덱스입니다.");
}
Java
복사
java.util.Comparator
NOTE
Comparator는 객체를 비교하는 매커니즘을 제공합니다. 주로 컬렉션 프레임워크에서 객체 정렬, 순서 관리에서 주로 사용됩니다.
List<String> animals = new ArrayList<>();
animals.add("Dog");
animals.add("Elephant");
animals.add("Cat");
// Comparator 람다 표현식
Collections.sort(animals, Comparator.comparingInt(String::length));
System.out.println(animals); // [Dog, Cat, Elephant]
// naturalOrder 기본정렬
Collections.sort(animals, Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder()));
System.out.println(animals); // [Cat, Dog, Elephant]
// reversed 역정렬
Collections.sort(animals, Comparator.comparingInt(String::length)
.reversed());
System.out.println(animals); // [Elephant, Cat, Dog]
Java
복사
java.util.Arrays
NOTE
Arrays는 배열 구조를 조작, 변환, 정렬, 검색하는 정적 메서드들을 제공해줍니다!
// 배열 정렬(sort)
int[] numbers = {3, 1, 4, 1, 5, 9};
Arrays.sort(numbers);
System.out.println("Sorted numbers: " + Arrays.toString(numbers));
// 출력: Sorted numbers: [1, 1, 3, 4, 5, 9]
// 이진 검색(binarySearch)
int index = Arrays.binarySearch(numbers, 4);
System.out.println("Index of 4: " + index);
// 출력: Index of 4: 3
// 배열 복사(copyOf)
int[] copiedNumbers = Arrays.copyOf(numbers, numbers.length);
System.out.println("Copied array: " + Arrays.toString(copiedNumbers));
// 출력: Copied array: [1, 1, 3, 4, 5, 9]
// 배열 채우기(fill)
Arrays.fill(copiedNumbers, 7);
System.out.println("Array filled with 7: " + Arrays.toString(copiedNumbers));
// 출력: Array filled with 7: [7, 7, 7, 7, 7, 7]
// 배열을 리스트로 변환(asList)
String[] names = {"Alice", "Bob", "Charlie"};
System.out.println("Names list: " + Arrays.asList(names));
// 출력: Names list: [Alice, Bob, Charlie]
Java
복사
java.util.Collections
NOTE
Objects는 객체에 대한 일반적인 연산을 수행하는 정적 메서드들을 제공해 다양한 연산을 쉽게 처리할 수 있게 도와주는 유틸리티 클래스입니다.
// 리스트 정렬(sort)
List<String> fruits = new ArrayList<>();
fruits.add("Pineapple");
fruits.add("Apple");
fruits.add("Orange");
Collections.sort(fruits);
System.out.println("Sorted fruits: " + fruits);
// 출력: Sorted fruits: [Apple, Orange, Pineapple]
// 리스트 셔플 (shuffle)
Collections.shuffle(fruits);
System.out.println("Shuffled fruits: " + fruits);
// 출력: Shuffled fruits: [Pineapple, Apple, Orange] (출력은 실행할 때마다 달라질 수 있음)
// 리스트 뒤집기(reverse)
Collections.reverse(fruits);
System.out.println("Reversed fruits: " + fruits);
// 출력: Reversed fruits: [Orange, Apple, Pineapple] (셔플된 상태에 따라 다를 수 있음)
// 최대값, 최소값 찾기(max, min)
System.out.println("Max fruit: " + Collections.max(fruits));
System.out.println("Min fruit: " + Collections.min(fruits));
// 출력: Max fruit: Pineapple
// 출력: Min fruit: Apple
Java
복사
java.util.Collectors
NOTE
Objects는 객체에 대한 일반적인 연산을 수행하는 정적 메서드들을 제공해 다양한 연산을 쉽게 처리할 수 있게 도와주는 유틸리티 클래스입니다.
// 리스트 수집
Stream<String> names = Stream.of("John", "Paul", "George", "Ringo");
List<String> nameList = names.collect(Collectors.toList());
System.out.println(nameList);
// [John, Paul, George, Ringo]
// 길이별 문자열 그룹화
Stream<String> namesForGrouping = Stream.of("John", "Paul", "George", "Ringo");
Map<Integer, List<String>> nameByLength = namesForGrouping.collect(Collectors.groupingBy(String::length));
System.out.println(nameByLength);
// {4=[John, Paul], 5=[Ringo], 6=[George]}
// 문자열 조인
Stream<String> namesForJoin = Stream.of("John", "Paul", "George", "Ringo");
String joinNames = namesForJoin.collect(Collectors.joining(", "));
System.out.println(joinNames);
// John, Paul, George, Ringo
Java
복사
java.util.Optional
NOTE
Optional 클래스는 null이 될 수 있는 값을 캡슐화하는 컨테이너 객체입니다.
Optional<String> optionalPresent = Optional.of("Present");
Optional<String> optionalEmpty = Optional.empty();
// 값이 존재하는 경우 출력
optionalPresent.ifPresent(name -> System.out.println("name = " + name));
// 값이 없는 경우 기본값 설정
String nameOrDefault = optionalEmpty.orElse("Default");
System.out.println("nameOrDefault = " + nameOrDefault);
// 값이 있으면 가져오고, 없으면 새로운 Optional 생성
String value = optionalEmpty.orElseGet(() -> "New Value");
System.out.println("Value or New Value: " + value);
// 값이 없을 때 에러
try {
String valueOrThrow = optionalEmpty.orElseThrow(IllegalStateException::new);
System.out.println(valueOrThrow);
} catch (IllegalStateException e) {
System.out.println(e.getMessage());
}
Java
복사