DTO와 VO란?

DTO(Data Transfer Object)와 VO(Value Object)는 서로 다른 목적을 가진 객체이지만, 개발자들 사이에서 혼용되어 사용되는 경우가 많음.
이러한 혼동의 원인은 일부 서적에서 VO를 DTO로 잘못 정의한 데에서 비롯됨.


DTO (Data Transfer Object)

  • 데이터 전송을 위한 바구니 역할을 하는 객체.
  • 주로 컨트롤러 → 서비스 → DAO 등 계층 간 데이터 전달을 위해 사용됨.
  • Setter가 존재하면 가변 객체가 되지만, Setter 없이 생성자로 초기화하면 불변 객체로 만들 수 있음.
  • Entity와 DTO는 반드시 분리해야 함!
    • Entity는 DB와 직접 연결되는 핵심 클래스이므로 요청 및 응답 데이터 전달용으로 사용하면 안 됨.
    • DTO를 사용하면 뷰 변경이 Entity에 영향을 주지 않음.

DTO 예제

public class CrewDto {
    private final String name;
    private final String nickname;

    public CrewDto(String name, String nickname) {
        this.name = name;
        this.nickname = nickname;
    }

    public String getName() {
        return name;
    }

    public String getNickname() {
        return nickname;
    }
}
 

VO (Value Object)

  • 값 자체를 표현하는 객체이며, 속성 값이 같으면 같은 객체로 판단됨.
  • 불변(Immutable) 객체로 설계되어야 하며, Setter를 사용하지 않음.
  • 비즈니스 로직을 포함할 수 있음.
  • equals()와 hashCode()를 오버라이딩하여 값이 동일하면 같은 객체로 판단하도록 구현해야 함.

VO 예제

public class Money {
    private final int value;

    public Money(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Money money = (Money) o;
        return value == money.value;
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }
}

 

✅ 같은 금액을 가진 Money 객체들은 동일한 객체로 판단됨.


DTO vs VO 비교 정리

비교 항목 DTO (데이터 전달 객체) VO (값 객체)
목적 레이어 간 데이터 전달 값 자체를 표현
변경 가능 여부 가변 객체 가능 불변 객체
로직 포함 여부 Getter, Setter만 가능 추가 로직 포함 가능
비교 기준 객체 주소 비교 속성 값 비교 (equals, hashCode 오버라이딩)

 

📌 결론:

  • DTO는 데이터를 계층 간 전달하는 역할을 하므로 불필요한 로직을 포함해서는 안 됨.
  • VO는 값 자체를 표현하는 객체이므로 값이 같으면 같은 객체로 인식해야 함.

 

 


 

 

Entity란?

Entity는 데이터베이스의 테이블과 직접 매핑되는 클래스로,
도메인 모델에서 비즈니스 로직을 포함할 수 있는 핵심 객체이다.

 

Entity의 주요 특징

  • DB 테이블과 1:1 매핑되는 클래스
  • 비즈니스 로직을 포함할 수 있음
  • 고유 식별자(PK, ID)를 통해 객체를 구분
  • DB 변경을 반영해야 하는 경우 Entity를 수정해야 함
  • Setter를 최소화하고, 필요할 때만 값 변경 허용

Entity 예제

@Entity
public class User {
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;
    private String email;

    protected User() {} // JPA 기본 생성자

    public User(String username, String email) {
        this.username = username;
        this.email = email;
    }

    // 비즈니스 로직 포함 가능
    public void changeEmail(String newEmail) {
        this.email = newEmail;
    }
}

 

📌 특징:

  • @Entity 어노테이션으로 DB 테이블과 매핑됨
  • @Id를 이용해 PK(고유 식별자)를 사용하여 비교
  • 비즈니스 로직을 포함할 수 있음
  • Setter 대신 변경 메서드(changeEmail())를 제공하여 데이터 변경 관리

DTO vs VO vs Entity 비교

구분 DTO (Data Transfer Object) VO (Value Object) Entity (엔티티)
목적 데이터 전달 (계층 간 통신) 값 자체를 표현 DB 테이블과 매핑
영역 컨트롤러 ↔ 서비스 ↔ DAO 도메인 모델 데이터베이스
변경 가능 여부 가변(Setter 존재 가능) 불변(Setter 없음) 가변 (Setter 최소화)
비교 기준 객체 주소(레퍼런스) 비교 속성 값 비교 (equals & hashCode 오버라이딩) ID(PK) 비교
로직 포함 여부 Getter/Setter만 포함 로직 포함 가능 비즈니스 로직 포함 가능
사용 사례 API 응답, 요청 객체 Money, Color 같은 값 표현 객체 User, Order 같은 도메인 모델

 

Entity, DTO, VO 활용 사례

사용 예시 DTO VO  Entity
DB 저장용
API 요청/응답 데이터
비즈니스 로직 포함
불변 객체 ❌ (Setter가 없으면 가능)
데이터 전송 용도

정리

DTO는 데이터를 안전하게 전달하는 역할을 하며, API 응답 및 요청에서 활용됨.
VO는 값 자체를 표현하는 불변 객체이며, equals()와 hashCode()를 오버라이딩해야 함.
Entity는 DB 테이블과 매핑되며 비즈니스 로직을 포함할 수 있음.
Entity와 DTO를 반드시 분리해야 하며, VO는 특정 값 표현에만 사용해야 함.

 

📌 결론:

  • Entity를 API 응답에 직접 사용하지 않고 DTO를 활용하자!
  • VO는 값 기반 비교가 필요할 때 사용하자!
  • DTO는 데이터를 전달하는 역할에 충실하자!

 

참조
https://www.youtube.com/watch?v=J_Dr6R0Ov8E
https://www.youtube.com/watch?v=z5fUkck_RZM

'Web Programming Language > JAVA' 카테고리의 다른 글

MurmurHash3  (1) 2025.02.17
BitSet 클래스  (0) 2025.02.17
Records  (1) 2025.02.12
orElse vs orElseGet 차이점  (0) 2025.02.12
JAVA) print, printf, println 차이점  (0) 2021.03.11

자바의 Records란?

Java의 Records(레코드) 는 Java 14에서 프리뷰 기능으로 처음 도입되었고, Java 16에서 정식 기능으로 추가됨.
레코드는 특정 데이터를 저장하기 위한 객체를 간단히 만들 수 있도록 설계된 새로운 유형의 클래스.
일반적으로 데이터 저장용으로만 사용하는 클래스에서 Boilerplate Code(반복되는 코드)를 줄여주는 것이 핵심 기능.


기존 방식 vs. Records 방식

기존 방식: 일반 클래스 사용

데이터를 저장하는 단순한 객체를 만들 때도 여러 가지 메서드와 필드를 정의해야 함.

예제: Employee 클래스 (기존 방식)

public class Employee {
    private final String name;
    private final int employeeNumber;

    // 생성자
    public Employee(String name, int employeeNumber) {
        this.name = name;
        this.employeeNumber = employeeNumber;
    }

    // Getter 메서드
    public String getName() {
        return name;
    }

    public int getEmployeeNumber() {
        return employeeNumber;
    }

    // toString() 메서드
    @Override
    public String toString() {
        return "Employee{name='" + name + "', employeeNumber=" + employeeNumber + "}";
    }

    // equals() & hashCode() 메서드
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return employeeNumber == employee.employeeNumber &&
               name.equals(employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, employeeNumber);
    }
}

 

문제점:

  • 단순한 데이터 저장용 클래스임에도 불구하고 50줄 이상의 코드가 필요.
  • toString(), equals(), hashCode() 등의 반복적인 코드(Boilerplate Code)가 많음.

새로운 방식: Java Records 사용

위와 같은 클래스를 한 줄의 코드로 정의 가능!

public record Employee(String name, int employeeNumber) {}

 

기본적으로 포함되는 기능들:

  1. private final 필드 자동 생성
  2. getter() 메서드 자동 생성 (get 접두사 없이 name(), employeeNumber() 형태)
  3. toString(), equals(), hashCode() 자동 생성
  4. Canonical Constructor(모든 필드를 초기화하는 생성자) 자동 제공

Records의 주요 특징

1. 불변 객체 (Immutable)

  • 레코드는 불변 객체 이므로, 생성된 후 필드 값을 변경할 수 없음.
  • 따라서 Setter 메서드가 자동으로 생성되지 않음.
Employee emp = new Employee("John", 12345);
emp.name = "Mike"; // 컴파일 에러 ❌

 

대신 새 객체를 생성해야 변경 가능:

Employee emp2 = new Employee("Mike", emp.employeeNumber());

2. 자동 생성되는 메서드

  • toString() 메서드:
Employee emp = new Employee("John", 12345);
System.out.println(emp);
// 출력: Employee[name=John, employeeNumber=12345]
  • equals() & hashCode():
Employee emp1 = new Employee("John", 12345);
Employee emp2 = new Employee("John", 12345);
System.out.println(emp1.equals(emp2)); // true ✅

3. Compact Constructor (압축 생성자)

  • 레코드는 기본적으로 Canonical Constructor(모든 필드를 초기화하는 생성자)를 자동 생성.
  • 하지만 특정 로직을 추가하려면 Compact Constructor 사용 가능.

 

✅ Compact Constructor란?

Compact Constructor는 record 내부에서 모든 필드를 대상으로 공통 검증 로직이나 전처리 로직을 넣고 싶을 때 사용하는 생성자입니다.

 

📌 특징

항목 설명
생성자 선언 시 파라미터 생략 record에 선언된 필드와 동일한 순서와 타입으로 자동 인식
필드 초기화 생략 가능 this.name = name 같은 코드는 자동 삽입됨
용도 유효성 검사, 형 변환, 예외 처리 등
제한 사항 일부 필드만 처리하는 생성자는 만들 수 없음 (항상 전체 필드를 대상으로 함)

 

예제: Compact Constructor로 유효성 검사하기

public record Employee(String name, int employeeNumber) {
    Employee {
        if (employeeNumber < 0) {
            throw new IllegalArgumentException("Employee number cannot be negative");
        }
    }
}

 

🔍 해석

  • 생성자 이름 Employee만 쓰고 (String name, int employeeNumber)는 생략했지만,
    → 컴파일러는 record 선언부에 있는 필드 정보를 기반으로 생성자를 자동 구성합니다.
  • this.name = name 등의 초기화 코드도 생략했지만,
    → 역시 컴파일러가 자동으로 필드에 값을 할당합니다.
  • 우리는 오직 추가적인 검증 로직만 작성하면 됩니다.

 

⚠️ 예외 발생 확인

Employee emp = new Employee("John", -5);

이렇게 실행하면, 음수 값이 들어가므로:

IllegalArgumentException: Employee number cannot be negative

예외가 발생합니다.
→ Compact Constructor를 통해 객체 생성 중 유효하지 않은 값에 대한 제어가 가능해진 것이죠.

 

✅ 즉, record도 생성자에서 검증을 할 수 있다!는 점에서 실무에 매우 유용합니다.


4. Records의 제약 사항

가능한 것

✅ static 필드 및 static 메서드 추가 가능
✅ 메서드 정의 가능
✅ implements를 사용해 인터페이스 구현 가능
✅ Compact Constructor 사용 가능

 

불가능한 것

🚫 extends 사용 불가능 (다른 클래스를 상속할 수 없음)
🚫 private 또는 non-static 필드 추가 불가능
🚫 mutable 필드 추가 불가능
🚫 abstract 메서드 선언 불가능

 

인터페이스 구현 예제

public record Employee(String name, int employeeNumber) implements Comparable<Employee> {
    @Override
    public int compareTo(Employee other) {
        return Integer.compare(this.employeeNumber, other.employeeNumber);
    }
}

Records는 언제 사용할까?

✅ 사용하기 좋은 경우

  • 데이터 전달 객체 (DTO)
  • 데이터 저장 클래스 (단순 값 저장)
  • 데이터베이스 엔티티
  • API 응답 모델

❌ 사용하지 않는 것이 좋은 경우

  • 도메인 객체 (비즈니스 로직 포함)
  • 필드를 변경해야 하는 경우 (Setter가 필요할 때)
  • 복잡한 로직이 포함된 클래스

결론

  • Java Records를 사용하면 데이터 저장용 클래스를 매우 간결하게 정의 가능.
  • 불변성을 유지하면서도 자동으로 필요한 메서드를 제공하여 코드 품질 향상.
  • 기능 확장이 필요하지 않은 단순한 데이터 저장 클래스에 적합.
  • Lombok을 사용하지 않아도 @Data와 같은 효과를 얻을 수 있음.

 

 


 

 

 

자주 묻는 질문 (Q&A)

Q1. 왜 레코드는 getter에 "get"이 붙지 않나요?

레코드는 기존 객체의 대체재가 아니라, 단순히 데이터를 전달하는 값 객체(Value Object) 개념에 초점이 맞춰져 있다.

✅ 일반적인 Java 클래스에서는 getName(), getEmployeeNumber()와 같은 게터 메서드를 사용하지만,
Records에서는 get이 생략되고 name() 또는 employeeNumber() 같은 방식으로 필드 값을 가져올 수 있다.

public record Employee(String name, int employeeNumber) {}

Employee emp = new Employee("John Doe", 12345);
System.out.println(emp.name());  // John Doe (getter 메서드처럼 작동)
System.out.println(emp.employeeNumber());  // 12345
 

이유
1️⃣ Records는 일반적인 객체 모델을 따르지 않으며, 단순한 데이터 컨테이너 역할을 수행한다.
2️⃣ Boilerplate 코드를 줄이기 위한 목적이므로, 불필요한 get 접두사를 생략하여 가독성을 높임.
3️⃣ Java 언어 자체의 설계 철학에 맞게, Records는 객체보다는 데이터 구조에 가깝게 설계됨.


Q2. Lombok 대신 레코드를 사용하면 되나요?

LombokRecords는 비슷한 기능을 제공하지만, 사용 목적과 장점이 다르다.
👉 둘 중 어떤 것을 선택할지 고민된다면 상황에 따라 적절한 선택이 필요하다.


비교 항목 Lombok Records
사용 목적 일반 객체의 Boilerplate 코드 감소 데이터 저장 및 전달용 객체 생성
주요 기능 @Data, @Builder, @Getter, @Setter 등 다양한 기능 지원 toString(), equals(), hashCode() 자동 생성
의존성 Lombok 라이브러리 설치 필요 JDK 16 이상에서 기본 제공
가독성 Lombok 어노테이션으로 코드가 줄어듦 가장 간결한 문법 (1줄로 클래스 생성 가능)
확장성 일반 클래스처럼 필드 추가, Setter 사용 가능 불변 객체이므로 Setter 없음
사용 가능 버전 Java 8 이상 Java 16 이상

 

📌 언제 Lombok을 사용할까?

✅ Setter가 필요할 때
✅ 객체가 비즈니스 로직을 포함하는 경우
✅ 추가적인 빌더 패턴(@Builder)이 필요할 때

 

📌 언제 Records를 사용할까?

✅ 단순한 데이터 저장과 전달이 목적일 때
✅ 코드 가독성을 높이고 유지보수를 편하게 하고 싶을 때
✅ 불변 객체(Immutable Object)가 필요할 때

 

 

🔹 예제: Lombok 사용

import lombok.Data;

@Data
public class Employee {
    private final String name;
    private final int employeeNumber;
}

 

🔹 예제: Records 사용

public record Employee(String name, int employeeNumber) {}

👉 같은 기능이지만, Records는 더 간결한 코드를 제공함.
👉 하지만, Setter가 필요하거나 객체의 상태를 변경해야 한다면 Lombok이 더 적합할 수 있음.


 

Q3. 레코드를 도메인 객체에 사용할 수 있을까요?

🚫 권장하지 않음!

도메인 객체(Domain Object)란, 비즈니스 로직을 포함하는 객체이다.
즉, 단순히 데이터를 저장하는 것뿐만 아니라, 특정 기능과 규칙을 수행해야 한다.

 

Records는 데이터 저장 및 전달을 위한 용도이므로, 비즈니스 로직을 포함하는 도메인 객체로 사용하기에는 적절하지 않다.
도메인 객체에는 일반 클래스 또는 Lombok을 사용하는 것이 더 적절하다.

 

 

📌 왜 Records를 도메인 객체로 사용하면 안 될까?

1️⃣ Setter가 없어 필드 값을 변경할 수 없음
→ 도메인 객체에서는 상태 변경이 필요한 경우가 많음 (예: 사용자의 점수 증가, 주문 상태 변경 등).
2️⃣ 비즈니스 로직을 추가하기 어려움
→ Records는 단순한 데이터 전달을 위해 설계되었으므로, 메서드를 추가하는 것이 비효율적임.
3️⃣ 도메인 객체는 상태를 바꿀 수 있어야 함
→ Records는 기본적으로 불변(Immutable)하므로, 상태 변경이 필요한 객체로 사용하기 어려움.

 

 

🔹 예제: 잘못된 사용 (Records를 도메인 객체로 사용)

public record Order(String orderId, String status) {
    public void changeStatus(String newStatus) { // 불가능한 설계
        this.status = newStatus; // ERROR ❌ (Setter 불가)
    }

대신 일반 클래스를 사용하는 것이 더 적절하다.

 

🔹 예제: 일반 클래스로 도메인 객체 구현

public class Order {
    private String orderId;
    private String status;

    public Order(String orderId, String status) {
        this.orderId = orderId;
        this.status = status;
    }

    public void changeStatus(String newStatus) {
        this.status = newStatus; // 상태 변경 가능 ✅
    }

    public String getStatus() {
        return status;
    }
}
 

 

📌 언제 Records를 사용하고, 언제 일반 클래스를 사용할까?

사용 사례 Records 사용 일반 클래스 사용
데이터 저장 ✅ DTO, API 응답 객체
데이터 변경 (Setter 필요) ✅ 가능
비즈니스 로직 포함 ✅ 가능
상태 유지 ❌ (Records는 Immutable) ✅ 가능
불변 객체가 필요할 때 ✅ (Setter 없음)

 

🔹 Records는 DTO(Data Transfer Object)에 적합하지만,
🔹 비즈니스 로직이 필요한 도메인 객체에는 적합하지 않음.


🔥 정리

질문 답변 요약
Q1. 왜 레코드는 getter에 "get"이 붙지 않나요? Records는 기존 객체 모델과 다르며, 데이터 저장용으로 설계되었기 때문에 불필요한 get을 생략하여 간결한 문법을 제공함.
Q2. Lombok 대신 레코드를 사용하면 되나요? 상황에 따라 다름. 간결한 코드가 필요하면 Records, 추가 기능이 필요하면 Lombok 선택.
Q3. 레코드를 도메인 객체에 사용할 수 있을까요? 권장하지 않음. 도메인 객체는 비즈니스 로직을 포함하므로 일반 클래스를 사용하는 것이 적절함.

 

Records는 단순한 데이터 저장 및 전달용으로 사용하면 매우 유용하지만, 일반 클래스의 완전한 대체는 아니다.
상황에 맞게 적절한 도구(Records, Lombok, 일반 클래스)를 선택하는 것이 중요하다!

 
 

 

'Web Programming Language > JAVA' 카테고리의 다른 글

BitSet 클래스  (0) 2025.02.17
DTO와 VO  (0) 2025.02.12
orElse vs orElseGet 차이점  (0) 2025.02.12
JAVA) print, printf, println 차이점  (0) 2021.03.11
JAVA) Java 프로그램 실행 구조  (0) 2020.11.18

orElse vs orElseGet

Java에서 Optional<T>을 사용할 때, orElse와 orElseGet은 Optional이 비어 있을 경우 기본값을 제공하는 메서드이다.
하지만 두 메서드가 작동하는 방식에는 중요한 차이점이 있다.

핵심 차이:

  • orElse(T other): 기본값을 항상 계산하고, Optional이 비어 있으면 반환.
  • orElseGet(Supplier<? extends T> supplier): Optional이 비어 있을 때만 기본값을 계산.

1. orElse 동작 방식

기본값을 "항상" 계산하는 메서드

  • Optional이 값이 있든 없든 항상 orElse에 전달된 값이 평가(계산)된다.
  • 즉, Optional이 값이 있을 때도 불필요한 연산이 실행될 수 있다.

orElse 예제

public class OrElseExample {
    public static String getDefaultValue() {
        System.out.println("getDefaultValue() 호출됨");
        return "기본값";
    }

    public static void main(String[] args) {
        Optional<String> optional = Optional.ofNullable("안녕하세요");

        String result = optional.orElse(getDefaultValue()); // getDefaultValue()가 실행될까?
        System.out.println("결과: " + result);
    }
}

실행 결과

getDefaultValue() 호출됨
결과: 안녕하세요

 

왜 이런 결과가 나왔을까?

  • Optional에는 "안녕하세요"라는 값이 이미 존재한다.
  • 그런데도 getDefaultValue()가 무조건 실행되었다.
  • 즉, 기본값이 필요하지 않더라도 연산이 발생하는 비효율적인 상황이 생길 수 있다.

2. orElseGet 동작 방식

기본값을 "필요할 때만" 계산하는 메서드

  • Optional이 비어 있을 때만 Supplier(람다 함수)를 실행한다.
  • 즉, 값이 존재하면 불필요한 연산을 하지 않는다.

orElseGet 예제

public class OrElseGetExample {
    public static String getDefaultValue() {
        System.out.println("getDefaultValue() 호출됨");
        return "기본값";
    }

    public static void main(String[] args) {
        Optional<String> optional = Optional.ofNullable("안녕하세요");

        String result = optional.orElseGet(() -> getDefaultValue()); // getDefaultValue()가 실행될까?
        System.out.println("결과: " + result);
    }
}

실행 결과

결과: 안녕하세요

 

이번에는 getDefaultValue()가 실행되지 않았다!

  • Optional에 "안녕하세요"라는 값이 있으므로 기본값을 만들 필요가 없기 때문이다.
  • 즉, orElseGet은 연산을 최소화할 수 있도록 도와준다.

 

3. orElse vs orElseGet 비교

비교 표

메서드 기본값 평가 시점 최적화 가능 여  언제 사용해야 할까?
orElse(T other) 항상 평가됨 ❌ 비효율적
(불필요한 연산 가능)
기본값이 가벼운 경우
orElseGet(Supplier<? extends T> supplier) 필요할 때만 평가됨 ✅ 최적화 가능 기본값을 생성하는 연산이 무거운 경우
(DB 조회, 파일 읽기 등)

orElse의 문제점

Optional<String> optional = Optional.ofNullable("데이터 있음");
String result = optional.orElse(getDataFromDatabase()); // DB 조회가 필요할까?
  • Optional에 값이 있음에도 DB 조회가 실행됩니다!
  • 연산 비용이 큰 작업이 불필요하게 실행될 수 있습니다.

해결 방법 → orElseGet 사용

Optional<String> optional = Optional.ofNullable("데이터 있음");
String result = optional.orElseGet(() -> getDataFromDatabase()); // 필요할 때만 실행됨!
  • Optional이 비어 있을 때만 DB 조회가 실행됩니다.
  • 연산 비용이 큰 작업일 경우, 반드시 orElseGet을 사용하세요.

4. 실전 예제: 성능 차이 확인

orElse vs orElseGet 비교 실험

public class OrElseVsOrElseGet {
    public static String expensiveOperation() {
        System.out.println("💰 비용이 큰 연산 실행 중...");
        return "연산 결과";
    }

    public static void main(String[] args) {
        System.out.println("📌 `orElse` 사용:");
        Optional<String> optional1 = Optional.of("값 있음");
        String result1 = optional1.orElse(expensiveOperation());

        System.out.println("\n📌 `orElseGet` 사용:");
        Optional<String> optional2 = Optional.of("값 있음");
        String result2 = optional2.orElseGet(() -> expensiveOperation());
    }
}

실행 결과

📌 `orElse` 사용:
💰 비용이 큰 연산 실행 중...

📌 `orElseGet` 사용:
  • orElse는 값이 있어도 expensiveOperation()이 실행됨. (비효율적❌)
  • orElseGet은 값이 있으면 실행되지 않음. (최적화 가능✅)

 

5. 언제 orElse를 쓰고 언제 orElseGet을 써야 할까?

기본값이 간단한 값이라면 → orElse 사용

String result = optional.orElse("기본값");
  • "기본값"처럼 가벼운 값이라면 orElse가 편리함.

기본값을 생성하는 연산이 무겁다면 → orElseGet 사용

String result = optional.orElseGet(() -> getDataFromDatabase());
  • getDataFromDatabase()처럼 실행 비용이 큰 경우, orElseGet을 사용하여 불필요한 연산을 방지.

 

결론

  • orElse는 기본값 연산이 항상 실행되므로, 연산 비용이 크다면 orElseGet을 사용하는 것이 좋다.
  • orElseGet은 Optional이 비어 있을 때만 연산하므로, 불필요한 연산을 방지할 수 있다.
  • 성능 최적화를 위해 기본값을 미리 계산할 필요가 없는 경우 orElseGet을 적극 활용하자!

 

참조
https://ysjune.github.io/posts/java/orelsenorelseget/

'Web Programming Language > JAVA' 카테고리의 다른 글

BitSet 클래스  (0) 2025.02.17
DTO와 VO  (0) 2025.02.12
Records  (1) 2025.02.12
JAVA) print, printf, println 차이점  (0) 2021.03.11
JAVA) Java 프로그램 실행 구조  (0) 2020.11.18

변수와 상수의 차이와 활용

JavaScript에서 변수(variable)상수(constant)는 데이터를 저장하고 관리하는 핵심 요소이다.
var, let, const는 각각의 특성과 용도가 다르며, 코드 작성 시 이를 적절히 사용하는 것이 중요하다.

 

변수와 상수 선언 방법

1. var

  • 특징:
    • 재선언 및 재할당 가능.
    • 함수 스코프(Function Scope)를 가짐.
    • 블록 스코프를 지원하지 않음.
  • 사용 예:
    var name = "John";
    
    name = "Doe"; // 재할당 가능

주의: var는 의도치 않은 호이스팅 문제를 유발할 수 있으므로 현대 코드에서는 let과 const 사용이 권장된다.

 

2. let

  • 특징:
    • 재선언 불가능하지만 재할당 가능.
    • 블록 스코프(Block Scope)를 지원.
  • 사용 예:
let age = 25;

age = 26; // 재할당 가능

 

3. const

  • 특징:
    • 재선언 및 재할당 불가능.
    • 반드시 선언 시 초기화 필요.
    • 블록 스코프를 지원.
  • 사용 예:
const PI = 3.14;

// PI = 3.15; // Error: 재할당 불가능

 

변수와 상수의 주요 차이점

특성 var let const
재선언 가능 여부 Yes No No
재할당 가능 여부 Yes Yes No
초기화 필요 여부 No No Yes
스코프 함수 스코프 블록 스코프 블록 스코프

 

스코프(Scope)와 호이스팅(Hoisting)

1. 스코프

  • 함수 스코프: var로 선언된 변수는 함수 내에서만 유효.
  • 블록 스코프: let과 const는 {}로 감싼 블록 내에서만 유효.
if (true) {
  let x = 0;
}

console.log(x); // Error: x is not defined​

 

2. 호이스팅

  • JavaScript는 변수 선언을 코드의 상단으로 끌어올리는 호이스팅을 수행한다.
  • var는 선언부만 끌어올려져 초기화되지 않은 상태로 처리된다.
console.log(a); // undefined
var a = 5;

console.log(b); // Error: Cannot access 'b' before initialization
let b = 10;​

 

let과 const의 추천 사용법

1. const를 기본적으로 사용.
값이 변하지 않는 데이터를 선언할 때 사용

const maxUsers = 100;
 

2. 필요할 때만 let 사용.
동적으로 변경되는 데이터에 적합

let userCount = 0;
userCount++;

 

 

3. var는 사용하지 않음.
var의 함수 스코프와 호이스팅 문제는 유지보수에 적합하지 않다.

 

객체와 배열의 상수 처리

const로 선언된 객체와 배열은 내부 데이터 변경이 가능하다.

const user = { name: "Alice" };
user.name = "Bob"; // 가능

const numbers = [1, 2, 3];
numbers.push(4); // 가능

 

하지만 참조 자체를 변경하는 것은 불가능합니다:

user = { name: "Charlie" }; // Error: 재할당 불가능

 

변수 선언 관련 유용한 팁

 

1. 명확한 변수 이름 사용:
변수의 목적을 쉽게 알 수 있도록 작성

let userAge = 30; // 명확한 변수명

 

2. 초기화와 함께 선언:

선언과 초기화를 동시에 하여 예측 가능한 코드를 작성

const isLoggedIn = false;

3. 스코프를 잘 이해하고 활용:
불필요한 전역 변수 사용을 지양

 

요약

  • var 대신 let과 const를 사용
  • const는 값을 변경하지 않을 때, let은 변경 가능성이 있을 때 사용한다.
  • 스코프와 호이스팅의 작동 방식을 이해하면 코드 오류를 줄이고 가독성을 높일 수 있다.

최적의 코드 작성: 명확한 변수 선언과 스코프 활용은 코드 품질을 높이고, 협업 시 이해도를 향상시킨다.

 

 

 

참조
https://tcpschool.com/javascript/js_intro_syntax#google_vignette

https://ko.javascript.info/variables

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EB%B3%80%EC%88%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85#thankYou

 

 

'Web Programming Language > JS' 카테고리의 다른 글

JavaScript란?  (0) 2024.12.03
JavaScript) eval() 함수  (0) 2020.10.29
java script) history.back(), history.go(), history.forward()  (0) 2020.10.27

JavaScript란 무엇인가?

JavaScript는 웹 페이지를 동적으로 만들기 위해 사용하는 프로그래밍 언어로, 주로 브라우저에서 실행된다.
HTML 및 CSS와 함께 웹 개발의 핵심 기술로 자리 잡았으며, 다양한 기능을 통해 사용자 경험을 풍부하게 한다.

 

JavaScript의 정의

  • 정의: JavaScript는 클라이언트에서 실행되며, HTML 및 CSS와 함께 동작해 웹 페이지를 동적으로 제어한다.
  • 역사: 초창기에는 브라우저 내에서 간단한 동작을 수행하기 위해 개발되었으나, 현재는 서버, 앱, 게임 개발 등으로 확장되었다.

대표적인 실행 환경:

  • 브라우저: Chrome(V8 엔진), Firefox(SpiderMonkey), Edge(Chakra), Safari(WebKit).
  • 서버: Node.js.

 

브라우저에서 JavaScript로 할 수 있는 일

JavaScript는 브라우저에서 다양한 동적 기능을 제공한다.

  1. HTML 콘텐츠 조작:
    페이지 내용을 실시간으로 수정하거나 업데이트.
  2. 이벤트 처리:
    클릭, 입력, 스크롤 등의 사용자 인터랙션에 반응.
  3. 데이터 통신:
    AJAX를 통해 서버와 비동기적으로 데이터 송수신.
  4. 애니메이션 효과:
    요소의 움직임과 변화를 부드럽게 구현.

 

브라우저에서 JavaScript로 할 수 없는 일

브라우저의 JavaScript는 보안상의 이유로 몇 가지 제한이 있다.

  • 파일 시스템 접근.
  • 운영 체제나 하드웨어 직접 제어.
  • 다른 도메인의 서버 데이터에 접근(CORS 정책 적용).

 

JavaScript의 장점

  1. HTML/CSS와의 완벽한 통합:
    • 웹 페이지를 동적으로 업데이트 가능.
  2. 비동기 처리:
    • 비동기 통신(AJAX)을 통해 사용자 경험 개선.
  3. 광범위한 사용:
    • 브라우저뿐만 아니라 서버(Node.js), 모바일 앱에서도 사용 가능.

 

JavaScript의 확장 가능성

JavaScript는 다양한 파생 언어와 프레임워크를 통해 확장되었다.

  • TypeScript: JavaScript의 상위 언어로, 정적 타입을 제공.
  • Dart: Google이 개발한 언어로, JavaScript로 변환 가능.
  • Frameworks: React, Angular, Vue 등은 JavaScript로 강력한 웹 애플리케이션 개발을 지원.

 

요약

JavaScript는 웹 개발의 중심 기술로, 정적 콘텐츠에 생동감을 부여하고, 사용자와의 상호작용을 가능하게 한다.

  • 브라우저에서 실행: HTML, CSS와 통합.
  • 서버에서도 활용 가능: Node.js.
  • 강력한 확장성: 다양한 프레임워크와 라이브러리를 통해 현대적인 웹 개발을 지원.

 

참조:
https://ko.javascript.info/intro

'Web Programming Language > JS' 카테고리의 다른 글

변수와 상수  (0) 2024.12.03
JavaScript) eval() 함수  (0) 2020.10.29
java script) history.back(), history.go(), history.forward()  (0) 2020.10.27

basename() 함수 - 파일 이름 반환

 

1. basename - 역할

주어진 경로에서 파일 이름만 반환하는 함수.

 

 

1.1. 구문형식

 

basename(경로 , 접미사)

 

접미사가 입력되면 파일 이름에서 해당하는 접미사는 제거됨

 

 

 

2. basename - 예제

 

2.1. 코드

<body>
<?php
    
    $test_path = "/home/work/menu/test.php";
    
    echo basename ($test_path);
    echo "<br>";
    echo basename($test_path,".php");
?>
</body>

 

 

2.2. 결과화면

 

 

2.3. 설명

test_path는 경로를 나타내고 있고 basename() 함수를 통하여 파일 이름만 반환하고 있다.



 

 

참고 :

https://devjhs.tistory.com/211

'Web Programming Language > PHP' 카테고리의 다른 글

PHP) readfile() 함수  (0) 2021.01.15
PHP) HTTP Response Header - Content-Disposition 속성  (0) 2021.01.15
PHP) HTTP Header - MIME-Type, Content-Type  (0) 2021.01.14
PHP) shell_exec() 함수  (0) 2020.11.05
PHP) system() 함수  (0) 2020.11.05

+ Recent posts