동적 타입 언어인 파이썬과 자바스크립트에 적응한 나란 몸..
정적 타입 언어 자바를 쓰려니 참 어렵다... 휴
자바 미션과 코딩테스트를 대비해서 헷갈렸던 개념을 정리하면서 공부해보자!
List 클래스
자바에서 List를 만들때 List 인터페이스를 구현한 ArrayList나 LinkedList와 같은 객체를 생성하게 되는데 Arrays.asList()와 List.of() 메소드로도 생성할 수 있다.
1) Arrays.asList()
List<String> strList = new ArrayList<>(Arrays.asList(splitArray));
2) List.of()
List.of() 메서드는 JAVA 9 부터 지원하는 메서드이다.
char 배열과 String 클래스 차이
코드를 짤 때 문자열 저장은 String 타입의 변수를 사용했다. '문자열'의 뜻은 '문자를 연이어 늘어놓은 것'을 의미하므로 문자배열인 char 배열과 같은 뜻이다.
💡 그러면 왜 자바에서 char 배열 대신 String 클래스를 이용할까?
1️⃣ String 클래스는 char 배열에 기능(메서드)을 추가한 것이다.
그렇다! C언어에서는 문자열을 char 배열로 다루지만, 자바에서는 char 배열과 그와 관련된 기능을 묶어서 클래스로 정의한다!! 메서드를 가득가득 추가했다!!
- 객체지향 언어 특징: 데이터와 그와 관련된 기능을 하나의 클래스에 묶어서 다룬다.
2️⃣ String 클래스는 읽을 수만 있고 변경은 할 수 없다. (ReadOnly)
그래서 변경 가능한 문자열을 다루려면, StringBuffer클래스를 사용하면 된다.
1) 주요 메서드
메서드 | 설명 |
char charAt(int index) | 문자열에서 해당 위치(index)에 있는 문자를 반환한다. |
int length() | 문자열의 길이를 반환한다. |
String substring(int from, int to) | 문자열에서 해당 범위(from~to)에 있는 문자열을 반환한다. (to는 범위에 포함되지 않음) (to 생략하면 끝까지) |
boolean equals(Object obj) | 문자열의 내용이 obj와 같은지 확인한다. 같으면 결과는 true, 다르면 false가 된다. 문자열 비교할 땐 '=='을 쓰면 안된다. 대소문자를 구분한다. (구분 원하지 않으면 equalsIgnoreCase() 사용) |
char[] toCharArray() | 문자열을 문자배열(char[])로 변환해서 반환한다. |
지금은 차이점을 공부하는 중이기 때문에 더 자세한 메서드는 따로 정리하겠다.
* '=='와 'equals'의 차이점
- '==' 연산자는 두개의 대상의 주소값을 비교한다.
- 'equals'는 두개의 대상의 값 자체를 비교한다.
✔️ String에서 '=='연산자를 사용하지 않는 이유
- 기본 타입(int, char) 같은 경우에는 Call by Value 형태로 기본적으로 대상에 주소값을 가지지 않는 형태이다.
- 하지만 String은 일반적인 타입이 아닌 클래스이다. 클래스는 Call by Reference형태로 생성 시 주소값이 부여된다.
- 따라서 String타입을 선언했을때는 같은 값을 부여하더라도 서로간의 주소값이 다르다.
- 그래서 자바에서 문자열 비교는 equals() 메서드를 사용해야 한다.
2) 문자열 추출
1. str.charAt(0)
으로 특정 인덱스의 문자열을 추출하면 char 타입으로 반환되어 String.valueOf로 타입을 변경해주어야 한다.
(파이썬에서는 배열도 문자열도 다 'list[0]', 'str[0]' 이런 식으로 가져왔지만 자바에서는 배열은 'list[0]'가 가능하지만 str은 'str.charAt(0)'으로 가져와야 한다.)
2. str.substring(0,4)
문자열의 일부를 추출할 수 있다.
주의할 점은 4는 범위에 포함되지 않는다.
String 타입으로 반환하고 싶을 때는 str.substring(0,1)을 쓰자.
3. StringBuilder
StringBuilder를 사용하면 특정 문자열을 뽑아서 문자열을 만들 수 있다.
StringBuilder sb = new StringBuilder();
sb.append(testString.charAt(0));
sb.append(testString.charAt(1));
char 배열과 String 클래스 변환
char[] chArr = {"A", "B", "C"};
// char배열 -> String
String str = new String(chArr); // 생성자 활용
String str = String.valueOf(chArr);
StringBuilder sb = new StringBuilder();
for (char ch : charArray) {
sb.append(ch);
}
String str = sb.toString();
Stream<Character> charStream = Arrays.stream(charArray);
String str = charStream.map(String::valueOf).collect(Collectors.joining());
// String -> char배열
char[] tmp = str.toCharArray();
String 클래스
String 클래스는 읽어 올 수만 있고, 변경할 수는 없다.
- '+' 연산자를 이용해서 문자열을 결합
- 덧셈 연산자를 이용한 문자열 결합은 성능이 떨어진다.
- 매 연산마다 새로운 문자열을 가진 String 인스턴스가 생성되어 메모리 공간을 차지하기 때문이다.
그래서 반복문 안에서 지속적인 문자열 결합을 해야할 때에는 StringBuffer 클래스를 써야한다.
빈 문자열 (empty string)
: 초기화 방법
String s = "";
char c = ' ';
배열에 특정 값이 존재 여부 확인
1) equals() 메서드
💡 예시 상황: 숫자 36이 들어오면 각 자리에 3, 6, 9의 개수를 count 한다.
단순히 존재 여부가 아니라 몇 개가 일치하는지도 중요하여 for문으로 단순하게 반복해서 비교했다.
(이때 리팩토링해 3, 6, 9가 3의 배수라는 것을 이용하는 조건문으로 변경했지만 equals()에 대해서 제대로 알게 되어 아래 예시로 남겨둔다.)
private static int check369(int number) {
String NumToString = String.valueOf(number);
String[] splitArray = NumToString.split("");
int count = 0;
for(String str : splitArray) {
if(str.equals("3") || str.equals("6") || str.equals("9")) {
count++;
}
}
return count;
}
2) List 변환 후 contains 메서드
현재 String[] 배열을 List로 변환한 뒤 List 클래스에서 제공하는 contains() 메서드로 값의 존재 여부를 확인할 수 있다.
값의 존재 여부를 확인할 때 유용한 메서드인 듯 하다.
List<String> strList = new ArrayList<>(Arrays.asList(splitArray));
return strList.contains("3") || strList.contains("6") || strList.contains("9");
이때 List로 변환할 때 Arrays 클래스의 asList() 메서드를 사용했다.
대소문자 구분
1) 문자열이 전부 소문자인지
validation하는 메소드를 구현하는 과정 필요한 대소문자 구분을 알아보자.
- String 클래스에서는 문자열을 대소문자로 변환할 수 있는 메소드를 제공한다. 이걸 이용해보자.
- 소문자인지 알고 싶을 땐 들어온 input값을 모두 소문자로 바꾼 뒤 기존 input과 같은지 확인한다.
// input은 String 타입이다.
input.toLowerCase()
input.toLowerCase()
private static void validateLower(String input) {
if (!input.toLowerCase().equals(input)) {
throw new IllegalArgumentException("cryptogram은 알파벳 소문자로만 이루어져 있다.");
}
}
* 여기서 잠시 깜빡하고 문자열 비교에 '==' 연산자를 사용했다. 기억하자! 문자열 비교에는 equals를 쓰자!!
* 또 equals는 대소문자를 구분한다. (구분 원하지 않으면 equalsIgnoreCase() 사용)
if (!input.toLowerCase().equals(input)) {
if (input.toLowerCase() != input) { // 안돼~
2) 특정 문자열이 소문자인지, 대문자인지
Character.isUpperCase(str.charAt(0));
Character.isLowerCase(str.charAt(0));
해당 메서드는 Character 클래스에서 제공하는 메서드이다.
char 타입이 들어가야한다. charAt은 char 타입을 반환한다.
스택 (Stack)
자바에서는 Stack 클래스를 따로 지원해준다.
Stack<Element> stack = new Stack<>();
import java.util.Stack; //import
Stack<Character> stack = new Stack<Character>();
Stack<Integer> stack = new Stack<>(); //int형 스택 선언
Stack<String> stack = new Stack<>(); //char형 스택 선언
Stack의 메서드
메서드 | 설명 |
boolean empty() | Stack이 비어있는지 알려준다. |
Object peek() | Stack의 맨 위에 저장된 객체를 반환. pop()과 달리 Stack에서 객체를 꺼내지는 않음. (비었을 때는 EmptyStackException발생) |
Object pop() | Stack의 맨 위에 저장된 객체를 꺼낸다. (비었을 때는 EmptyStackException 발생) |
Object push(Object item) | Stack에 객체(item)를 저장한다. |
int search(Object o) | Stack에서 주어진 객체(o)를 찾아서 그 위치를 반환. 못찾으면 -1을 반환 (배열과 달리 위치는 0이 아닌 1부터 시작) |
void clear() | Stack의 전체 값 제거 (초기화) |
boolean contains(Object o) | Stack에 o가 있는지 확인한다. |
int size() | Stack의 크기 |
큐 (Queue)
Queue의 메서드
메서드 | 설명 |
boolean add(Object o) | 지정된 객체를 Queue에 추가한다. 성공하면 true를 반환. IllegalStateException 발생. |
Object remove() | Queue에서 객체를 꺼내 반환. 비어있으면 NoSuchElementException 발생. |
Object element() | 삭제없이 요소를 읽어온다. peek와 달리 Queue가 비어있을 때 NoSuchElementException 발생. |
boolean offer(Object o) | Queue에 객체를 저장. 성공하면 true, 실패하면 false를 반환. |
Object poll() | Queue에서 객체를 꺼내서 반환. 비어있으면 null을 반환. |
Object peek() | 삭제없이 요소를 읽어 온다. Queue가 비어있으면 null을 반환. |
아스키 코드
아스키코드의 처음 32개(0~31)는 프린터나 전송 제어용으로 사용되고 나머지는 숫자와 로마글자 및 도량형 기호와 문장기호를 나타낸다. 아스키코드는 7자리의 2진코드인데 1비트의 패리티 비트를 추가하여 8비트로 많은 컴퓨터에 사용되고 있다.
65~90 (A~Z), 97~122 (a~z)
private static char changeAlphabet(char ch) {
// 65~90 (A~Z), 97~122 (a~z)
// 65 -> 90 , 66 -> 89
int changeAscii = (int)ch;
if (changeAscii >= 65 && changeAscii <= 90) {
return (char)(91 - (changeAscii - 64));
}
if (changeAscii >= 97 && changeAscii <= 122) {
return (char)(123 - (changeAscii - 96));
}
return ch;
}
HashMap
Map 인터페이스를 구현한 대표적인 컬렉션 클래스
HashMap map = new HashMap();
map.put("myId", "1234");
map.put("asdf", "1111");
map.put("asdf", "1234"); // 에러가 나는게 아니라 값을 덮어쓴다.
HashMap<String, Integer> map = new HashMap<>();
HashMap의 메서드
메서드 | 설명 |
Object put(Object key, Object value) | 지정된 키와 값을 HashMap에 저장 |
void putAll(Map m) | Map에 저장된 모든 요소를 HashMap에 저장 |
Object remove(Object key) | HashMap에 지정된 키로 저장된 값을 제거 |
Object replace(Object key, Object value) | 지정된 키의 값을 지정된 객체로 대체 |
Set entrySet() | HashMap에 저장된 키와 값을 엔트리(키와 값의 결합)의 형태로 Set에 저장해서 반환 |
Set keySet() | HashMap에 저장된 모든 키가 저장된 Set을 반환 |
Collection values() | HashMap에 저장된 모든 값을 컬렉션의 형태로 반환 |
Object get(Object key) | 지정된 키의 값을 반환. 못찾으면 null 반환 |
boolean containsKey(Object key) | HashMap에 지정된 키가 포함되어있는지 알려준다. |
boolean containsValue(Object value) | HashMap에 지정된 값이 포함되어있는지 알려준다. |
같은 key일 때, value에 list로 담기
- forms
[ ["jm@email.com", "제이엠"], ["jason@email.com", "제이슨"], ["woniee@email.com", "워니"], ["mj@email.com", "엠제이"], ["nowm@email.com", "이제엠"] ]
private static HashMap<String, ArrayList<String>> initHashMap(List<List<String>> forms) {
HashMap<String, ArrayList<String>> map = new HashMap<>();
for (List<String> form : forms) {
ArrayList<String> list = new ArrayList<>();
if (map.containsKey(form.get(1))) {
list = map.get(form.get(1));
list.add(form.get(0));
} else {
list.add(form.get(0));
}
map.put(form.get(1), list);
}
return map;
}
📌 Reference
- char배열과 String 클래스 출처: 자바의 정석
'프로젝트 개발 기록 > [개발] java | spring' 카테고리의 다른 글
[Java] 람다와 스트림 (Lambda & Stream) (0) | 2022.11.13 |
---|---|
[Java] 코딩테스트 대비 정리 (2) (0) | 2022.11.07 |
[IntelliJ] project마다 JDK 버전 관리하기 (0) | 2022.10.25 |
[Java] 예외처리 (1) | 2022.10.23 |
댓글