ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [KB IT’s Your Life 7기] 백엔드개발을 위한 자바프로그래밍 후기 | 자바 2편
    카테고리 없음 2026. 5. 10. 23:58

    안녕하세요.

     
    백엔드 개발을 위한 자바프로그래밍 교육 후기

     

    지난번에 이어서 자바에 관련된 포스팅을 써보려고 해요...

     

    자바(Java)는 현재 실무에서 가장 널리 사용되는 언어 중 하나로, 

    특히 백엔드 개발에서 압도적인 점유율을 자랑합니다. 

     

    객체지향 프로그래밍의 핵심 개념들이 언어 자체에 깊이 녹아 있어, 

    자바를 제대로 배우는 것은 단순히 문법을 익히는 것이 아니라 

    소프트웨어 설계의 사고방식을 기르는 과정이기도 합니다.

     

     

     

     

    오늘은 지난시간에 끝낸 람다식 컬랙션과 더불어 스트림까지 한번 포스팅을 작성하도록 해보겠습니다!

     

    현대 자바 프로그래밍의 정수는 데이터를 어떻게 효율적으로 구조화하고(Collections)

    이를 얼마나 간결하고 선언적인 로직으로 처리하느냐(Lambda & Stream)에 달려 있습니다

     

     

     

     

    1. 자바 컬렉션 프레임워크(Collections Framework)
    데이터 저장의 표준화
    컬렉션 프레임워크는 다수의 데이터를 효율적으로 저장하고 관리하기 위한 표준화된 구조입니다. 고정된 크기의 배열과 달리, 객체 추가에 따라 크기가 자동으로 조절되는 유연성을 제공합니다.

     

     

    주요 인터페이스 및 선택 가이드

     

    가장 중요한 점은 Map이 Collection 인터페이스를 상속받지 않는 별개의 계보라는 점입니다. List와 Set은 add/remove를 공유하지만, Map은 키-값 구조로 put/get을 사용합니다.
     

    인터페이스특징대표 구현 클래스선택 기준 (Senior's Tip)

    List
    순서 유지, 중복 허용
    ArrayList, LinkedList
    인덱스 조회가 많으면 ArrayList, 삽입/삭제가 빈번하면 LinkedList
    ArrayList, LinkedList, Vector
     
    Set
    순서 무관, 중복 불허
    HashSet, TreeSet
    단순 중복 제거는 HashSet, 자동 정렬과 범위 검색 필요 시 TreeSet
    HashSet, TreeSet
     
    Map
    키-값 쌍, 키 중복 불허
    HashMap, TreeMap
    빠른 검색은 HashMap, 키 기준 정렬이 필요하면 TreeMap
    HashMap, Hashtable, TreeMap, Properties
     

    List 컬렉션: 데이터의 순서와 인덱스 관리

    List는 인덱스로 요소를 관리하며, 데이터의 순차적 접근이 필요할 때 사용됩니다.

    • ArrayList: 내부적으로 배열을 사용하며, 인덱스 조회가 매우 빠릅니다. 다만, 중간 삽입/삭제 시 요소 이동 비용이 발생하므로 조회 위주의 작업에 적합합니다.
    • LinkedList: 노드 간 참조로 연결되어 삽입/삭제가 빠르지만, 조회 시 처음부터 순차 탐색이 필요해 성능이 떨어집니다.
    • Arrays.asList의 함정: Arrays.asList()가 반환하는 리스트는 원본 배열과 데이터를 공유하는 "Backed-by" 구조입니다. 리스트 요소를 변경하면 배열도 변경되며, 고정 크기이므로 add()나 remove() 호출 시 예외가 발생합니다. 완전한 불변성이 필요하다면 List.of()를 사용하십시오.
    • Stack의 대안: 자바 초기의 Stack은 Vector를 상속받아 동기화 오버헤드가 큽니다. 현대 자바에서는 LIFO와 FIFO를 모두 지원하며 성능이 뛰어난 ArrayDeque 사용을 강력히 권장합니다.

     

     

    Set 컬렉션: 중복 불허와 집합의 논리

    HashSet은 해시 알고리즘을 통해 중복을 제거합니다. 이때 객체의 동등성 판단은 다음의 '계약(Contract)'을 따릅니다.

    1. hashCode() 결과가 같아야 함.
    2. equals() 결과가 true여야 함.

     

     

    Map 컬렉션: 효율적인 키-값 쌍 관리

    • HashMap vs Hashtable: Hashtable은 모든 메소드가 동기화되어 성능이 낮고 null을 불허합니다. 멀티스레드 환경이 아니라면 HashMap을, 스레드 안전이 필요하다면 ConcurrentHashMap을 사용하는 것이 표준입니다.
    • Properties: 키와 값을 String으로 제한하며, 외부 설정 파일(.properties)을 읽어 하드코딩을 방지하는 실무적인 도구로 활용됩니다.

    Comparable vs Comparator

    • Comparable: 클래스 내부에 자연적인 순서를 정의 (compareTo).
    • Comparator: 외부에서 별도의 정렬 기준을 주입 (compare).


     

     

     

     


    람다식(Lambda Expression)

     

    람다식은 함수형 인터페이스의 인스턴스를 생성하는 간결한 표현식입니다. 익명 클래스가 별도의 .class 파일을 생성하는 것과 달리, 람다는 JVM invokedynamic 활용해 런타임에 최적화된 방식으로 처리되어 성능상 이점이 큽니다.

     

     

    함수형 인터페이스
    람다는 추상 메서드가 단 하나인 인터페이스에서만 사용 가능합니다. @FunctionalInterface 어노테이션을 활용하면 컴파일 시점에 이 제약 조건을 검증할 수 있어 안전합니다.
    람다 문법과 생략 규칙
    추상 메소드가 하나인 @FunctionalInterface를 대상으로 하며, 다음의 생략 규칙이 적용됩니다.
    • 매개변수 1개: 괄호 () 생략 가능.
    • 실행문 1개: 중괄호 { } 생략 가능.
    • 리턴문 1: return 중괄호를 함께 생략.
    // 매개변수와 리턴값이 있는 람다식 예시
    Calculable calc = (x, y) -> x + y; ​

     

     

     

    메소드 참조(Method Reference)

     

     

    단순히 매개변수를 전달만 하는 경우 :: 연산자로 가독성을 극대화할 수 있습니다.

    1. 정적 메소드 참조: Computer::staticMethod
    2. 인스턴스 메소드 참조: com::instanceMethod
    3. 매개변수의 메소드 참조: String::compareToIgnoreCase ( 번째 매개변수가 호출 주체가 )
    4. 생성자 참조: Member::new

     

    스트림 API(Stream API): 데이터 처리 파이프라인

    스트림의 철학과 지연 연산(Lazy Evaluation)

     

    스트림은 데이터를 저장하지 않는 '흐름'입니다. 가장 중요한 특징은 지연 연산입니다. 최종 처리 메소드가 호출되기 전까지는 중간 처리 과정이 실제로 수행되지 않습니다.
    // 지연 연산의 예: 최종 처리가 없으면 filter 내부의 출력문은 실행되지 않음
    list.stream().filter(x -> {
        System.out.println("Filter 실행"); 
        return x > 0;
    });
    
     
     스트림 파이프라인 구동 원리
    스트림은 [오리지널 스트림 → 중간 처리 → 최종 처리]의 파이프라인 구조를 가집니다.
    중간 처리는 항상 새로운 스트림을 반환하며 필터링, 매핑, 정렬 등이 포함됩니다.
    for문 같은 외부 반복자와 달리, 스트림은 내부 반복자를 사용합니다. 개발자는 '어떻게'가 아닌 '무엇을' 할지에 집중하며, parallelStream()을 통해 복잡한 스레드 관리 없이도 손쉽게 병렬 처리를 구현할 수 있습니다.
    스트림 파이프라인 3단계
    double avg = list.stream()                    // 1. 오리지널 스트림 얻기
                     .mapToInt(s -> s.getScore()) // 2. 중간 처리 (매핑)
                     .filter(score -> score >= 80)// 2. 중간 처리 (필터링)
                     .average()                   // 3. 최종 처리 (집계)
                     .orElse(0.0);
    

     

    안전한 데이터 처리: Optional
    비어있는 스트림에서 집계 함수를 호출하면 NoSuchElementException이 발생할 수 있습니다. 이를 방지하기 위한 세 가지 전략은 다음과 같습니다.
    1. isPresent(): 값의 존재 여부 확인  get() 호출.
    2. orElse(): 값이 없을 경우 기본값 정의.
    3. ifPresent(): 값이 있을 때만 소비(Consume) 로직 실행.

     

    다음주 부터는 알고리즘 특강이 진행되는데

    정말 기대되는 수업 중 하나입니다.

    오늘은 여기까지하구 다음주에 만나요~

Designed by Tistory.