Coram Deo

[프로그래머스] JadenCase 문자열 만들기(Java) - 리팩토링 과정 본문

알고리즘 공부

[프로그래머스] JadenCase 문자열 만들기(Java) - 리팩토링 과정

탁탁슝 2024. 7. 9. 23:23

1. 처음 제출한 코드

  • 함수 사용 X
    • Solution 함수 하나에 모든 코드를 작성함
  • if - else가 중첩되어 코드가 복잡해지고 가독성이 떨어짐
    •  아래와 같이 매우 복잡해짐
import java.util.*;

class Solution {
    public String solution(String s) {
        // 1. 공백을 만나면 인덱스를 0으로 초기화, 공백 추가
        // 2. 인덱스가 0이고 a~z일 경우, 대문자로 변환하고 대체한다.
        // 3. 인덱스가 0이 아닌 나머지 경우, 소문자로 변환하고 대체한다.
       
        String answer = "";
        int index = 1;
        for(int i=0; i<s.length(); i++){
            if(s.charAt(i) == ' '){
                index = 0;
            }
            if(index == 1){
                if(s.charAt(i) >= 'a' && s.charAt(i) <='z'){
                    answer += (char)(s.charAt(i) - 32);
                }else{
                    answer += s.charAt(i);
                }
            }else {
                if(s.charAt(i) >= 'A' && s.charAt(i) <='Z'){
                    answer += (char)(s.charAt(i) + 32);
                }else{
                    answer += s.charAt(i);
                }
            }
            index++;
        }

        return answer;
        }
    }

 

2. 두번째 제출한 코드

  • 함수를 만들어서 사용함.
    • changeToUpper(int i, String s)
    • changeToLower(int i, String s)
  • 그러나 같은 값을 반복해서 사용함으로 가독성이 떨어짐.
    • s.charAt(i)
  • String을 사용하여 값을 반복적으로 더하여 성능이 떨어짐.
    • String answer += 값 (이 코드가 반복됨)
    • String 덧셈연산이 성능이 떨어지는 이유
      • String은 immutable하다. (= String은 한번 생성되면 수정이 불가함)
      • 따라서 String 객체끼리 더하는 연산을 할 때마다 새로운 객체를 생성하므로, 그때마다 메모리 할당과 해제를 발생시킨다.
import java.util.*;

class Solution {
    public String solution(String s) {
        // 1. 공백을 만나면 인덱스를 0으로 초기화
        // 2. 인덱스가 1이고 소문자인 경우, 대문자로 변환한다.
        // 3. 인덱스가 1이 아니고 대문자인 경우, 소문자로 변환한다.
       
        String answer = "";
        int index = 1;
        
        for(int i=0; i<s.length(); i++){
            if(s.charAt(i) == ' '){
                index = 0;
            }
            if(index == 1){
                answer += changeToUpper(i, s);
            }else {
                answer += changeToLower(i, s);
            }
            index++;
        }
        return answer;
    }
    
    // 대문자 변환 함수
    public String changeToUpper(int i, String s){
        String words = "";
        if(s.charAt(i) >= 'a' && s.charAt(i) <='z'){
            words += (char)(s.charAt(i) - 32);
        }else{
            words += s.charAt(i);
        }
        return words;
    }
    
    // 소문자 변환 함수
    public String changeToLower(int i, String s){
        String words = "";
        if(s.charAt(i) >= 'A' && s.charAt(i) <='Z'){
            words += (char)(s.charAt(i) + 32);
        }else{
            words += s.charAt(i);
        }
        return words;
    }
}

 

3. 최종 제출한 코드 

  • StringBuilder를 사용하여 성능을 높임
    • String 대신 answer을 StringBuilder로 생성
    • String의 더하기 연산대신 StringBuilder의 append()로 대체
    • 변경불가인 String과 다르게 StringBuiler는 변경가능한(mutable) 문자열을 만들어주기 때문에 성능이 높아짐.
  • 함수의 구조 변경
    • 매개변수를 변환하여 코드를 간결하게 함
    • 반환타입을 String에서 char로 변경하여 코드를 간결하고 효율적이게 함
      • String을 반환하면 내부적으로 계속 새로운 String객체를 생성하게 되어 메모리 사용측면에서 비효율적임.
      • char로 반환하면 한 글자를 변환한다는 함수의 목적이 명확해진다.
      • StringBuilder에 char를 추가하는 것이 String을 추가하는 것보다 더 빠르다.
  • 반복되는 값을 변수에 할당하여 사용 → 가독성 향상
    • char currentChar = s.charAt(i);
import java.util.*;

class Solution {
    public String solution(String s) {
        // 1. 공백을 만나면 인덱스를 0으로 초기화
        // 2. 인덱스가 1이고 소문자인 경우, 대문자로 변환한다.
        // 3. 인덱스가 1이 아니고 대문자인 경우, 소문자로 변환한다.
       
        StringBuilder answer = new StringBuilder();
        int index = 1;
        
        for(int i=0; i<s.length(); i++){
            char currentChar = s.charAt(i);
            
            if(currentChar == ' '){
                index = 1;
                answer.append(currentChar);
                continue;
            }
            
            if(index == 1){
                answer.append(changeToUpper(currentChar));
            }else {
                answer.append(changeToLower(currentChar));
            }
            index++;
        }
        return answer.toString();
    }
    
    // 대문자 변환 함수
    public char changeToUpper(char c){
        if(c >= 'a' && c <='z'){
            return (char)(c - 32);
        }
        return c;
    }
    
    // 소문자 변환 함수
    public char changeToLower(char c){
        if(c >= 'A' && c <='Z'){
            return (char)(c + 32);
        }
        return c;
    }
}

 

 

4. 내장 함수를 이용한 코드

  • char를 대소문자 변환해주는 내장 함수 사용
    • Character.toUpperCase( currentChar )
    • Character.toLowerCase( currentChar )
import java.util.*;

class Solution {
    public String solution(String s) {
        // 1. 공백을 만나면 인덱스를 0으로 초기화
        // 2. 인덱스가 1이고 소문자인 경우, 대문자로 변환한다.
        // 3. 인덱스가 1이 아니고 대문자인 경우, 소문자로 변환한다.
       
        StringBuilder answer = new StringBuilder();
        int index = 1;
        
        for(int i=0; i<s.length(); i++){
            char currentChar = s.charAt(i);
            
            if(currentChar == ' '){
                index = 1;
                answer.append(currentChar);
                continue;
            }
            
            if(index == 1){
                answer.append(Character.toUpperCase(currentChar));
            }else {
                answer.append(Character.toLowerCase(currentChar));
            }
            index++;
        }
        return answer.toString();
    }
    
   
}