[ 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() : 예외 발생 시 예외 메시지와 함께 호출 스택 정보를 출력해주는 메소드