본문 바로가기

(09.02) java 기초 - Collections 활용, Generic, Iterator, 날짜시간 API, 예외처리

@starweb2025. 9. 2. 18:06

[ 4주차 - 0902 ] 

    금일 커리큘럼
        ├ 09:00 ~ 12:00 자바 프로그래밍 기초 (Collections 활용, Generic)
        └ 13:00 ~ 18:00 자바 프로그래밍 기초 (Iterator, 날짜시간 API, 예외처리)

1. Collections 활용

  • java.util.Collections
  • 컬렉션 프레임워크에 포함된 클래스
  • 컬렉션을 조작하거나 변환하는 데 사용되는 유틸리티 메서드

간단한 예제

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


public class ExamCollections {
    public static void main(String[] args) {
        // 인티저 ------------------------------
        System.out.println("title: 정수형 확인");
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i <= 10; i++) {
            list.add(i);
        }

        Collections.shuffle(list); // 랜덤섞기
        System.out.println(list); // [8,1,3 ...]

        Collections.sort(list); // 오름차순
        System.out.println(list); // [0,1..,10]


        Collections.sort(list, Collections.reverseOrder()); // 내림차순
        System.out.println(list); // [10,9..,1]

        Collections.reverse(list); // 뒤집기
        System.out.println(list); // [0,1..,10]

        System.out.println("─".repeat(30));

        // 스트링 ------------------------------
        System.out.println("title: 스트링 확인");
        List<String> listStr = new ArrayList<>();
        listStr.add("가나");
        listStr.add("마바");
        listStr.add("다라");

        Collections.sort(listStr);
        System.out.println(listStr); // [가나, 다라, 마바]

        System.out.println("─".repeat(30));
    }
}
# 실행 결과
title: 정수형 확인
[9, 5, 7, 2, 3, 1, 10, 6, 4, 0, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
──────────────────────────────
title: 스트링 확인
[가나, 다라, 마바]
──────────────────────────────

객체 정렬 예제


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

// 테스트용 Comparable
class TestPerson implements Comparable<TestPerson> {
    private String name;
    private int age;

    public TestPerson(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
    @Override
    public int compareTo(TestPerson o) {
        // Comparable 인터페이스 오버라이딩
        return this.age - o.age; // 나이기준
        //return this.name.compareTo(o.name); // 이름기준
    }

    @Override
    public String toString() {
        return "\nTestPerson{" +
                "name='" + name + '\'' +
                ", age=" + age +
                "}";
    }
}

public class ExamCollections {
    public static void main(String[] args) {
        List<TestPerson> list1 = new ArrayList<>();

        list1.add(new TestPerson("안녕", 1));
        list1.add(new TestPerson("가나", 30));
        list1.add(new TestPerson("다라", 10));
        list1.add(new TestPerson("마바", 20));

        // 내부 오버라이딩시 - 나이기준으로 기준 정의됨 ---------------------
        Collections.sort(list1);
        System.out.println("내부 compareTo: " + list1);
        System.out.println("─".repeat(30));

        List<TestPerson> list2 = new ArrayList<>();
        list2.add(new TestPerson("홍길동", 50));
        list2.add(new TestPerson("김철수", 30));

        // 내부 익명 예시 (Comparator) ---------------------
        Collections.sort(list2, new Comparator<TestPerson>() {
            @Override
            public int compare(TestPerson o1, TestPerson o2) {
                return o1.getName().compareTo(o2.getName()); // 이름순 기준
            }
        });
        System.out.println("list2 Comparator: " + list2);
        System.out.println("─".repeat(30));

        // 람다 - 나이 기준 정렬 (compare) ---------------------
        Collections.sort(list1, (a, b) -> Integer.compare(a.getAge(), b.getAge()));
        System.out.println("람다-나이: " + list1);
        System.out.println("─".repeat(30));


        // 람다 - 이름 기준 정렬 (compareTo) ---------------------
        Collections.sort(list1, (a, b) -> a.getName().compareTo(b.getName()));
        System.out.println("람다-이름: " + list1);
        System.out.println("─".repeat(30));

        // 컴페어투 확인
        System.out.println("'가,나' 비교: " + "가".compareTo("나")); // -1176
        System.out.println("'나,가' 비교: " + "나".compareTo("가")); // 1176
        System.out.println("'B,A' 비교: " + "B".compareTo("A")); // 1
    }
}
내부 compareTo: [
TestPerson{name='안녕', age=1}, 
TestPerson{name='다라', age=10}, 
TestPerson{name='마바', age=20}, 
TestPerson{name='가나', age=30}]
──────────────────────────────
list2 Comparator: [
TestPerson{name='김철수', age=30}, 
TestPerson{name='홍길동', age=50}]
──────────────────────────────
람다-나이: [
TestPerson{name='안녕', age=1}, 
TestPerson{name='다라', age=10}, 
TestPerson{name='마바', age=20}, 
TestPerson{name='가나', age=30}]
──────────────────────────────
람다-이름: [
TestPerson{name='가나', age=30}, 
TestPerson{name='다라', age=10}, 
TestPerson{name='마바', age=20}, 
TestPerson{name='안녕', age=1}]
──────────────────────────────
가,나 비교 :-1176
나,가 비교 :1176
1

Comparable 과 Comparator

  • Comparable 인터페이스
    • implements Comparable<클래스명>
    • 객체의 기본 정렬 기준을 정의 - compareTo() 메소드 구현
    • 자바 객체가 자연스러운 순서로 정렬될 수 있도록 함
    • 구현시 compareTo 메서드를 오버라이드하여 객체 간의 정렬 순서를 정의
class TestPerson implements Comparable<TestPerson> {
    private String name;
    private int age;
    // pre code ...
    @Override
    public int compareTo(TestPerson o) {
        return this.age - o.age; // 나이 기준 오름차순
        // return this.name.compareTo(o.name); // 이름 기준
    }
    // next code ...
}
  • Comparator 인터페이스
    • 객체들을 특정한 기준으로 정렬할 때 사용
    • 별도의 정렬 기준을 정의 - compare() 메소드 구현
    • compare 메서드를 오버라이드하여 두 객체를 비교하는 방식을 정의
    • Comparable은 내부에서 가능한 반면 Comparator객체 외부에서 정렬 기준을 정의
    • getter 필요함
Collections.sort(list2, new Comparator<TestPerson>() {
    @Override
    public int compare(TestPerson o1, TestPerson o2) {
        // return o1.getAge - o2.getAge; // 나이 기준
        return o1.getName().compareTo(o2.getName()); // 이름 기준
    }
});
  • 람다식 ((a, b) -> ...) 활용
    • Comparator를 람다로 간단히 표현 가능
// 나이 기준 정렬
Collections.sort(list1, (a, b) -> a.getAge().compareTo(b.getAge()));
// 이름 기준 정렬
Collections.sort(list1, (a, b) -> a.getName().compareTo(b.getName()));

2. 제네릭 (Generic)

어떤 것이든 담는 상자

  • 어떤 객체가 들어올지 모를 경우 임의 타입을 정하여 사용하는 방식
    • 예: <T>, <I>, <E>
  • 컴파일 타임에 타입 안전성을 보장함
  • 형변환(casting) 불필요
  • 정해진 타입만 사용하도록 강제
public class GenericBox<T> {
    private T item;

    public T getValue() {
        return item;
    }
    public void setValue(T item) {
        this.item = item;
    }
}
public class Pen {
    private String name;
    private int price;

    public Pen(String name,int price ){
        this.name=name;
        this.price=price;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    public void write() {
        System.out.println(name + "을 쓴다");
    }

    @Override
    public String toString() {
        return "Pen{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
public class ExamGeneric {
    public static void main(String[] args) {
        GenericBox<Pen> penBox = new GenericBox<>();
        Pen pen1 = new Pen("볼펜",1300);
        penBox.setItem(pen1);

        System.out.println(penBox.getItem());
        // Pen{name='볼펜', price=1300}
        penBox.getItem().write();
        // 볼펜을 쓴다
    }
}

3. Collection과 Iterator (*복습)

Collection 인터페이스

  • 의미: 자바에서 데이터 집합을 다루는 최상위 인터페이스 중 하나
  • 주요 하위 인터페이스
    • List : 순서가 있고, 중복 허용. (ArrayList, LinkedList)
    • Set : 순서가 없고(HashSet), 중복 불가. (HashSet, LinkedHashSet, TreeSet)
    • Queue : 선입선출(FIFO) 구조. (LinkedList, PriorityQueue)

Iterator 인터페이스

  • 의미: Collection 내부 요소를 순차적으로 탐색하기 위한 도구
  • 주요 메서드
    • hasNext() : 다음 요소가 있으면 true 반환
    • next() : 다음 요소 반환 (커서 이동)
    • remove() : 현재 위치의 요소 제거
public class ExamIterator {
    public static void main(String[] args) {
        List<String> lists = new ArrayList<>();
        fruits.add("사과");
        fruits.add("바나나");
        fruits.add("포도");

        // Iterator를 이용한 순회
        Iterator<String> iterLists = lists.iterator(); // Iterator 생성

        while (iterLists.hasNext()) { // 다음 요소가 있는지 확인
            String str = iterLists.next(); // 요소 꺼내기
            System.out.println(str);
        }

        // for-each 문 (내부적으로 Iterator 사용됨)
        for (String item : lists) {
            System.out.println(item);
        }
    }
}

4. 날짜와 시간 API

  • Date : 구버전 방식
  • Calendar : java1.1 에 추가된 구버전 개선판
  • java8 이후 java.time 패키지
    • LocalDate : 날짜만 다룸 (연, 월, 일).
    • LocalDateTime : 시간만 다룸 (시, 분, 초, 나노초)
    • ZonedDateTime : 날짜 + 시간 함께 다룸

Date 구버전 방식

import java.util.Date;
import java.text.SimpleDateFormat;

public class ExamDate {
    public static void main(String[] args) {
        // Date 올드 버전임  -----------------------------------------
        Date date = new Date();
        System.out.println(date); // Tue Sep 02 13:18:20 KST 2025 (현재날짜)
        Date date1 = new Date(2000,1,1);
        System.out.println(date1); // Thu Feb 01 00:00:00 KST 3900
        // 연도 1900부터 , 월 0~11 (출력할떄+1)

        int _calcyear = 1900;
        int _calcMonth = 1;
        Date date2 = new Date((2000 - _calcyear),(10 - _calcMonth),9);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        System.out.println(sdf.format(date)); // 2025-09-02 13:21:33
        System.out.println(sdf.format(date1)); // 3900-02-01 00:00:00
        System.out.println(sdf.format(date2)); // 2000-10-09 00:00:00
    }
}

Date() 생성자는 Deprecated(사용 권장하지 않음)

Calendar 방식

import java.util.Calendar;
import java.text.SimpleDateFormat;

public class ExamCalendar {
    public static void main(String[] args) {
        // Calendar = 추상클래스임 -----------------------------------------
        // 현재날짜 : 2025-09-02 화요일
        Calendar cal = Calendar.getInstance();
        System.out.println(cal.get(Calendar.YEAR)); // 2025
        System.out.println(cal.get(1)); // 2025
        System.out.println(cal.get(Calendar.MONTH)); // 8 
        System.out.println(cal.get(Calendar.DAY_OF_MONTH)); // 2
        System.out.println(cal.get(Calendar.DAY_OF_WEEK)); // 3
        // DAY_OF_WEEK ?
        //일1, 월2, 화3, 수4, 목5, 금6, 토7


        cal.set(2000, Calendar.JANUARY, 1); // 2000년 1월 1일
        Date calDate = cal.getTime();

        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(sdf2.format(calDate)); // 2000-01-01
    }
}

연습 : Calendar 로 달력만들기

import java.util.Calendar;
import java.util.Scanner;

public class ExamCalendar {
    static Scanner sc = new Scanner(System.in);

    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();

        System.out.println("달력 만들기 (ex: 2025-09)");
        System.out.print("입력: ");

        String input = sc.nextLine();
        int year, month;
        String[] strArr;

        strArr = input.split("-");
        year = Integer.parseInt(strArr[0]);
        month = Integer.parseInt(strArr[1]);

        cal.set(year, month - 1, 1);

        int startDay = cal.get(Calendar.DAY_OF_WEEK); // 요일 위치 정수값
        int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH); // 해당월 마지막 날

        System.out.println();
        System.out.printf(
                "─".repeat(6) + "[ %04d년 %02d월 ]" + "─".repeat(6) + "%n",
                year, month
        );
        System.out.println("일\t월\t화\t수\t목\t금\t토");

        for (int i = 1; i < startDay; i++) {
            System.out.print("\t"); // 시작위치 만큼 탭
        }

        for (int day = 1; day <= maxDay; day++) {
            System.out.printf("%2d\t", day);
            // (day + startDay - 1)
            // startDay가 1이면 월요일부터 시작
            // X 1 2 3 4 5 6 이런 느낌으로 들어가야 함
            if ((day + startDay - 1) % 7 == 0) {  //일주일마다 줄바꿈
                System.out.println();
            }
        }

        System.out.println();
        System.out.println("─".repeat(26));
    }
}
# 실행 결과 (2025-09입력)
──────[ 2025년 09월 ]──────
일    월    화    수    목    금    토
     1     2     3     4     5     6    
 7     8     9    10    11    12    13    
14    15    16    17    18    19    20    
21    22    23    24    25    26    27    
28    29    30    
──────────────────────────

java8 이후 java.time

LocalDate, LocalTime, LocalDateTime

  • LocalDate : 날짜만 (연, 월, 일만 표현)
  • LocalTime : 시간만 (시, 분, 초, 나노초만 표현)
  • LocalDateTime : 날짜 + 시간 (연/월/일 + 시/분/초까지 다 포함)
    • 사람이 읽는 날짜, 시간 (타임존 없음)
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class ExamLocalApi {
    public static void main(String[] args) {
        // 현재날짜 : 2025-09-02
        // 현재 날짜/시간
        LocalDate date = LocalDate.now();
        LocalTime time = LocalTime.now();
        LocalDateTime dateTime = LocalDateTime.now();

        System.out.println("날짜: " + date);
        System.out.println("시간: " + time);
        System.out.println("날짜시간: " + dateTime);
        System.out.println("─".repeat(10));

        // 특정 날짜/시간 생성
        LocalDate date01 = LocalDate.of(2000, 1, 1); // yyy-mm-dd
        LocalTime noon = LocalTime.of(12, 0); // hh:mm
        LocalDateTime appointment = LocalDateTime.of(2024, 12, 25, 18, 30);
        // yyy-mm-ddThh:mm

        System.out.println(date01);
        System.out.println(noon);
        System.out.println(appointment);
        System.out.println("─".repeat(10));

        // 날짜 연산 (minus,plus)
        System.out.println("어제: " + date.minusDays(1));
        System.out.println("내일: " + date.plusDays(1));
        System.out.println("지난주: " + date.minusWeeks(1));
        System.out.println("다음주: " + date.plusWeeks(1));
        System.out.println("지난달: " + date.minusMonths(1));
        System.out.println("다음달: " + date.plusMonths(1));
        System.out.println("─".repeat(10));

        // 날짜 정보 추출
        System.out.printf("%d년 %s %d일 %s%n",
                date.getYear(),
                date.getMonth(),
                date.getDayOfMonth(),
                date.getDayOfWeek()
        ); // 2025년 SEPTEMBER 2일 TUESDAY
        // 숫자월 표기시 : date.getMonthValue()

    }
}
# 실행 결과
날짜: 2025-09-02
시간: 14:43:55.861742600
날짜시간: 2025-09-02T14:43:55.861742600
──────────
2000-01-01
12:00
2024-12-25T18:30
──────────
어제: 2025-09-01
내일: 2025-09-03
지난주: 2025-08-26
다음주: 2025-09-09
지난달: 2025-08-02
다음달: 2025-10-02
──────────
2025년 SEPTEMBER 2일 TUESDAY

ZonedDateTime (시간대 포함된 날짜/시간)

  • 연, 월, 일, 시, 분, 초, 나노초 + 타임존(ZoneId) + 오프셋(UTC±시차) 까지 포함
  • 전 세계 표준 시간 변환할 때 꼭 필요
  • 서버/클라이언트가 다른 나라일 때 필수적으로 사용
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;

public class ExamLocalApi {
    public static void main(String[] args) {
        // 현재날짜 2025-09-02
        // 시스템 기본 시간대
        ZoneId systemZone = ZoneId.systemDefault();
        System.out.println("내 지역(TimeZone): " + systemZone);

        // 현재 시간대의 날짜시간
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println("현재(서울): " + now);

        // 다른 시간대로 변환
        ZonedDateTime newYork = now.withZoneSameInstant(
                ZoneId.of("America/New_York"));
        System.out.println("뉴욕: " + newYork);

        // 특정 시간대로 생성
        ZonedDateTime paris = ZonedDateTime.of(
                LocalDateTime.now(),
                ZoneId.of("Europe/Paris"));
        System.out.println("파리: " + paris);

        // 사용 가능한 시간대 확인
        Set<String> zoneIds = ZoneId.getAvailableZoneIds();
        zoneIds.stream()
                .filter(z -> z.contains("Seoul"))
                .forEach(System.out::println);
    }
}
# 실행 결과
내 지역(TimeZone): Asia/Seoul
현재(서울): 2025-09-02T14:51:02.224749500+09:00[Asia/Seoul]
뉴욕: 2025-09-02T01:51:02.224749500-04:00[America/New_York]
파리: 2025-09-02T14:51:02.227749800+02:00[Europe/Paris]
Asia/Seoul

Period와 Duration

  • Period : LocalDate 사이의 차이를 계산할 때 사용
    • 날짜차이 = 며칠, 몇 달, 몇 년 차이 같은 것
  • Duration : LocalDateTime / Instant 등 시간 단위 차이를 계산할 때 사용
    • 시간차이 = 몇 시간, 몇 분, 몇 초 차이
import java.time.LocalDateTime;
import java.time.Duration;
import java.time.Period;

public class ExamLocalApi {
    public static void main(String[] args) {
        // Duration
        LocalDateTime time1 = LocalDateTime.of(2025, 9, 2, 10, 0);
        LocalDateTime time2 = LocalDateTime.of(2025, 9, 2, 15, 30);

        // 2025-09-02 10:00 | 2025-09-02 15:30
        Duration duration = Duration.between(time1, time2);

        System.out.println("총 시간 차이: " + duration.toHours() + "시간");
        System.out.println("총 분 차이: " + duration.toMinutes() + "분");
        System.out.println("총 초 차이: " + duration.toSeconds() + "초");


        // Period
        LocalDate date1 = LocalDate.of(2025, 1, 1);
        LocalDate date2 = LocalDate.of(2025, 9, 2);

        // 2025-01-01 | 2025-09-02
        Period period = Period.between(date1, date2);

        System.out.printf("두 날짜 차이: %d년 %d개월 %d일%n",
                period.getYears(),
                period.getMonths(),
                period.getDays()
        );
    }
}
# 실행 결과
# 2025-09-02 10:00 | 2025-09-02 15:30
총 시간 차이: 5시간
총 분 차이: 330분
총 초 차이: 19800초
# 2025-01-01 | 2025-09-02
두 날짜 차이: 0년 8개월 1일

5. 예외 처리

프로그램 실행 중에 발생할 수 있는 예상치 못한 상황(예외)에 대비하여
프로그램의 정상적인 흐름을 유지하고 예외 상황을 안전하게 처리하는 프로그래밍 기법

  • 프로그램의 안정성과 신뢰성 보장
  • 오류의 조기 발견 및 대응
  • 사용자 경험 개선
  • 시스템 자원의 안전한 관리

Error와 Exception

  • Error = 수습할 수 없는 심각 한 오류
    • 컴파일 에러 : 문법오류, 타입불일치 등
    • 런타임 에러 : 메모리 부족, 0으로 나누기 등
  • Exception = 예외 처리를 통해 수습할 수 있는 덜 심각한 오류
    • 예외 처리 방식은 try-catch , throws 방식이 있음

예외가 발생될 수 있는 코드

배열인덱스, 널포인터, 넘버포맷, 아리스메틱

int[] arr = {1, 2, 3};
System.out.println(arr[5]); // ArrayIndexOutOfBoundsException

String str = null;
System.out.println(str.length()); // NullPointerException

String num = "abc";
int value = Integer.parseInt(num); // NumberFormatException

int a = 10;
int b = 0;
System.out.println(a / b); // ArithmeticException  (0으로나눔)

파일 입출력 (아직 안배움)

import java.io.*;
FileReader fr = new FileReader("없는파일.txt"); 
// FileNotFoundException (checked exception )

try-catch 예외처리

기본 문법

try {
    // 코드...
} catch (Exception e) { // Exception은 최상위 예외 클래스
    // 예외 처리하는 블럭 ...
    // 최소한 코드 한줄 있어야 예외처리 가능
    System.out.println(e);
}
  • Exception: 최상위 요소 예외 클래스
  • Exception 하위 클래스 종류
    • ArrayIndexOutOfBoundsException
    • NullPointerException
    • ArithmeticException
    • NumberFormatException
    • 그 외 ...

예외처리 확인해보기


public class ExamException {
    public static void method1(int[] arr) {
        try {
            System.out.println(arr[5]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Array: " + e);
        } catch (Exception e) {
            System.out.println("Exception:");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        int[] arr1 = new int[5];
        int[] arr2 = null;
        method1(arr1);
        System.out.println("메서드(arr1) 실행 후");
        method1(arr2);
        System.out.println("메서드(arr2) 실행 후");
    }
}
# 실행 결과
Array: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
메서드(arr1) 실행 후
Exception:
메서드(arr2) 실행 후
java.lang.NullPointerException: Cannot load from int array because "arr" is null
    at week_04._0902.ExamException.method1(ExamException.java:10)
    at week_04._0902.ExamException.exam01(ExamException.java:24)
    at week_04._0902.ExamException.main(ExamException.java:5)

e.printStackTrace() : 예외 발생 시 예외 메시지와 함께 호출 스택 정보를 출력해주는 메소드


starweb
@starweb :: starweb 님의 블로그

starweb 님의 블로그 입니다.

공감하셨다면 구독도 환영합니다!

목차