throw new IllegalArgumentException("미성년자는 접근할 수 없습니다!");

try {
exceptionPractice.callUncheckedException();
} catch (RuntimeException e) { // 예외처리
System.out.println("언체크 예외 처리");
} catch (Exception e) {
System.out.println("체크 예외 처리");
}
public class ExceptionPractice {
public void callCheckedException() throws Exception { // ✅ throws 예외를 상위로 전파
if (true) {
System.out.println("체크예외 발생");
throw new Exception();
}
}
}
public class Main {
public static void main(String[] args) {
// 예외 실습 객체 인스턴스화
ExceptionPractice exceptionPractice = new ExceptionPractice();
// 체크 예외 사용
// ✅ 반드시 상위 메서드에서 try-catch 를 활용해 주어야합니다.
try {
exceptionPractice.callCheckedException();
} catch (Exception e) {
System.out.println("예외처리");
}
}
}
if(class!=null)
Optional객체를 메서드 반환 자료형에 선언해서 해당 메서드가 null이 반환될 가능성을 명확하게 전달할 수 있다.
Optional.ofNullalbe()을 사용하여 null이 반환 될 수 있는 객체를 감싼다.
활용할 때는 isPresent()와 같은 Optional API를 통해 안전하게 null처리를 할 수 있다.
isPresent() 활용 방법
Optional 내부의 값이 존재할 경우 true를 반환하고
내부 값이 null일 경우 false를 반환한다.
import java.util.Optional;
public class Camp {
private Student student;
// ✅ null 이 반환될 수 있음을 명확하게 표시
public Optional<Student> getStudent() {
return Optional.ofNullable(student);
}
}
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Camp camp = new Camp();
// Optional 객체 반환받음
// Optional값을 반환 받음으로 널이 반환 될 수도 있는 값이라는 것을 알려줌
Optional<Student> studentOptional = camp.getStudent();
// Optional 객체의 기능 활용
boolean flag = studentOptional.isPresent(); // false 반환
if (flag) {
// 존재할 경우
Student student = studentOptional.get(); // ✅ 안전하게 Student 객체 가져오기
String studentName = student.getName();
System.out.println("studentName = " + studentName);
} else {
// null 일 경우
System.out.println("학생이 없습니다.");
}
}
}
import java.util.Optional;
public class Camp {
private Student student;
// ✅ null 이 반환될 수 있음을 명확하게 표시
public Optional<Student> getStudent() {
return Optional.ofNullable(student);
}
}
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Camp camp = new Camp();
// ✅ Optional 객체의 기능 활용 (orElseGet 사용)
Student student = camp.getStudent()
.orElseGet(() -> new Student("미등록 학생"));
System.out.println("studentName = " + student.getName());
}
}

int[] numbers = new int[2];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30; // ❌ 요소 추가시 에러발생
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30); // ✅ 정상 동작 (길이 제한 없음)

public class Box {
private Integer item; // ⚠️ Integer 타입으로 고정
public Box(Integer item) { // ⚠️ Integer 타입으로 고정
this.item = item;
}
public Integer getItem() {
return this.item;
}
}
public class Main {
public static void main(String[] args) {
// ✅ Integer 타입 박스
Box box1 = new Box(100);
// ❌ String 타입을 저장하려면 새로운 클래스를 만들어야 함
Box box2 = new Box("ABC");
}
}
public class ObjectBox {
private Object item; // ⚠️ 다형성: 모든 타입 저장 가능 (하지만 안전하지 않음)
public ObjectBox(Object item) {
this.item = item;
}
public Object getItem() {
return this.item;
}
}
public class Main {
public static void main(String[] args) {
// ✅ ObjectBox 사용
ObjectBox objBox = new ObjectBox("Hello");
String str = (String) objBox.getItem(); // 형변환 필요
System.out.println("objBox 내용: " + str); // Hello
// ⚠️ 실행 중 오류 발생 (잘못된 다운 캐스팅: ClassCastException)
objBox = new ObjectBox(100); // 정수 저장
String error = (String) objBox.getItem(); // ❌ 오류: Integer -> String
System.out.println("잘못된 변환: " + error);
}
}
public class GenericBox<T> { // ✅ 제네릭 클래스
private T item;
public GenericBox(T item) {
this.item = item;
}
public T getItem() {
return this.item;
}
}
public class Main {
public static void main(String[] args) {
// 1. ✅ 재사용 가능(컴파일시 타입소거: T -> Object)
GenericBox<String> strGBox = new GenericBox<>("ABC");
GenericBox<Integer> intGBox = new GenericBox<>(100);
GenericBox<Double> doubleGBox = new GenericBox<>(0.1);
// 2. ✅ 타입 안정성 보장(컴파일시 타입소거: 자동으로 다운캐스팅)
String strGBoxItem = strGBox.getItem();
Integer intGBoxItem = intGBox.getItem();
Double doubleGBoxItem = doubleGBox.getItem();
System.out.println("strGBoxItem = " + strGBoxItem);
System.out.println("intGBoxItem = " + intGBoxItem);
System.out.println("doubleGBoxItem = " + doubleGBoxItem);
}
}
public class GenericBox<T> {
private T item;
public GenericBox(T item) {
this.item = item;
}
public T getItem() {
return this.item;
}
// ⚠️ 일반 메서드 T item 는 클래스의 <T> 를 따라간다.
public void printItem(T item) {
System.out.println(item);
}
// ✅ 제네릭 메서드 <S> 는 <T> 와 별개로 독립적이다.
public <S> void printBoxItem(S item) {
System.out.println(item);
}
}
public class Main {
public static void main(String[] args) {
GenericBox<String> strGBox = new GenericBox<>("ABC");
GenericBox<Integer> intGBox = new GenericBox<>(100);
// ⚠️ 일반메서드: 클래스 타입 매개변수를 따라갑니다.
// String 데이터 타입 기반으로 타입소거가 발생.
// String 타입의 다운캐스팅 코드 삽입!
strGBox.printItem("ABC"); // ✅ String 만 사용가능
strGBox.printItem(100); // ❌ 에러 발생
// ✅ 제네릭 메서드: 독립적인 타입 매개변수를 가집니다.
// String 타입 정보가 제네릭 메서드에 아무런 영향을 주지 못함.
// 다운캐스팅 코드 삽입되지 않음.
strGBox.printBoxItem("ABC"); //✅ 모든 데이터 타입 활용 가능
strGBox.printBoxItem(100); //✅ 모든 데이터 타입 활용 가능
strGBox.printBoxItem(0.1); //✅ 모든 데이터 타입 활용 가능
}
}
public interface Calculator {
int sum(int a, int b);
}
public class Main {
public static void main(String[] args) {
// ✅ 익명 클래스 활용
Calculator calculator1 = new Calculator() {
@Override
public int sum(int a, int b) {
return a + b;
}
};
int ret1 = calculator1.sum(1, 1);
System.out.println("ret1 = " + ret1);
}
}
// 람다 표현식
Calculator calculator1 = (a, b) -> a + b;
// 익명클래스
Calculator calculator1 = new Calculator() {
@Override
public int sum(int a, int b) {
return a + b;
}
};
@FunctionalInterface // ✅ 함수형 인터페이스 선언
public interface Calculator {
int sum(int a, int b); // ✅ 오직 하나의 추상 메서드만 선언해야합니다.
}
public class Main {
public static void main(String[] args) {
...
// ✅ 람다식 활용
Calculator calculator2 = (a, b) -> a + b;
int ret2 = calculator2.sum(2, 2);
System.out.println("ret2 = " + ret2);
}
}
public class Main {
public static int calculate(int a, int b, Calculator calculator) {
return calculator.sum(a, b);
}
public static void main(String[] args) {
// ✅ 람다식을 직접 매개변수로 전달
int ret5 = calculate(5, 5, (a, b) -> a + b);
System.out.println("ret5 = " + ret5); // 출력: ret5 = 10
}
}
public class Main {
public static void main(String[] args) {
// ArrayList 선언
List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// ✅ for 명령형 스타일
List<Integer> ret1 = new ArrayList<>();
for (Integer num : arrayList) {
int multipliedNum = num * 10; // 각 요소 * 10
ret1.add(multipliedNum);
}
// ✅ 스트림 선언적 스타일
List<Integer> ret2 = arrayList
.stream()
.map(num -> num * 10)
.collect(Collectors.toList());
// 출력
System.out.println("ret1 = " + ret1);
System.out.println("ret2 = " + ret2);
}
}

arrayList
.stream() // 데이터 준비
.map() // 중간 연산 등록
.collect() // 최종 연산
// 1. 데이터 준비: 스트림 생성
Stream<Integer> stream = arrayList.stream();
// 2. 중간 연산 등록: 각 요소를 10배로 변환 로직 등록
Stream<Integer> mappedStream = stream.map(num->num*10);
// 3. 최종 연산: 최종 결과 리스트로 변환
List<Integer> ret2 = mappedStream.collect(Collectors.toList());
// ✅ 한 줄로 표현 가능
List<Integer> ret2 = arrayList.stream() // 1. 데이터 준비
.map(num -> num * 10) // 2. 중간 연산 등록
.collect(Collectors.toList()); // 3. 최종 연산
List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// ✅ filter() + map() 사용 예제
List<Integer> ret6 = arrayList.stream() // 1. 데이터 준비: 스트림 생성
.filter(num -> num % 2 == 0) // 2. 중간 연산: 짝수만 필터링
.map(num -> num * 10) // 3. 중간 연산: 10배로 변환
.collect(Collectors.toList()); // 4. 최종 연산: 리스트로 변환
System.out.println(ret6); // 출력: [20, 40]
// For 문 예시
List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
List<Integer> ret6 = new ArrayList<>();
for (int num : arrayList) {
int remain = num % 2;
if (remain == 0) {
int data = num * 10;
ret6.add(data);
}
}
// 5. 결과 출력
System.out.println(ret6); // 출력: [20, 40]
// ✅ Thread 클래스 상속으로 쓰레드 구현
public class MyThread extends Thread {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("::: " + threadName + "쓰레드 시작 :::");
for (int i = 0; i < 10; i++) {
System.out.println("현재 쓰레드: " + threadName + " - " + i);
try {
Thread.sleep(500); // 딜레이 0.5 초
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("::: " + threadName + "쓰레드 종료 :::");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("::: main 쓰레드 시작");
MyThread thread0 = new MyThread();
MyThread thread1 = new MyThread();
// 1. thread0 실행
System.out.println("::: main 이 thread0 을 실행");
thread0.start();
// 2. thread1 실행
System.out.println("::: main 이 thread1 을 실행");
thread1.start();
System.out.println("::: main 쓰레드 종료");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("::: main 쓰레드 시작");
MyThread thread0 = new MyThread();
MyThread thread1 = new MyThread();
// 시작시간 기록
long startTime = System.currentTimeMillis();
// 1. thread0 시작
System.out.println("thread0 시작");
thread0.start();
// 2. thread1 시작
System.out.println("thread1 시작");
thread1.start();
// ⌛️ main 쓰레드 대기 시키기
try {
thread0.join();
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("총 작업 시간: " + totalTime + "ms");
System.out.println("::: main 쓰레드 종료");
}
}
// 구현체를 Thread로 상속받지 않고
public class MyRunnable extends Thread {
// Runnalbe로 구현한다.
public class MyRunnable implements Runnable {
public class Main {
public static void main(String[] args) {
MyRunnable task = new MyRunnable(); // ✅ 하나의 작업 객체 선언
// ✅ 하나의 작업을 여러 쓰레드에서 공유
Thread thread0 = new Thread(task); // 작업 객체 공유
Thread thread1 = new Thread(task); // 작업 객체 공유
// 실행
thread0.start();
thread1.start();
}
}
public class MyThread extends Thread, MyNewClass{ // ❌ 다중 상속 불가
public class MyRunnable extends MyNewClass implements Runnable { // ✅ 다중 상속