Java 기초 개념 심화: 자바 문법 구조 및 최적화 기법

자바 문법 구조의 이해

자바는 강력한 객체지향 프로그래밍 언어로, 그 문법 구조를 깊이 이해하는 것은 효율적인 코드 작성의 기본입니다.

 

패키지 구조의 중요성

1
2
3
4
5
6
package com.example.application.service;
import java.util.List;
import java.util.ArrayList;
import static java.util.stream.Collectors.toList;
cs

 

패키지 구조는 단순한 코드 정리 이상의 의미를 갖습니다. 잘 설계된 패키지 구조는

  1. 가독성 향상: 관련 클래스들을 논리적으로 그룹화

  2. 접근 제어 강화: 패키지 접근 제한자를 통한 캡슐화

  3. 이름 충돌 방지: 동일한 클래스 이름의 충돌 방지

  4. 배포 용이성: 모듈화된 배포 가능

 

권장 패키지 구조

  • com.company.project.domain: 비즈니스 도메인 객체

  • com.company.project.service: 비즈니스 로직

  • com.company.project.repository: 데이터 액세스

  • com.company.project.controller: 사용자 인터페이스 로직

  • com.company.project.util: 유틸리티 클래스

 

클래스 구조 최적화

클래스 구조를 최적화하기 위한 팁

  1. 일관된 순서 유지: 상수, 정적 변수, 인스턴스 변수, 생성자, 메서드, 내부 클래스 순으로 배치

  2. 단일 책임 원칙: 클래스는 하나의 책임만 가져야 함

  3. 불변성 활용: 가능한 final 키워드 사용

  4. 접근 제한자 최소화: 필요한 최소한의 접근 권한만 부여

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
31
32
33
34
35
public class UserService {
    // 상수 정의
    private static final int MAX_LOGIN_ATTEMPTS = 5;
    // 정적 변수
    private static int userCount = 0;
    // 인스턴스 변수
    private final UserRepository repository;
    private String serviceId;
    // 생성자
    public UserService(UserRepository repository) {
        this.repository = repository;
        this.serviceId = generateServiceId();
        userCount++;
    }
    // 메서드
    public User findById(Long id) {
        return repository.findById(id)
            .orElseThrow(() > new UserNotFoundException(id));
    }
    // 정적 메서드
    public static int getUserCount() {
        return userCount;
    }
    // 내부 클래스
    private class ServiceMetrics {
        // 내부 구현
    }
}
cs

 

자바 코드 최적화 기법

1. 문자열 처리 최적화

문자열은 자바에서 가장 많이 사용되는 데이터 타입 중 하나이지만, 비효율적으로 사용하면 성능 저하의 원인이 됩니다.

성능 비교: 위 두 코드의 실행 시간은 수백 배 차이가 날 수 있습니다. 첫 번째 방법은 매 반복마다 새로운 String 객체를 생성하지만, 두 번째 방법은 단일 StringBuilder 객체를 재사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 비효율적인 방법
String result = “”;
for (int i = 0; i < 10000; i++) {
    result += i;  // 매 반복마다 새 String 객체 생성
}
// 최적화된 방법
StringBuilder result = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    result.append(i);  // 기존 객체 재사용
}
String finalResult = result.toString();
cs

 

 

2. 루프 최적화

루프 최적화 팁

  1. 루프 불변 코드 외부로 이동

  2. 향상된 for 루프 사용 (가독성)

  3. 적절한 경우 스트림 API 활용 (병렬 처리 가능)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 기본 for 루프
for (int i = 0; i < list.size(); i++) {  // 매 반복마다 size() 호출
    process(list.get(i));
}
// 최적화된 for 루프
int size = list.size();  // size() 한 번만 호출
for (int i = 0; i < size; i++) {
    process(list.get(i));
}
// 향상된 for 루프 (가장 가독성 좋음)
for (Element e : list) {
    process(e);
}
// 스트림 API (함수형 접근)
list.stream()
    .filter(e > e.isValid())
    .forEach(e > process(e));
cs

3. 조건문 최적화

조건문 최적화 전략

  1. 빈도 기반 정렬: 가장 자주 발생하는 조건을 먼저 검사

  2. 조기 반환: 조건 충족 시 즉시 반환하여 불필요한 검사 방지

  3. 복잡한 조건은 분리: 단순한 조건부터 평가하여 단락 평가 활용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 비효율적인 조건문
if (condition1) {
    // 자주 실행되는 코드
else if (condition2) {
    // 가끔 실행되는 코드
else if (condition3) {
    // 드물게 실행되는 코드
}
// 최적화된 조건문
if (condition1) {
    // 자주 실행되는 코드
    return;
}
if (condition2) {
    // 가끔 실행되는 코드
    return;
}
// 드물게 실행되는 코드
cs

4. 객체 생성 최적화

객체 생성 최적화 방법

  1. 객체 풀링: 자주 사용되는 객체는 풀에서 재사용

  2. 지연 초기화: 필요할 때만 객체 생성

  3. 불변 객체 활용: 스레드 안전성 확보 및 재사용 가능

1
2
3
4
5
6
7
8
9
10
11
12
// 비효율적인 방법
for (int i = 0; i < 1000; i++) {
    Date now = new Date();  // 매 반복마다 객체 생성
    process(now);
}
// 최적화된 방법
Date now = new Date();
for (int i = 0; i < 1000; i++) {
    process(now);  // 객체 재사용
}
cs

 

실전 예제: 성능 최적화된 데이터 처리

다음은 대용량 사용자 데이터를 처리하는 최적화된 코드 예제입니다.

이 코드는 다음과 같은 최적화 기법을 적용했습니다.

  1. 스트림 API를 사용한 선언적 프로그래밍

  2. 병렬 처리로 멀티코어 활용

  3. 필터링을 통한 불필요한 처리 방지

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public List<UserDTO> processUsers(List<User> users) {
    return users.stream()
        .filter(user > user.isActive())  // 활성 사용자만 필터링
        .parallel()  // 병렬 처리로 성능 향상
        .map(user > {
            // 객체 변환 로직
            UserDTO dto = new UserDTO();
            dto.setId(user.getId());
            dto.setName(user.getName());
            dto.setEmail(user.getEmail());
            return dto;
        })
        .collect(Collectors.toList());
}
cs

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다