데이터 엔지니어링

패스트캠퍼스 환급챌린지 33일차: 데이터엔지니어링 초격차 강의 후기

Big Byte 2025. 5. 3. 18:04

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

자바 컬렉션 여정 3탄! 🚀 타입 마법 '제네릭스'와 코드 다이어트 '람다' 정복!

 

 

안녕하세요, 여러분! ✨

지난 시간에는 데이터 처리 순서의 달인, Queue, Stack, ArrayDeque를 만나봤죠! 🥞🚶‍♂️🚶‍♀️↔️ 데이터를 넣고 빼는 규칙을 배우며 코드의 흐름을 제어하는 법을 익혔습니다. 마치 교통정리를 하는 경찰관처럼 데이터의 입출고 순서를 명확하게 관리할 수 있게 되었어요! 🚦

 

하지만 컬렉션을 다루다 보면 이런 생각이 들 때가 있어요. "이 리스트에는 문자열만 넣고 싶은데, 실수로 숫자를 넣으면 어떡하지? 😨", "정렬 기준을 정해주려고 코드를 썼는데, 왜 이렇게 길고 복잡해 보이지? 😵‍💫" 이런 고민들, 다들 한 번쯤 해보셨죠?

 

오늘은 바로 이런 고민들을 시원하게 해결해 줄 자바의 강력한 기능, 제네릭스(Generics) 람다 표현식(Lambda Expressions)을 배워볼 시간입니다! 코드를 더 안전하게! 더 간결하게! 만들어주는 마법이죠. 🪄✨ 마치 복잡한 마법 주문을 더 강력하고 외우기 쉬운 주문으로 바꾸는 것과 같아요!

 

오늘 우리가 탐험할 코드 레벨업 세계는 다음과 같아요:

  1. 타입 걱정 끝! - 제네릭스 (Generics) <🎁> (타입 안전성 마법!)
  2. 코드가 짧아진다! - 람다 표현식 (Lambda Expressions) () -> {} (간결함 마법!)

자, 코드 업그레이드 준비되셨나요? 함께 떠나봅시다! 🚀

 

 

1. 타입 걱정 끝! - 제네릭스 (Generics) <🎁>

우리가 컬렉션을 사용할 때, 예를 들어 ArrayList에 여러 데이터를 담는다고 생각해봅시다. 그런데 이 리스트에 문자열(String)만 넣기로 약속했는데, 깜빡하고 숫자(Integer)를 넣어버리면 어떻게 될까요? 😱

import java.util.ArrayList;
import java.util.List;

public class BeforeGenerics {
    public static void main(String[] args) {
        List myFavoriteThings = new ArrayList(); // 타입 지정 없이 생성!

        myFavoriteThings.add("코딩");
        myFavoriteThings.add("커피");
        myFavoriteThings.add(123); // 앗! 실수로 숫자를 넣어버렸다!

        for (Object item : myFavoriteThings) {
            // 꺼낼 때마다 어떤 타입인지 모르니, 직접 확인하고 형변환 해야 함!
            String thing = (String) item; // 여기서 숫자 123을 만나면? -> 에러 발생!💥 (ClassCastException)
            System.out.println("내가 좋아하는 것: " + thing.toUpperCase());
        }
    }
}

위 코드처럼 타입을 명시하지 않으면, ArrayList는 모든 종류의 객체(Object)를 다 받아줍니다. 고마운 것 같지만... 나중에 꺼내 쓸 때 원래 어떤 타입이었는지 기억하고 직접 형변환((String))을 해줘야 해요. 만약 다른 타입이 실수로 들어갔다면? 프로그램을 실행하고 나서야 ClassCastException이라는 무시무시한 에러를 만나게 됩니다! 💣

 

마치 '아무거나 담는 상자'에 물건을 넣었다가, 꺼낼 때 "이게 사과였나? 배였나?" 헷갈리고 잘못 꺼내는 것과 같아요. 🍎🍐❓

이런 위험천만하고 번거로운 상황을 해결해주는 것이 바로 제네릭스(Generics)입니다! ✨

 

제네릭스는 컬렉션이 저장할 수 있는 데이터 타입을 미리 지정해주는 마법이에요. < > 기호 안에 타입을 명시해주면, 컴파일러(우리의 코드를 기계어로 번역해주는 친구)가 코드를 실행하기 전(컴파일 시점)에 타입이 맞는지 똑똑하게 체크해줍니다! ✅

import java.util.ArrayList;
import java.util.List;

public class WithGenerics {
    public static void main(String[] args) {
        // <String> 으로 이 리스트는 오직 문자열만 받겠다고 선언!
        List<String> myFavoriteThings = new ArrayList<>();

        myFavoriteThings.add("코딩");
        myFavoriteThings.add("커피");
        // myFavoriteThings.add(123); // 이 줄은 컴파일 에러! 🙅‍♀️ "String만 넣기로 했잖아!"

        // 꺼낼 때 이미 String 타입인 것을 알고 있으므로, 형변환 필요 없음!
        for (String thing : myFavoriteThings) {
            System.out.println("내가 좋아하는 것: " + thing.toUpperCase());
        }
    }
}

보세요! <String>이라고 타입을 명시하니, 이제 myFavoriteThings 리스트에는 문자열만 들어갈 수 있습니다. 만약 다른 타입을 넣으려고 하면, 코드를 실행하기도 전에 컴파일러가 "어허! 여긴 문자열만 넣는 곳이야!" 하고 알려주죠. 덕분에 우리는 훨씬 안전하고 깔끔하게 코드를 작성할 수 있습니다.

 

제네릭스의 장점:

  • 타입 안전성 향상: 컴파일 시점에 타입 오류를 미리 발견할 수 있어요. (런타임 에러 방지!)
  • 형변환 불필요: 꺼낼 때 어떤 타입인지 이미 알고 있으므로, 번거로운 형변환 코드가 사라져요. (코드 간결!)
  • 가독성 증가: <String>만 봐도 이 리스트가 무엇을 담는지 명확히 알 수 있어요.

이제 '아무거나 담는 상자'가 아니라 '사과 전용 상자'🍎, '책 전용 상자'📚처럼 확실하게 사용할 수 있게 된 거죠! 제네릭스, 정말 고마운 친구죠? 😊

 

2. 코드가 짧아진다! - 람다 표현식 (Lambda Expressions) () -> {}

자, 이번엔 코드를 확! 줄여주는 마법, 람다를 만나볼까요? ✨

혹시 자바에서 버튼 클릭 처리나, 리스트 정렬 같은 걸 할 때 아래처럼 생긴 코드를 본 적 있나요?

import java.util.*;

public class BeforeLambda {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("둘리", "고길동", "마이콜");

        // 이름을 가나다 순으로 정렬하고 싶을 때 (익명 클래스 사용)
        Collections.sort(names, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2); // 문자열 비교 로직
            }
        });

        System.out.println("정렬 후: " + names); // [고길동, 둘리, 마이콜]
    }
}

Collections.sort()를 사용해 리스트를 정렬하는데, 정렬 기준을 알려주기 위해 new Comparator<String>() { ... } 부분이 들어갔어요. 이걸 '익명 클래스(Anonymous Class)'라고 부릅니다. 딱 한 번 사용할 간단한 기능을 위해 클래스를 정의하고 객체를 생성하는 방식이죠. 그런데... 뭔가 좀 길고 거추장스러워 보이지 않나요? 😅 "그냥 문자열 비교만 해주면 되는데, 코드가 너무 장황해!" 라는 생각이 들 수 있죠.

 

이럴 때 람다 표현식(Lambda Expression)이 등장하면 코드가 놀랍게 간결해집니다! 🪄

람다는 이런 익명 클래스를 훨씬! 아주 훨씬! 간결하게 표현할 수 있도록 자바 8부터 도입된 혁신적인 기능이에요. 마치 긴 문장을 핵심만 요약한 메모처럼요. 📝

 

람다는 '함수형 인터페이스(Functional Interface)'라는 특별한 친구와 함께 작동해요. 이건 딱 하나의 추상 메소드만 가진 인터페이스를 말합니다. (위 예시의 Comparatorcompare라는 추상 메소드 하나만 가지고 있죠!)

람다의 기본 문법은 이렇습니다: (매개변수 목록) -> { 실행될 코드 }

 

위의 정렬 코드를 람다로 바꿔볼까요?

import java.util.*;

public class WithLambda {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("둘리", "고길동", "마이콜");

        // 람다 표현식으로 훨씬 간결하게! ✨
        Collections.sort(names, (String o1, String o2) -> {
            return o1.compareTo(o2);
        });

        // 더 줄일 수도 있어요! (타입 추론, 중괄호 및 return 생략)
        Collections.sort(names, (o1, o2) -> o1.compareTo(o2));

        System.out.println("정렬 후: " + names); // [고길동, 둘리, 마이콜]
    }
}

 

어때요? new Comparator<String>() { ... } 부분이 (o1, o2) -> o1.compareTo(o2) 이렇게 짧고 명료하게 바뀌었죠! 🎉 자바 컴파일러가 똑똑해서 매개변수 타입(String)도 생략 가능하고, 코드가 한 줄이면 중괄호 {}return 키워드까지 생략할 수 있답니다.

 

람다 표현식의 장점:

  • 코드 간결성: 익명 클래스의 장황한 코드를 확 줄여줘요.
  • 가독성 향상: (익숙해지면) 코드의 의도가 더 명확하게 보여요.
  • 함수형 프로그래밍: 데이터를 객체처럼 다루는 함수형 프로그래밍 스타일을 지원해요.

람다는 정렬뿐만 아니라 이벤트 처리, 스레드 생성(Runnable) 등 다양한 곳에서 코드를 깔끔하게 만드는 데 아주 유용하게 사용됩니다! 꼭 익혀두세요! 👍

 

정리하며 📝

오늘은 자바 코드를 한 단계 업그레이드 시켜주는 두 가지 강력한 마법, 제네릭스와 람다를 배웠습니다! 🪄

  • 제네릭스 (Generics) <🎁>: <타입>을 명시하여 컬렉션에 저장될 데이터 타입을 미리 지정! 컴파일 시점에 타입 오류를 잡고, 불필요한 형변환을 없애 코드를 안전하고 명확하게 만들어주는 타입 마법!
  • 람다 표현식 (Lambda Expressions) () -> {}: 익명 클래스의 장황함을 줄이고, 함수형 인터페이스를 간결하게 구현하는 코드 다이어트 비법! 코드를 짧고 읽기 쉽게 만들어주는 간결함 마법!

제네릭스와 람다는 현대 자바 개발에서 빼놓을 수 없는 필수 요소예요! 이 두 가지를 잘 활용하면 여러분의 코드는 더욱 견고하고, 세련되고, 효율적으로 변할 거예요! 💪

 

와! 오늘도 정말 중요한 개념들을 함께 마스터했네요! ✨ 제네릭스로 타입 안전성을 높이고, 람다로 코드를 간결하게 만드는 법까지! 여러분의 자바 실력이 한 단계 더 성장한 느낌, 드시나요? 😊 이 개념들은 직접 코드로 작성해보면서 손에 익히는 것이 중요해요. 꼭 한번 연습해보세요!

 

 

 

오늘은 즐거운 토요일! ☀️ 한 주 동안 열심히 코딩하며 달린 여러분, 오늘은 잠시 키보드에서 손을 떼고 푹 쉬면서 재충전하는 시간을 가지시길 바랍니다! 맛있는 것도 드시고, 좋아하는 영화도 보고, 꿀잠도 자면서 에너지를 가득 채우세요! 😴☕️🍕🎬

 

그럼 다음 시간에 더 유익하고 재미있는 내용으로 다시 만나요! 모두들 즐거운 주말 보내세요! 안녕~ 👋