String literal : String Pool에 저장, 동일한 값을 공유, 메모리 효율성이 높다.
new String("") : 매번 Heap에 새 객체를 생성, 동일한 문자열이더라도 서로 다른 객체로 간주.
String literal ( String str = "hello"; )
new String("") ( String str1 = new String("hello"); )
이와 같이 String literal은 메모리 절약과 성능 이점을 가지며, new String("")은 매번 새로운 객체가 필요할 때 사용됩니다.
String : 불변(immutable) 객체, 값이 변경될 때마다 새로운 객체를 생성
StringBuilder : 가변, thread-safe 하지않고, 내부 값을 직접 수정할 수 있다.
StringBuffer : 가변, thread-safe 하고, 내부 값을 직접 수정할 수 있다.
String
StringBuilder
StringBuffer
Exception : 프로그램에서 발생할 수 있는 예외적인 상황, 일반적으로 프로그램 내에서 처리할 수 있다.
Error : 시스템 환경에서 발생하는 치명적인 오류, 프로그램이 이를 처리하지 않고 종료되는 것이 일반적이다.
Exception
Error
주요 예시로는 IOException, ClassNotFoundException, SQLException, NoSuchMethodException, NullPointerException 등이 있습니다.
IOException : 입출력 작업 중 발생하는 예외입니다. ( 파일을 읽으려 할 때 파일이 존재하지 않으면 FileNotFoundException이 발생 )
import java.io.*;
public class FileNotFoundExceptionExample {
public static void main(String[] args) {
try {
// 없는 파일을 읽으려 시도하여 FileNotFoundException 발생
FileReader fileReader = new FileReader("nonexistentfile.txt");
} catch (FileNotFoundException e) {
System.out.println("FileNotFoundException 발생: 파일을 찾을 수 없습니다. (" + e.getMessage() + ")");
} catch (IOException e) {
System.out.println("IOException 발생: " + e.getMessage());
}
}
}
ClassNotFoundException : 특정 클래스를 로드하려 할 때 해당 클래스가 클래스패스에 없을 경우 발생하는 예외입니다.
SQLException: 데이터베이스와의 통신에서 발생하는 예외로, SQL 문법 오류, 연결 실패, 권한 문제, 잘못된 쿼리 실행 등의 이유로 발생합니다.
import java.sql.*;
public class SQLExceptionExample {
public static void main(String[] args) {
String url = "jdbc:mysql://invalid_host:3306/test";
try {
Connection connection = DriverManager.getConnection(url, "user", "password");
} catch (SQLException e) {
System.out.println("SQLException 발생: " + e.getMessage());
}
}
}
NoSuchMethodException : 호출하려는 메서드가 클래스에 존재하지 않을 때 발생하는 예외입니다.
NullPointerException: null 값을 참조하려 할 때 발생하는 예외입니다. 초기화되지 않은 객체의 메서드 호출, 필드 접근 등에서 발생합니다.
public class NullPointerExceptionExample {
public static void main(String[] args) {
String str = null;
try {
System.out.println(str.length());
} catch (NullPointerException e) {
System.out.println("NullPointerException 발생: " + e.getMessage());
}
}
}
Checked Exception : 컴파일 시점에 예외 처리가 요구되는 예외
Unchecked Exception : 런타임 시에만 발생하며 예외 처리가 강제되지 않는 예외
Checked Exception
Unchecked Exception
throw : 예외를 실제로 발생시키는 데 사용
throws : 메서드가 던질 수 있는 예외를 명시하여 호출하는 코드에서 예외를 처리할 수 있도록 안내.
throw : 예외를 강제로 발생시킬 때 사용합니다. ( 예: throw new IllegalArgumentException("Invalid input") );
throws : 메서드 선언에서 예외가 발생할 가능성을 명시하는 것입니다. throws를 통해 호출자에게 예외 처리가 필요하다는 사실을 알리는 규약 역할 ( 예: public void readFile() throws IOException )
throws가 선언된 메서드를 호출하는 쪽에서는 해당 예외를 처리해야 합니다. throws를 통해 예외를 상위로 넘기면, 최종적으로 예외가 발생하는 곳에서만 하나의 try-catch로 묶어서 예외를 처리할 수 있습니다. 모든 메서드에서 개별적으로 처리하는 것이 아니고, 예외를 발생한 곳에서만 처리할 수 있어 불필요한 코드를 줄 일 수 있습니다.
finally : 예외 발생 여부와 관계없이 항상 실행. 주로 자원 해제나 마무리 작업(예: 파일 닫기, 데이터베이스 연결 종료 등)을 위해 사용.
finally 블록은 예외가 발생하든 하지 않든 무조건 실행됩니다. 예외가 발생하여 catch 블록이 실행된 경우에도, 예외가 발생하지 않아 catch를 건너뛸 때도 finally는 실행됩니다.
주로 파일, 데이터베이스 연결 등 외부 자원을 해제하거나, 마무리 작업을 수행할 때 사용됩니다. 항상 실행되므로 중요한 정리 작업을 안전하게 처리할 수 있습니다.
Throwable : Java 예외 계층 구조의 최상위 클래스로, 모든 예외와 오류를 포함.
Exception : Throwable의 하위 클래스 중 하나로, 주로 프로그램 내에서 발생하는 예외적 상황을 나타냅니다.
Throwable: 모든 에러와 예외의 최상위 클래스입니다. Java에서 예외 처리의 시작점이 되는 클래스이며, Throwable을 상속받는 클래스만이 throw 키워드로 던질 수 있습니다.
모든 예외와 오류를 포괄하기 때문에, 구체적인 예외나 오류보다는 전체적인 예외 처리 흐름을 다룰 때 사용됩니다.
Exception: Throwable의 하위 클래스 중 하나로, 프로그램 내에서 발생할 수 있는 예외적인 상황을 나타냅니다. 주로 프로그램의 로직과 관련된 예외를 처리합니다.
제네릭(Generic) : 타입을 매개변수로 사용하여 코드의 타입 안전성과 재사용성을 높여주는 기능
제네릭은 Java에서 클래스나 메서드에 사용할 데이터 타입을 파라미터로 명시할 수 있는 기능입니다.
List<Integer>
와 List<String>
모두 같은 List 클래스를 사용하여 타입만 다르게 적용할 수 있습니다.주문 관리 API를 개발하면서 제네릭을 활용하여 타입 안전성과 코드의 재사용성을 높이는 방식으로 설계하였습니다.
타입 안정성을 높이기 위한 제네릭 활용 : 제네릭을 사용함으로써 컴파일 시점에 타입을 검사하여 안전한 코드를 작성할 수 있었습니다. 예를 들어, ResponseEntity<OrderResponseDto>
와 같이 ResponseEntity의 타입 파라미터로 DTO 객체를 지정하여, API 응답이 항상 OrderResponseDto 타입으로 리턴됨을 보장했습니다. 이를 통해 잘못된 타입으로 인한 런타임 오류 가능성을 미리 방지할 수 있었습니다.
재사용성 향상 : List<OrderResponseDto>
와 같은 제네릭 리스트 타입을 사용하여 특정 데이터 타입을 반복적으로 작성할 필요 없이 코드의 재사용성을 높였습니다. 이를 통해 주문 관련 DTO 리스트를 일관된 타입으로 처리할 수 있어 코드 중복을 줄였고, 코드 유지보수가 용이해졌습니다.