Java에 대하여 - 3

SUM·2025년 1월 9일

Java

목록 보기
3/5

📌 문자열

(1) String literal

  • 생성 방식:
    • 문자열 리터럴은 String Pool이라는 메모리 영역에 저장됩니다.
    • 같은 내용의 문자열 리터럴이 이미 String Pool에 존재하면, 기존 객체의 참조를 반환합니다. 새로운 객체를 생성하지 않습니다.
    • 예:
      String str1 = "hello";
      String str2 = "hello";
      System.out.println(str1 == str2); // true (같은 객체를 참조)
  • 장점:
    • 메모리 효율적: 동일한 값의 문자열을 여러 번 생성해도 새로운 객체를 만들지 않으므로 메모리를 절약할 수 있습니다.
    • 빠른 비교: ==로 참조를 비교하면 String Pool 내 동일한 객체를 가리키기 때문에 빠릅니다.

(2) new String("")

  • 생성 방식:
    • new String("")은 힙(Heap) 영역에 새로운 String 객체를 생성합니다.
    • 이 과정에서 항상 새로운 객체를 생성합니다. String Pool을 확인하지 않습니다.
    • 예:
      String str1 = new String("hello");
      String str2 = new String("hello");
      System.out.println(str1 == str2); // false (다른 객체를 참조)
  • 단점:
    • 불필요한 객체 생성으로 메모리 낭비가 발생할 수 있습니다.
    • 객체 비교 시 ==를 사용할 경우 예상치 못한 결과를 초래할 수 있습니다. (값 비교는 equals()를 사용해야 합니다.)

(3) String literal과 new String("")의 비교

특징String Literalnew String("")
저장 위치String PoolHeap
객체 생성동일 내용이면 재사용항상 새로운 객체 생성
메모리 사용효율적비효율적
== 비교 결과true (같은 객체)false (다른 객체)

(4) String, StringBuilder, StringBuffer의 차이

String, StringBuilder, StringBuffer의 차이는 가변성, 스레드 안전성, 성능에서 크게 구분됩니다. 아래에서 각각의 특성과 차이를 정리하겠습니다.


1. String

  • 특징:

    • 불변 객체 (Immutable):
      • String 객체는 생성 이후 내용을 변경할 수 없습니다.
      • 문자열을 수정(추가, 삭제 등)하면 새로운 String 객체가 생성됩니다.
    • 저장 위치:
      • String Pool 또는 힙 메모리에 저장됩니다.
      • 동일한 리터럴 값은 String Pool에서 재사용됩니다.
  • 성능:

    • 문자열이 자주 변경되면 새로운 객체가 생성되어 성능과 메모리 효율이 떨어질 수 있습니다.
  • 스레드 안전성:

    • 스레드 안전하지 않습니다.
  • 사용 예:

    String s1 = "Hello";
    String s2 = s1 + " World"; // 새로운 객체 생성
    System.out.println(s2); // Hello World

2. StringBuilder

  • 특징:

    • 가변 객체 (Mutable):
      • 문자열을 수정(추가, 삭제 등)해도 동일한 객체를 사용합니다.
    • 스레드 비안전:
      • 동기화 처리가 없으므로 다중 스레드 환경에서는 안전하지 않습니다.
  • 성능:

    • 단일 스레드 환경에서 가장 빠른 성능을 제공합니다.
  • 사용 예:

    StringBuilder sb = new StringBuilder("Hello");
    sb.append(" World"); // 같은 객체에서 수정
    System.out.println(sb.toString()); // Hello World

3. StringBuffer

  • 특징:

    • 가변 객체 (Mutable):
      • StringBuilder와 동일하게 동일 객체 내에서 문자열을 수정할 수 있습니다.
    • 스레드 안전:
      • 동기화를 지원하여 다중 스레드 환경에서도 안전하게 사용할 수 있습니다.
      • 하지만 동기화로 인해 StringBuilder보다 성능이 느립니다.
  • 성능:

    • 스레드 안전성을 위해 동기화 비용이 추가됩니다.
  • 사용 예:

    StringBuffer sb = new StringBuffer("Hello");
    sb.append(" World"); // 같은 객체에서 수정
    System.out.println(sb.toString()); // Hello World

4. 비교 표

특징StringStringBuilderStringBuffer
가변성불변 (Immutable)가변 (Mutable)가변 (Mutable)
스레드 안전성스레드 안전하지 않음스레드 안전하지 않음스레드 안전
성능느림 (새 객체 생성)빠름 (단일 스레드 환경)비교적 느림 (동기화)
사용 환경읽기 전용, 간단 작업단일 스레드 작업멀티스레드 작업

5. 사용 추천

  1. String:
    • 문자열이 거의 변경되지 않는 경우.
    • 간단한 문자열 작업.
  2. StringBuilder:
    • 단일 스레드 환경에서 문자열을 자주 수정하는 경우.
    • 성능이 중요한 경우.
  3. StringBuffer:
    • 멀티스레드 환경에서 문자열을 안전하게 수정해야 하는 경우.

6. 예제 비교

public class StringExample {
    public static void main(String[] args) {
        // String (Immutable)
        String str = "Hello";
        str += " World"; // 새로운 객체 생성
        System.out.println(str); // Hello World

        // StringBuilder (Mutable, Not Thread-safe)
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(" World"); // 같은 객체 내에서 수정
        System.out.println(sb); // Hello World

        // StringBuffer (Mutable, Thread-safe)
        StringBuffer sbf = new StringBuffer("Hello");
        sbf.append(" World"); // 같은 객체 내에서 수정
        System.out.println(sbf); // Hello World
    }
}

이 차이를 이해하면 성능과 메모리 사용을 최적화하면서 적절한 도구를 선택할 수 있습니다.


📌 예외, 제네릭

(1) Exception

  • 정의:

    • Exception은 프로그램에서 예외적인 상황을 나타내는 객체입니다.
    • 개발자가 예상 가능하고, 적절히 처리할 수 있는 문제를 나타냅니다.
  • 특징:

    • java.lang.Exception을 상속합니다.
    • 대부분의 Exception은 런타임에 발생하며, 프로그램의 정상적인 흐름에서 벗어난 경우에 발생합니다.
    • Exception은 checked exceptionunchecked exception으로 나뉩니다.
      • Checked Exception: 컴파일 시점에 반드시 처리해야 하는 예외 (예: IOException, SQLException).
      • Unchecked Exception: 런타임에 발생하며 처리 강제가 없는 예외 (예: NullPointerException, ArrayIndexOutOfBoundsException).
  • :

    try {
        int result = 10 / 0; // ArithmeticException 발생
    } catch (ArithmeticException e) {
        System.out.println("예외 발생: " + e.getMessage());
    }
  • 처리 가능:

    • try-catch 블록으로 예외를 처리하거나 throws 키워드를 사용해 호출자에게 전달할 수 있습니다.

(2) Exception Class

1. Exception 클래스란?

  • 정의:

    • Java의 표준 라이브러리인 java.lang.Exception 클래스는 Throwable 클래스를 직접 상속합니다.
    • 프로그램 실행 중 예상 가능한 문제 상황(예: 파일 없음, 데이터베이스 연결 실패 등)을 나타냅니다.
    • Checked Exception의 루트 클래스입니다. 즉, 대부분의 하위 클래스는 컴파일 시점에 예외 처리가 강제됩니다.
  • 역할:

    • 예외가 발생했을 때, 프로그램이 비정상 종료되지 않도록 처리 로직을 작성할 수 있게 도와줍니다.
    • 사용자 정의 예외(Custom Exception) 생성 시 기본 클래스로 사용할 수 있습니다.

2. Exception 클래스의 계층 구조

Java의 Throwable 클래스 아래에 두 가지 주요 계층이 있습니다:
1. Error: 시스템 수준의 치명적인 문제를 나타냄.
2. Exception: 애플리케이션 수준에서 처리 가능한 문제를 나타냄.

3. Exception 클래스 예제

1. IOException

  • 파일 입출력에서 문제가 발생할 때 던져지는 예외.

  • 예:

    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class IOExceptionExample {
        public static void main(String[] args) {
            try {
                File file = new File("nonexistent.txt");
                FileReader fr = new FileReader(file); // IOException 발생
            } catch (IOException e) {
                System.out.println("파일을 찾을 수 없습니다: " + e.getMessage());
            }
        }
    }

2. SQLException

  • 데이터베이스 작업 중 SQL 문법 오류 또는 연결 실패 시 발생.

  • 예:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    public class SQLExceptionExample {
        public static void main(String[] args) {
            try {
                Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "user", "pass");
            } catch (SQLException e) {
                System.out.println("데이터베이스 연결 실패: " + e.getMessage());
            }
        }
    }

3. ClassNotFoundException

  • 특정 클래스가 로드되지 않았을 때 발생.
  • 예:
    public class ClassNotFoundExceptionExample {
        public static void main(String[] args) {
            try {
                Class.forName("com.nonexistent.MyClass"); // ClassNotFoundException 발생
            } catch (ClassNotFoundException e) {
                System.out.println("클래스를 찾을 수 없습니다: " + e.getMessage());
            }
        }
    }

4. NullPointerException (Unchecked Exception)

  • null 객체를 참조할 때 발생.
  • 예:
    public class NullPointerExceptionExample {
        public static void main(String[] args) {
            String str = null;
            System.out.println(str.length()); // NullPointerException 발생
        }
    }

5. ArithmeticException (Unchecked Exception)

  • 수학적인 오류가 발생할 때 (예: 0으로 나눔).
  • 예:
    public class ArithmeticExceptionExample {
        public static void main(String[] args) {
            try {
                int result = 10 / 0; // ArithmeticException 발생
            } catch (ArithmeticException e) {
                System.out.println("수학 오류 발생: " + e.getMessage());
            }
        }
    }

(3) Checked Exception vs Unchecked Exception

  • Checked Exception:

    • 컴파일 시점에 반드시 처리해야 하는 예외.
    • 예: IOException, SQLException, ClassNotFoundException.
    • 처리하지 않으면 컴파일 에러 발생.
  • Unchecked Exception (RuntimeException):

    • 런타임에 발생하며, 처리 강제가 없음.
    • 예: NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException.
    • 예외 처리 없이 실행 가능하지만, 런타임 시 프로그램이 종료될 수 있음.

(4) Error

  • 정의:

    • Error는 프로그램 실행 중 발생하는 심각한 시스템 레벨의 문제를 나타냅니다.
    • 예상하거나 복구할 수 없는 문제를 의미합니다.
  • 특징:

    • java.lang.Error를 상속합니다.
    • 주로 JVM(Java Virtual Machine) 또는 하드웨어 환경에서 발생하는 문제입니다.
    • 대부분의 경우 프로그램이 종료되며, 개발자가 직접 처리하거나 복구할 수 없습니다.
  • :

    • OutOfMemoryError: 메모리가 부족할 때 발생.
    • StackOverflowError: 무한 재귀 호출 등으로 스택이 초과될 때 발생.
    • VirtualMachineError: JVM 관련 심각한 문제가 발생할 때.
  • :

    public static void main(String[] args) {
        main(args); // StackOverflowError 발생
    }
  • 처리 불가능:

    • 일반적으로 처리하지 않습니다. Error는 치명적인 시스템 문제를 나타내므로 수정은 원인 제거를 통해 이루어져야 합니다.

Exception과 Error의 차이

특징ExceptionError
상속 계층java.lang.Exceptionjava.lang.Error
처리 가능성처리 가능 (예: try-catch 또는 throws 키워드 사용)대부분 처리 불가능
발생 원인코드 수준의 문제 (예: 잘못된 입력, 파일 미존재 등)시스템 수준의 문제 (예: 메모리 부족, JVM 충돌 등)
복구 가능성복구 가능복구 불가능
예시IOException, NullPointerExceptionOutOfMemoryError, StackOverflowError
컴파일 강제 여부Checked Exception은 반드시 처리해야 함Error는 처리 강제가 없음

(5) throw, throws

throwthrows는 Java에서 예외 처리와 관련된 키워드이지만, 사용하는 목적과 위치가 다릅니다. 아래에서 각각의 의미와 차이점을 정리하겠습니다.


1. throw

  • 정의:

    • 특정 예외를 발생시키는 데 사용됩니다.
    • 메서드 내부에서 사용되며, 예외 객체를 생성하여 던집니다.
  • 사용법:

    • throw new Exception();처럼, 예외 객체를 명시적으로 생성한 후 던질 수 있습니다.
    • 런타임 예외(RuntimeException)뿐만 아니라 체크 예외도 던질 수 있습니다.
  • 예제:

    public class ThrowExample {
        public static void validateAge(int age) {
            if (age < 18) {
                throw new IllegalArgumentException("나이는 18 이상이어야 합니다."); // 예외 발생
            }
            System.out.println("나이가 유효합니다.");
        }
    
        public static void main(String[] args) {
            validateAge(16); // IllegalArgumentException 발생
        }
    }
  • 특징:

    • 예외를 발생시키는 키워드.
    • 예외가 발생하면 프로그램 실행 흐름이 중단되고, 예외 처리가 이루어지지 않으면 프로그램이 종료됩니다.

2. throws

  • 정의:

    • 메서드 선언부에서 사용되며, 해당 메서드가 호출될 때 발생할 가능성이 있는 예외를 명시합니다.
    • 호출한 메서드에서 예외를 처리하거나, 다시 던져야 합니다.
  • 사용법:

    • 메서드 선언부에서 throws 뒤에 예외 클래스를 나열합니다.
    • 체크 예외(Checked Exception)는 반드시 throws를 사용해 명시해야 합니다.
  • 예제:

    import java.io.IOException;
    
    public class ThrowsExample {
        public static void readFile() throws IOException {
            throw new IOException("파일을 읽을 수 없습니다."); // IOException 던짐
        }
    
        public static void main(String[] args) {
            try {
                readFile(); // 호출된 메서드에서 예외 처리
            } catch (IOException e) {
                System.out.println("예외 처리: " + e.getMessage());
            }
        }
    }
  • 특징:

    • 메서드가 어떤 예외를 던질 수 있는지 선언적으로 표시.
    • 호출하는 쪽에서 예외를 처리하도록 강제.

3. 차이점

특징throwthrows
목적예외를 발생시키기 위해 사용메서드가 던질 수 있는 예외를 선언
위치메서드 내부메서드 선언부
사용 대상예외 객체예외 클래스 이름
처리 강제 여부발생한 순간 예외 처리가 필요호출한 메서드에서 예외 처리 또는 다시 던짐
예제throw new IOException("에러");public void method() throws IOException {}

(6) try~catch~finally

try-catch-finally는 Java에서 예외를 처리하기 위한 구조입니다. 예외가 발생할 수 있는 코드를 감싸고, 예외 처리 및 리소스 정리를 체계적으로 수행할 수 있도록 합니다.


1. 구조

기본 문법

try {
    // 예외가 발생할 가능성이 있는 코드
} catch (ExceptionType1 e1) {
    // ExceptionType1을 처리하는 코드
} catch (ExceptionType2 e2) {
    // ExceptionType2를 처리하는 코드
} finally {
    // 예외 발생 여부와 상관없이 항상 실행되는 코드
}

2. 각 키워드의 역할

1. try

  • 역할:
    • 예외가 발생할 가능성이 있는 코드를 작성합니다.
    • 예외가 발생하면 catch 블록으로 제어가 넘어갑니다.
  • 특징:
    • 반드시 하나 이상의 catch 또는 finally 블록과 함께 사용해야 합니다.
  • :
    try {
        int result = 10 / 0; // ArithmeticException 발생
    } catch (ArithmeticException e) {
        System.out.println("예외 발생: " + e.getMessage());
    }

2. catch

  • 역할:
    • try 블록에서 발생한 특정 예외를 처리합니다.
    • 예외의 타입별로 여러 개의 catch 블록을 작성할 수 있습니다.
  • 특징:
    • 예외를 잡아내지 못하면 프로그램이 종료됩니다.
    • 다중 catch 블록을 사용할 경우, 더 구체적인 예외 타입을 먼저 작성해야 합니다.
  • :
    try {
        String str = null;
        System.out.println(str.length()); // NullPointerException 발생
    } catch (NullPointerException e) {
        System.out.println("NullPointerException 처리");
    } catch (Exception e) {
        System.out.println("기타 예외 처리");
    }

3. finally

  • 역할:
    • 예외 발생 여부와 관계없이 항상 실행되는 코드 블록입니다.
    • 주로 리소스 정리(예: 파일 닫기, 데이터베이스 연결 해제 등)에 사용됩니다.
  • 특징:
    • try와 함께 반드시 사용할 필요는 없지만, 예외 발생 여부와 관계없이 실행되어야 하는 코드는 여기에 작성합니다.
  • :
    try {
        int[] arr = {1, 2, 3};
        System.out.println(arr[5]); // ArrayIndexOutOfBoundsException 발생
    } catch (Exception e) {
        System.out.println("예외 처리: " + e.getMessage());
    } finally {
        System.out.println("리소스 정리 수행");
    }

3. 예제: try-catch-finally 동작

public class TryCatchFinallyExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; // ArithmeticException 발생
            System.out.println("결과: " + result); // 실행되지 않음
        } catch (ArithmeticException e) {
            System.out.println("예외 발생: " + e.getMessage());
        } finally {
            System.out.println("리소스 정리: finally 블록 실행");
        }
    }
}

실행 결과:

예외 발생: / by zero
리소스 정리: finally 블록 실행

4. 주요 특징

  1. catchfinally의 선택:
    • catch는 예외를 처리하고, finally는 예외 처리와 상관없이 항상 실행됩니다.
  2. finally의 생략 가능성:
    • catch만으로도 예외 처리가 가능하지만, 리소스 정리가 필요하다면 finally를 추가로 사용해야 합니다.

5. 예외 발생 시 흐름

  1. try 블록에서 예외 발생:
    • 발생한 예외가 가장 먼저 해당되는 catch 블록에서 처리됩니다.
  2. finally 블록:
    • 예외 발생 여부와 관계없이 실행됩니다.
  3. catch에서 예외가 처리되지 않으면:
    • 프로그램이 종료됩니다.

6. 예외가 발생하지 않을 때

  • try 블록이 정상적으로 실행되고, catch 블록은 건너뛰어집니다.
  • finally 블록은 항상 실행됩니다.
public class NoExceptionExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 2;
            System.out.println("결과: " + result);
        } catch (Exception e) {
            System.out.println("예외 발생: " + e.getMessage());
        } finally {
            System.out.println("리소스 정리: finally 블록 실행");
        }
    }
}

실행 결과:

결과: 5
리소스 정리: finally 블록 실행

7. 주의점

  • finally에서 예외를 다시 던지거나, 프로그램 흐름을 조작하면 정상적인 예외 처리 흐름이 깨질 수 있으므로 주의가 필요합니다.
  • 예외가 발생하지 않더라도 항상 리소스를 정리해야 하는 경우 finally 블록을 사용하는 것이 권장됩니다.

(7) Throwable

Throwable은 Java에서 모든 예외(Exception)오류(Error)의 최상위 클래스입니다. java.lang.Throwable 클래스는 Java의 예외 처리 메커니즘의 근간을 이루며, ErrorException 클래스가 이를 상속합니다.


1. Throwable의 정의

  • 위치: java.lang.Throwable
  • 역할: Java에서 발생할 수 있는 모든 예외와 오류를 나타내는 최상위 클래스.
  • 주요 서브클래스:
    • Error: 시스템 레벨에서 발생하는 치명적인 오류 (예: 메모리 부족, 스택 오버플로우).
    • Exception: 프로그램 실행 중 예외적인 상황을 나타냄 (예: 파일 없음, 잘못된 입력).
Throwable
├── Exception
│   ├── RuntimeException
│   │   ├── NullPointerException
│   │   ├── ArithmeticException
│   │   └── IndexOutOfBoundsException
│   └── IOException
│       ├── FileNotFoundException
│       └── EOFException
└── Error
    ├── OutOfMemoryError
    ├── StackOverflowError
    └── VirtualMachineError

2. 주요 메서드

1. getMessage()

  • 예외나 오류의 상세 메시지를 반환.
  • 예:
    try {
        int result = 10 / 0;
    } catch (ArithmeticException e) {
        System.out.println(e.getMessage()); // "/ by zero"
    }

2. printStackTrace()

  • 예외가 발생한 위치와 스택 트레이스를 출력.
  • 디버깅 시 유용.
  • 예:
    try {
        int result = 10 / 0;
    } catch (ArithmeticException e) {
        e.printStackTrace();
    }

3. toString()

  • 예외의 클래스 이름과 메시지를 문자열로 반환.
  • 예:
    try {
        String str = null;
        str.length();
    } catch (NullPointerException e) {
        System.out.println(e.toString()); // "java.lang.NullPointerException"
    }

4. getCause()

  • 예외의 원인(다른 예외)을 반환. 연쇄 예외(Chained Exception) 처리에 유용.
  • 예:
    try {
        throw new IllegalArgumentException("잘못된 인자", new NullPointerException("null 값"));
    } catch (IllegalArgumentException e) {
        System.out.println(e.getCause()); // java.lang.NullPointerException: null 값
    }

5. addSuppressed(Throwable)

  • 억압된 예외를 추가. 주로 try-with-resources에서 발생하는 추가 예외를 관리할 때 사용.
  • 예:
    try {
        throw new Exception("Main Exception");
    } catch (Exception e) {
        e.addSuppressed(new Exception("Suppressed Exception"));
        e.printStackTrace();
    }

3. Throwable의 주요 서브클래스

1. Exception

  • 애플리케이션 수준의 예외를 나타냅니다.
  • 프로그램 실행 중 예외적인 상황을 나타내며, 대부분 처리 가능합니다.
  • 예:
    • IOException: 파일 입출력 예외.
    • SQLException: 데이터베이스 예외.

2. Error

  • 시스템 수준에서 발생하는 치명적인 오류를 나타냅니다.
  • 일반적으로 복구가 불가능하며, 프로그램이 종료됩니다.
  • 예:
    • OutOfMemoryError: 메모리 부족 오류.
    • StackOverflowError: 스택 메모리 초과 오류.

4. Throwable의 계층 구조

Object
└── Throwable
    ├── Error (치명적인 시스템 오류)
    │   ├── OutOfMemoryError
    │   ├── StackOverflowError
    │   └── VirtualMachineError
    └── Exception (프로그램 예외)
        ├── RuntimeException (Unchecked Exception)
        │   ├── NullPointerException
        │   ├── ArithmeticException
        │   └── IndexOutOfBoundsException
        └── Checked Exception
            ├── IOException
            └── SQLException

5. 주요 특징

특징Throwable
상위 클래스Object
서브클래스Error, Exception
역할예외와 오류를 모두 표현
사용 목적예외 처리와 디버깅 지원
주요 메서드getMessage(), printStackTrace(), getCause()

6. 예제: Throwable 사용

public class ThrowableExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; // 예외 발생
        } catch (Throwable t) { // Exception과 Error 모두 처리 가능
            System.out.println("Throwable로 예외 처리: " + t.getMessage());
            t.printStackTrace();
        }
    }
}

7. 요약

  1. Throwable은 모든 예외와 오류의 최상위 클래스입니다.
  2. 두 주요 서브클래스:
    • Exception: 예외적인 상황으로 복구 가능.
    • Error: 치명적인 시스템 오류로 복구 불가능.
  3. 디버깅과 예외 처리를 돕는 유용한 메서드(getMessage(), printStackTrace() 등)를 제공합니다.

Throwable을 이해하면 예외 처리와 오류 디버깅을 보다 체계적으로 할 수 있습니다.

📌 제네릭

(1) 제네릭이란?

제네릭은 데이터 타입을 일반화하여 코드의 재사용성을 높이고 타입 안정성을 보장하는 기능입니다.

(2) 제네릭 사용 예시

다양한 타입에 대해 동일한 코드를 재사용한 경험이 있습니다. 특정 Key와 Value를 반환하는 Pair 클래스의 경우 동작은 같으나 타입만 다르므로 제네릭을 통해 중복 코드를 방지할 수 있었습니다.

타입 안정성을 보장한 경험이 있습니다. ArrayList 대신 ArrayList을 사용하여 런타임에 발생할 수 있는 ClassCastException을 방지할 수 있었습니다.


📌 람다, 스트림,

(1) 람다란?

람다식은 메소드를 하나의 식으로 표현한 것을 말합니다. 그리고 람다식은 함수의 이름이 없기 때문에 익명 함수라고 부르며, 메소드의 매개 변수로 전달되거나 메소드의 결과로 반환될 수 있는 특징이 있어서 함수를 변수로 다룰 수 있다는 장점이 있습니다.

(2) 스트림이란?

컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해 주는 내부 반복자를 말합니다. 외부 반복자는 개발자가 컬렉션을 조작하면서 처리 흐름을 제어하지만, 내부 반복자는 컬렉션 내부에서 흐름이 진행됩니다.

(3) 람다와 스트림이 생긴 이유

함수형 프로그래밍의 장점 때문에 탄생했다고 생각합니다. 함수형 프로그래밍은 how가 아닌 what에 집중하므로 코드의 가독성이 높아지고, 함수를 변수에 할당할 수 있으므로 함수의 재사용이 용이합니다.

또한 함수들이 순수 함수로 구성되어 있으므로 외부의 값이 변경되는 등의 사이드 이펙트가 발생하지 않습니다. 순수 함수는 함수에 동일한 인자가 주어졌을 때, 항상 같은 값을 리턴하는 함수입니다. 이로 인해 외부의 상태를 변경하지 않습니다.

📌 어노테이션, 리플렉션

(1) 자바에서 어노테이션이란?

어노테이션은 인터페이스를 기반으로 한 문법으로 주석처럼 코드에 달아 클래스에 특별한 의미를 부여하거나 기능을 주입할 수 있습니다.

(2) 어노테이션 사용 이유

Java 리플렉션을 통해 어노테이션을 런타임 중에 조회할 수 있고, 이 어노테이션의 메타 데이터를 사용하여 런타임 중에 특별한 로직을 작성할 수 있게 됩니다.

(3) 리플렉션이란?

힙 영역에 로드된 클래스 타입의 객체를 통해, 원하는 클래스의 인스턴스를 생성할 수 있게 지원하고, 인스턴스의 필드와 메소드를 접근 제어자와 상관 없이 사용할 수 있도록 지원하는 자바 API입니다.

(4) 리플렉션을 활용해서 어노테이션의 메타 데이터를 가져오는 등의 로직 구현 경험

📌  추가 심화

(1) System.out.println 클래스는 성능이 좋지 않다고 하는데 이유가 무엇일까요?

println 메서드는 블로킹 IO이므로 해당 메서드를 호출하는 스레드는 그 작업이 끝날 때까지 다른 작업을 수행하지 못하고 기다려야 합니다. 또한, println 메서드 내부에 synchronized block이 있어서 여러 스레드가 동시에 System.out 객체의 println 메서드를 호출할 수 없습니다. 이는 thread-safe하다는 점은 있지만 락 베이스로 동작하므로 성능이 떨어집니다.

즉, 싱글 스레드일 경우 블로킹 IO로 인한 성능 이슈가 있고 멀티 스레드일 경우 한 스레드 외의 다른 스레드는 블로킹 된다는 성능 이슈가 존재합니다.

profile
백엔드 개발자 SUM입니다.

0개의 댓글