개발자 꼬부기의 성장일기
22일차 - StringifyJSON 구현하기 본문
Stringify는 JSON 형태의 데이터로 변환하는 기능
JSON 데이터
JSON 데이터는 이름과 값의 쌍으로 구성.
이러한 JSON 데이터는 데이터 이름, 콜론(:), 값의 순서로 구성.
"데이터이름": 값
데이터의 이름이 "name"이고, 값은 "식빵"이라는 문자열을 갖는 JSON 데이터
"name": "식빵"
데이터의 이름도 문자열이므로, 항상 큰따옴표("")와 함께 입력해야 한다.
데이터의 값으로 문자열, 숫자, 불리언, 배열, 객체로 올 수 있다.
문자열 => "문자열"
숫자 => 숫자
불리언 => 불리언
객체 => []
배열 => []
Map => {key:value}
1. stringify함수 구현하기
1-1. instanceof 연산자를 통해 모든 경우의 수로 분기시킨다.
//입력된 값이 문자열일 경우
if (data instanceof String)
//입력된 값이 Integer일 경우
if (data instanceof Integer)
//입력된 값이 Boolean일 경우
if (data instanceof Boolean)
//입력된 값이 Object[]일 경우 : 배열
if (data instanceof Object[])
//입력된 값이 HashMap일 경우
if (data instanceof HashMap)
1-2. 가장 마지막의 리턴값 부터 채우고 차례대로 리턴값을 구한다.
//입력된 값이 문자열일 경우
if (data instanceof String)
return String.format("\"%s\"", data );;
//입력된 값이 Integer일 경우
if (data instanceof Integer)
return Integer.toString((Integer) data);
//입력된 값이 Boolean일 경우
if (data instanceof Boolean)
return String.valueOf((Boolean) data);
//입력된 값이 Object[]일 경우 : 배열
if (data instanceof Object[]) {
//여기서 바로 하려다가 '[ ]' 필요해서 함수 분기 시킴
String returnStr = arrayToString((Object[]) data);
return "[" + returnStr + "]";
}
//입력된 값이 HashMap일 경우
if (data instanceof HashMap) {
//여기서 바로 하려다가 '{ }' 필요해서 함수 분기 시킴
//맵 사이즈가 없으면 빈값이니 {}로 출력됨
if (((HashMap<?, ?>) data).size() == 0){
return "{}";
}
String returnStr = mapToString((HashMap<?,?>) data);
return "{" + returnStr + "}";
}
//지정되지 않은 타입의 경우에는 "null"을 리턴합니다.
return "null";
* 특수문자 " 큰따옴표 등은 \" 앞에 \(역슬래시)가 붙어야 한다.
* 정수를 문자열로 변환하는 방법 4가지
- Integer.toString():
- 정수를 문자열로 변환하기 위해 toString() 메서드를 사용
- 간단하고 직관적인 방법
- null을 처리할 수 없으며, 정수 값이 null인 경우 NullPointerException이 발생
- 예시: String str = Integer.toString(number);
- String.valueOf():
- String 클래스의 valueOf() 메서드를 사용하여 정수를 문자열로 변환
- null을 처리할 수 있으며, 정수 값이 null인 경우 "null" 문자열로 변환
- 예시: String str = String.valueOf(number);
- String.format():
- 문자열 포맷을 사용하여 정수를 문자열로 변환
- 다양한 형식화 옵션을 제공하므로 원하는 형태로 출력가능.
- null을 처리할 수 없으며, 정수 값이 null인 경우 NullPointerException이 발생
- 예시: String str = String.format("%d", number);
- DecimalFormat 클래스:
- DecimalFormat 클래스를 사용하여 정수를 형식화된 문자열로 변환
- 형식화된 출력을 위한 유연한 형식 옵션 제공
- null을 처리할 수 없으며, 정수 값이 null인 경우 NullPointerException이 발생
- 예시: DecimalFormat decimalFormat = new DecimalFormat("#,###"); String str = decimalFormat.format(number);
결론, 여기서는 String.valueOf()가 맞을것같다. null을 "null"문자열로 변환하는 조건도 일치하며 예외가 발생되지 않기 때문에
1-3. 배열로 받는 경우의 수 구현
private String arrayToString(Object[] data) {
StringBuilder sb = new StringBuilder();
String result = "";
if(data.length == 0) return "";
for(Object con : data){
sb.append(stringify(con));
sb.append(",");
}
result = sb.substring(0,sb.length()-1).toString();
return String.valueOf(result);
}
* 반복문으로 갈 수록 concat 또는 + 연산자 보다 stringBuilder의 append 연산자가 더 유리하다.
chat GPT에서...
+ 연산자를 사용하는 것은 간단하고 직관적인 방법입니다. 예를 들어, "Hello, " + name + "!와 같은 형태로 문자열을 합칠 수 있습니다. 하지만 + 연산자는 내부적으로 StringBuilder 객체를 생성하고 append() 메서드를 호출하여 문자열을 합치는 작업을 수행합니다. 따라서 + 연산자를 반복적으로 사용하면 성능 저하가 발생할 수 있습니다. 특히 반복문 안에서 문자열을 합치는 경우에는 성능 문제가 더욱 심각해질 수 있습니다.
append() 메서드는 StringBuilder 클래스의 인스턴스를 사용하여 문자열을 합칩니다. StringBuilder는 가변 크기의 문자열을 효율적으로 처리하기 위해 설계된 클래스로, 내부적으로 버퍼를 사용하여 문자열을 저장합니다. append() 메서드는 문자열을 기존 버퍼에 추가하는 방식으로 작동하므로 + 연산자보다 효율적입니다. 따라서 반복적으로 문자열을 합칠 때는 append() 메서드를 사용하는 것이 성능적으로 유리합니다.
stringBuilder vs string Buffer
toString() 메서드는 StringBuilder 클래스에도 있으며, 동일한 방식으로 사용할 수 있습니다. StringBuffer와 StringBuilder는 유사한 기능을 제공하지만, StringBuffer는 스레드 안전(thread-safe)하고 동기화되어 있으므로, 멀티스레드 환경에서 사용할 때 선호됩니다. 단일 스레드 환경에서는 StringBuilder를 사용하는 것이 성능상 이점이 있습니다.
1-4 해시맵으로 받는 함수 구현
public String mapToString(HashMap<?,?> data){
//LinkedHashMap Map은 순서가 없는데 순서 유지해서 복사함.
HashMap<?,?> map = new LinkedHashMap<>(data);
//순서가 없으니 키셋으로 받아온다음 순서가 있는 배열로 변환함.
Object key = map.keySet().toArray()[0];
//배열 첫번째꺼 빼면서 키값으로 value 값에 접근
Object value = map.get(key);
StringBuilder sb = new StringBuilder();
//문자열이면 "" , 숫자면 그냥 그대로 가지고오는 함수 호출
sb.append(stringify(key));
sb.append(":");
sb.append(stringify(value));
String result = sb.toString();
// 사이즈가 1개면 , 필요없으므로 그냥 그대로 출력
if(map.size()==1) {
//썼던 키값은 빼줘야 순차적으로 접근 가능함.
map.remove(key);
return result;
}
// 사이즈가 여러개이면 , 필요함
else{
//썼던 키값은 빼줘야 순차적으로 접근 가능함.
map.remove(key);
//재귀함수로 반복
return result + "," + mapToString(map);
}
}
두가지 방법으로 풀 수 있다.
1) hashmap은 원래 순서가 없다 => LinkedHashMap 맵의 순서대로 나오는 자료구조 활용
keyset 담고 첫번째 키배열 빼주고 리턴 그다음 돌대 또 첫번째 키배열 빼주고 리턴.
2) entryset 이용 : 모든 엔트리를 셋으로 리턴해줌. => 반복문 돌면서 글자 찍어줌.
끝.
'언어공부 > [코드스테이츠] 백엔드부트캠프' 카테고리의 다른 글
24일차 - 자료구조/알고리즘 (Graph/Tree) (0) | 2023.05.16 |
---|---|
23일차 - 자료구조/알고리즘 (Stack/Queue) (0) | 2023.05.15 |
22일차 - DailyCoding (0) | 2023.05.11 |
21일차 - DailyCoding (0) | 2023.05.10 |
20일차 - Section 1 마치며 (0) | 2023.05.09 |