🐯[TIL] 250619-014

byoΒ·2025λ…„ 6μ›” 19일

πŸ’« JAVA

βœ”οΈ Generics

βœ… Genericsλž€?

  • ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œμ—μ„œ μ‚¬μš©ν•  데이터 νƒ€μž…μ„ λ‚˜μ€‘μ— μ§€μ •ν•  수 μžˆλ„λ‘ ν•΄μ£ΌλŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€.
  • 컴파일 μ‹œ νƒ€μž…μ„ μ²΄ν¬ν•˜λ―€λ‘œ 였λ₯˜λ₯Ό 쀄이고 νƒ€μž… μ•ˆμ •μ„±μ„ λ†’μž…λ‹ˆλ‹€.
  • λ‹€μ–‘ν•œ νƒ€μž…μ— μž¬μ‚¬μš© κ°€λŠ₯ν•˜μ—¬ μ½”λ“œ 쀑볡을 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€. νƒ€μž…λ³„ μ½”λ“œ λ¬΄ν•œμƒμ‚° κ°€λŠ₯

βœ… μ œλ„€λ¦­ 클래슀 μ •μ˜

  • 클래슀 이름 뒀에 <T>λ₯Ό 뢙이면 TλŠ” 'νƒ€μž… λ§€κ°œλ³€μˆ˜'κ°€ λ©λ‹ˆλ‹€.
  • 이 νƒ€μž…μ€ 객체λ₯Ό λ§Œλ“€ λ•Œ μ‹€μ œ νƒ€μž…μœΌλ‘œ μ§€μ •λ©λ‹ˆλ‹€.
  • 클래슀 λ‚΄λΆ€μ—μ„œ Tλ₯Ό λ³€μˆ˜ νƒ€μž…μ΄λ‚˜ λ°˜ν™˜ νƒ€μž… λ“±μœΌλ‘œ 자유둭게 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ˜ν•œ λ©”μ„œλ“œμ— λ³„λ„μ˜ μ œλ„€λ¦­ νƒ€μž… <E>λ₯Ό μ‚¬μš©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
class Box<T> {
    private T content;

    public Box(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }

    public void setContent(T content) {
        this.content = content;
    }

    // μ œλ„€λ¦­ λ©”μ„œλ“œ μ˜ˆμ‹œ (EλŠ” λ©”μ„œλ“œ μ „μš© νƒ€μž…)
    public <E> void printContent(E extraInfo) {
        System.out.println("Content: " + content + ", Extra: " + extraInfo);
    }
}

ℹ️ Wrapper

Box<int> box = new Box<>();
        int => Integer;
        double => Double;
        float => Float;
        char => Character;
        primitive type이 genericsλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ Wrapperκ°€ μ”Œμ›Œμ§„ Objectλ₯Ό 상속받은 νƒ€μž…μœΌλ‘œ 감싸주어야 ν•œλ‹€.

✏️ μ œλ„€λ¦­ λ©”μ„œλ“œ μ‹€μŠ΅

  • μ•žμ—μ„œ μ •μ˜ν•œ μ œλ„€λ¦­ λ©”μ„œλ“œ displayArray()λ₯Ό μ‚¬μš©ν•΄ λ‹€μ–‘ν•œ νƒ€μž…μ˜ 배열을 좜λ ₯ν•΄λ΄…λ‹ˆλ‹€.
  • νƒ€μž…μ— 상관없이 ν•˜λ‚˜μ˜ λ©”μ„œλ“œλ‘œ μ²˜λ¦¬ν•  수 μžˆμ–΄ μ½”λ“œκ°€ κ°„κ²°ν•΄μ§‘λ‹ˆλ‹€.
class Box {
    public static <T> void displayArray(T[] array) {
        for(T element : array) {
            System.out.println(element);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Integer[] numbers = {1, 2, 3, 4, 5};
        String[] words = {"apple", "banana", "cherry"};
        Box.displayArray(numbers);
        Box.displayArray(words);
    }
}

ℹ️ μ œλ„€λ¦­μ΄ μ—†λ‹€λ©΄?

  • λ™μΌν•œ 둜직의 클래슀λ₯Ό νƒ€μž…λ§ˆλ‹€ μ—¬λŸ¬ 개 λ§Œλ“€κ²Œ 됨
  • BoxInt, BoxString λ“± 쀑볡 λ°œμƒ
  • GenericsλŠ” 이런 쀑볡을 λ°©μ§€ν•˜κ³  μ½”λ“œ μœ μ§€λ³΄μˆ˜λ₯Ό μ‰½κ²Œ 함

πŸ” Generics 핡심 μš”μ•½ 정리

ν•­λͺ©μ„€λͺ…
κ°œλ…νƒ€μž…μ„ μΌλ°˜ν™”ν•΄ μ½”λ“œ μž¬μ‚¬μš©μ„±κ³Ό μ•ˆμ •μ„±μ„ λ†’μ΄λŠ” κΈ°λŠ₯
λŒ€ν‘œ ν‚€μ›Œλ“œ<T>, <E>, <K, V> λ“± νƒ€μž… λ§€κ°œλ³€μˆ˜ μ‚¬μš©
적용 λŒ€μƒν΄λž˜μŠ€, λ©”μ„œλ“œ, μΈν„°νŽ˜μ΄μŠ€ λͺ¨λ‘ μ‚¬μš© κ°€λŠ₯
μž₯점컴파일 μ‹œ νƒ€μž… 체크, 쀑볡 μ½”λ“œ 제거, νƒ€μž… μ•ˆμ •μ„± ν–₯상
μ œλ„€λ¦­ 클래슀class Box<T> ν˜•νƒœλ‘œ μ„ μ–Έν•˜μ—¬ λ‹€μ–‘ν•œ νƒ€μž… 처리
μ œλ„€λ¦­ λ©”μ„œλ“œpublic <T> void method(T param) ν˜•νƒœλ‘œ μ„ μ–Έ
νƒ€μž… μΆ”λ‘ λ©”μ„œλ“œ 호좜 μ‹œ μ „λ‹¬λœ 인자 νƒ€μž…μœΌλ‘œ μžλ™ μœ μΆ”λ¨
νƒ€μž… μ œν•œ<T extends Number>처럼 μƒν•œ μ œν•œ κ°€λŠ₯

βœ”οΈ '?' μ™€μΌλ“œμΉ΄λ“œ

βœ… μ™€μΌλ“œμΉ΄λ“œλž€?

  • μ œλ„€λ¦­μ—μ„œ ?λŠ” μ–΄λ–€ νƒ€μž…μ΄λ“  올 수 μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.
  • νƒ€μž…μ„ μœ μ—°ν•˜κ²Œ ν•˜λ©΄μ„œλ„ 컴파일 μ‹œ νƒ€μž… μ•ˆμ •μ„±μ„ μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λŒ€ν‘œ μ˜ˆμ‹œ: List<?> β†’ 아무 νƒ€μž…μ΄λ‚˜ 받을 수 있음
    List<? extends Number> β†’ Number λ˜λŠ” κ·Έ ν•˜μœ„ νƒ€μž…λ§Œ ν—ˆμš©

ℹ️ 곡변성과 λΆˆκ³΅λ³€μ„±

  • Integer[]은 Object[]둜 μ‚¬μš© κ°€λŠ₯ β†’ 곡변(covariant): ν•˜μœ„ νƒ€μž… 배열을 μƒμœ„ νƒ€μž… λ°°μ—΄λ‘œ 처리 κ°€λŠ₯
  • ν•˜μ§€λ§Œ List<Integer>λŠ” List<Object>둜 μ‚¬μš©ν•  수 μ—†μŒ β†’ λΆˆκ³΅λ³€(invariant): μ œλ„€λ¦­μ€ νƒ€μž…μ΄ μ •ν™•νžˆ μΌμΉ˜ν•΄μ•Ό 함
public static void printArray(Object[] arr) {
    for (Object o : arr) System.out.println(o);
}

βœ… λΆˆκ³΅λ³€ μ˜ˆμ‹œ

  • μ œλ„€λ¦­ νƒ€μž…μ€ 기본적으둜 λΆˆκ³΅λ³€(invariant)이라 μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
  • μ•„λž˜ μ½”λ“œλŠ” List<Integer>λ₯Ό List<Object>둜 λ°”κΎΈλ €κ³  ν•΄μ„œ 컴파일 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.
List<Integer> list = Arrays.asList(1, 2, 3);
List<Object> objList = list; // 였λ₯˜!

✏️ printElements λ©”μ„œλ“œ

  • List<?>λŠ” μ–΄λ–€ νƒ€μž…μ˜ λ¦¬μŠ€νŠΈλ“  받을 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 좜λ ₯만 ν•  κ²½μš°μ—λŠ” νƒ€μž…μ— 상관없이 μ•ˆμ „ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
public static void printElements(List<?> list) {
    for (Object o : list) {
        System.out.println(o);
    }
}

✏️ sumList λ©”μ„œλ“œ

  • List<? extends Number>λŠ” Integer, Double λ“± 숫자 νƒ€μž… 리슀트λ₯Ό 받을 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 각 μš”μ†Œλ₯Ό doubleValue()둜 λ³€ν™˜ν•΄ 합계λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.
public static double sumList(List<? extends Number> list) {
    double sum = 0;
    for (Number n : list) {
        sum += n.doubleValue();
    }
    return sum;
}
public static void main(String[] args) {
	List<Integer> intList = Arrays.asList(10, 20, 30);
	System.out.println("합계: " + sumList(intList));
}

πŸ” μ™€μΌλ“œμΉ΄λ“œ μš”μ•½ 정리

ν˜•νƒœμ„€λͺ…
<?>λͺ¨λ“  νƒ€μž… ν—ˆμš© (읽기만 κ°€λŠ₯, μ“°κΈ°λŠ” λΆˆκ°€)
<? extends T>T λ˜λŠ” ν•˜μœ„ νƒ€μž… ν—ˆμš© (읽기만 κ°€λŠ₯)
<? super T>T λ˜λŠ” μƒμœ„ νƒ€μž… ν—ˆμš© (μ“°κΈ° κ°€λŠ₯, μ½κΈ°λŠ” Object둜)
List<T>μ •ν™•ν•œ T만 ν—ˆμš© (읽기/μ“°κΈ° λͺ¨λ‘ κ°€λŠ₯)

βœ”οΈ Stream

βœ… Streamμ΄λž€?

  • μžλ°” 슀트림(Stream)은 데이터λ₯Ό 일련의 λ‹¨κ³„λ‘œ μ²˜λ¦¬ν•˜λŠ” 흐름(νŒŒμ΄ν”„λΌμΈ)μž…λ‹ˆλ‹€.
  • λžŒλ‹€μ™€ ν•¨κ»˜ μ‚¬μš©λ˜μ–΄ μ½”λ“œκ°€ 더 κ°„κ²°ν•˜κ³  읽기 μ‰¬μ›Œμ§‘λ‹ˆλ‹€.
  • forλ¬Έμ΄λ‚˜ Iterator보닀 ν•¨μˆ˜ν˜• μŠ€νƒ€μΌλ‘œ 데이터λ₯Ό 닀루고 싢을 λ•Œ μœ μš©ν•œ λŒ€μ•ˆμž…λ‹ˆλ‹€.

βœ… 리슀트 생성 및 슀트림 μ‹œμž‘

  • μŠ€νŠΈλ¦Όμ€ 보톡 List, Set 같은 μ»¬λ ‰μ…˜μ—μ„œ stream() λ©”μ„œλ“œλ‘œ μƒμ„±ν•©λ‹ˆλ‹€.
  • 이 μŠ€νŠΈλ¦Όμ„ 톡해 데이터λ₯Ό 순차적으둜 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();

βœ… λ©”μ„œλ“œ 체이닝

  • μŠ€νŠΈλ¦Όμ€ λ©”μ„œλ“œλ₯Ό 쀄쀄이 이어 λΆ™μ—¬μ„œ μ²˜λ¦¬ν•©λ‹ˆλ‹€.
  • 각 λ©”μ„œλ“œλŠ” 데이터λ₯Ό κ±ΈλŸ¬λ‚΄κ±°λ‚˜ λ³€ν˜•ν•˜κ³  λ‹€μŒ λ‹¨κ³„λ‘œ λ„˜κΉλ‹ˆλ‹€.
  • λ§ˆμ§€λ§‰μ—λŠ” κ²°κ³Όλ₯Ό ν•˜λ‚˜λ‘œ λͺ¨μ•„ μ΅œμ’… κ²°κ³Όλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
numbers.stream()
       .filter(n -> n % 2 == 0)
       .mapToInt(Integer::intValue)
       .sum();

βœ… filter() λ©”μ„œλ“œ

  • 쑰건에 λ§žλŠ” μš”μ†Œλ§Œ 남기고 λ‚˜λ¨Έμ§€λŠ” μ œμ™Έν•©λ‹ˆλ‹€.
  • 예: 짝수만 ν•„ν„°λ§ν•˜μ—¬ λ‹€μŒ λ‹¨κ³„λ‘œ μ „λ‹¬ν•©λ‹ˆλ‹€.
numbers.stream()
       .filter(n -> n % 2 == 0)

βœ… mapToInt() λ©”μ„œλ“œ

  • Integer 같은 래퍼 νƒ€μž…μ„ κΈ°λ³Έν˜• int둜 λ°”κΏ” IntStream을 λ§Œλ“­λ‹ˆλ‹€.
  • λžŒλ‹€ λŒ€μ‹  Integer::intValue처럼 λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ“°λ©΄ 더 κ°„κ²°ν•˜κ²Œ ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
.mapToInt(Integer::intValue)

βœ… sum()으둜 합계 κ΅¬ν•˜κΈ°

  • sum()은 IntStream의 μ΅œμ’… μ—°μ‚°μœΌλ‘œ, λͺ¨λ“  μš”μ†Œλ₯Ό λ”ν•œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
  • μ΅œμ’… 연산이 μ‹€ν–‰λ˜λ©΄ μŠ€νŠΈλ¦Όμ€ μ†Œλͺ¨λ˜λ©° λ‹€μ‹œ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
.sum();

βœ… 전체 예제 μ½”λ“œ
λ¦¬μŠ€νŠΈμ—μ„œ 짝수만 κ³¨λΌμ„œ κ·Έ 합을 κ΅¬ν•˜λŠ” 전체 μ½”λ“œμž…λ‹ˆλ‹€.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
                 .filter(n -> n % 2 == 0)
                 .mapToInt(Integer::intValue)
                 .sum();
System.out.println("Sum of even numbers: " + sum);

βœ… average()둜 평균 κ΅¬ν•˜κΈ°

  • mapToDouble()둜 Double 슀트림 생성 ν›„ average()
  • 평균은 OptionalDouble둜 λ°˜ν™˜λ˜λ©°, orElse()둜 κΈ°λ³Έκ°’ μ„€μ • κ°€λŠ₯
List<Double> values = Arrays.asList(10.0, 20.0, 30.0);
double avg = values.stream()
                    .mapToDouble(Double::doubleValue)
                    .average()
                    .orElse(0.0);

πŸ” Stream μ£Όμš” λ©”μ„œλ“œ μš”μ•½

λ©”μ„œλ“œμ„€λͺ…
stream()μ»¬λ ‰μ…˜(List λ“±)을 슀트림으둜 λ³€ν™˜
filter()쑰건에 λ§žλŠ” μš”μ†Œλ§Œ κ±ΈλŸ¬λƒ„ (쀑간 μ—°μ‚°)
mapToInt()Integerλ₯Ό κΈ°λ³Έν˜• int둜 λ³€ν™˜ν•˜μ—¬ IntStream 생성
mapToDouble()Double을 double둜 λ³€ν™˜ν•˜μ—¬ DoubleStream 생성
sum()숫자 합계 계산 (μ΅œμ’… μ—°μ‚°)
average()평균 계산, κ²°κ³ΌλŠ” OptionalDouble둜 λ°˜ν™˜λ¨ (μ΅œμ’… μ—°μ‚°)
orElse()Optional 값이 없을 λ•Œ κΈ°λ³Έκ°’ λ°˜ν™˜
profile
πŸ—‚οΈ hamstern

0개의 λŒ“κΈ€