개요
Collection은 객체들을 효율적으로 저장하고 관리하는 자료구조다.
자바 내에서 다양한 자료구조를 사용할 수 있는 모음집이라고 볼 수 있다.
List, Set, Map등의 interface를 통해 다수의 데이터를 쉽게 처리하는 방법을 제공한다.
Collection 주요 메서드
- add(E e) : 컬렉션에 요소 e를 추가하고, 성공하면 true를 반환한다.
- remove(Object o) : 컬렉션에서 요소 o를 제거하고, 제거되면 true를 반환한다. 요소가 없으면 false를 반환한다.
- contains(Object o) : 컬렉션에 요소 o가 존재하면 true, 없으면 false를 반환한다.
- isEmpty() : 컬렉션이 비어 있으면 true, 하나 이상의 요소가 있으면 false를 반환한다.
- size() : 컬렉션의 요소 개수를 정수로 반환한다.
- clear() : 컬렉션의 모든 요소를 삭제한다.
- iterator() : 컬렉션을 순회할 수 있는 Iterator 객체를 반환한다.
- toArray() : 컬렉션의 모든 요소를 포함하는 배열을 반환한다.
List
입력 순서가 있는 데이터의 집합이다.
입력 순서가 있으므로 데이터의 중복을 허락한다.
- add(E e) : 리스트 끝에 요소 e를 추가하고 true를 반환한다.
- add(int index, E e) : 지정된 인덱스에 요소 e를 삽입한다. 이후 요소들은 한 칸씩 뒤로 밀린다.
- get(int index) : 지정된 인덱스의 요소를 반환한다.
- set(int index, E e) : 지정된 인덱스의 요소를 e로 교체하고, 이전 요소를 반환한다.
- remove(int index) : 지정된 인덱스의 요소를 삭제하고, 삭제된 요소를 반환한다.
- remove(Object o) : 리스트에서 처음 발견된 요소 o를 삭제하고, 성공하면 true를 반환한다.
- indexOf(Object o) : 요소 o의 첫 번째 인덱스를 반환하고, 없으면 -1을 반환한다.
- lastIndexOf(Object o) : 요소 o의 마지막 인덱스를 반환하고, 없으면 -1을 반환한다.
- size() : 리스트의 요소 개수를 반환한다.
- isEmpty() : 리스트가 비어 있으면 true를 반환한다.
- contains(Object o) : 리스트에 요소 o가 포함되어 있으면 true를 반환한다.
- clear() : 리스트의 모든 요소를 제거한다.
- toArray() : 리스트의 모든 요소를 포함하는 배열을 반환한다.
- sort(Comparator<? super E> c) : 지정된 비교자를 사용해 리스트를 정렬한다.
- subList(int fromIndex, int toIndex) : fromIndex부터 toIndex까지의 부분 리스트를 반환한다.
import java.util.List;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws Exception {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(0, 4);
System.out.println(list);
System.out.println("리스크 크기 : " + list.size());
System.out.println("3은 " + list.indexOf(3) + "번째 인덱스에 있다.");
System.out.println("2번째 인덱스의 값은 " + list.get(2) + "이다.");
list.sort(Integer::compareTo);
System.out.println(list);
if (list.contains(4)) System.out.println("리스트에 4가 포함되어 있다.");
else System.out.println("리스트에 4가 포함되어 있지 않다.");
list.clear();
if (list.isEmpty()) System.out.println("리스트가 빈 상태이다.");
else System.out.println("리스트가 비지 않은 상태이다.");
}
}
배열과 ArrayList
배열은 가장 근본적인 형태의 자료 구조로 간단하며 사용이 쉽다.
또한 접근 속도가 빨라 고정된 크기의 데이터의 경우 연산 처리에 유리하다.
단, 크기를 변경할 수 없어 추가 데이터를 위해 새로운 배열을 만들고 복사해야 한다.
또한 연속된 메모리 공간을 사용하기에 비 순차적인 데이터의 추가, 삭제에 많은 시간이 걸린다.
ArrayList 또한 내부를 까보면 배열을 사용하는 구조이기 때문에 태생적으로 배열의 장-단점을 그대로 가진다.
배열은 int와 char과 같은 기본 탕비과 객체 타입을 모두 사용할 수 잇다.
ArrayList는 객체만 저장할 수 있어 기본형 타입을 사용하려면 Wrapper 클래스를 사용해야 한다.
LinkedList
LinkedList는 자바에서 제공하는 List 인터페이스의 구현 클래스 중 하나로, 연결 리스트 자료구조를 기반으로 한다. ArrayList와는 다르게 요소들을 노드라는 객체로 연결하여 저장하는 방식이다.
LinkedList는 각 요소를 Node라는 객체로 저장한다. 각 노드는 데이터와 함께 다음 노드에 대한 참조(포인터)를 가지고 있으며, 두 가지 형태의 연결 리스트가 있다.
- 단일 연결 리스트: 각 노드는 다음 노드만을 참조한다.
- 이중 연결 리스트: 각 노드는 이전 노드와 다음 노드를 모두 참조한다.
ArrayList는 배열의 크기를 변경할 때 시간이 걸리지만, LinkedList는 요소 간의 참조만 변경하면 되므로 삽입과 삭제가 빠르다. 그래서 중간에 삽입/삭제가 빠르고 효율적이다.
LinkedList는 특정 인덱스를 찾아가는 데 시간이 걸리므로, 순차 탐색이 필요하다. 반면, ArrayList는 배열 인덱스를 사용하여 빠르게 접근할 수 있다.
- get(int index): LinkedList는 O(n) 시간이 걸린다. 요소에 순차적으로 접근해야 하기 때문이다.
- add(E e): 요소 추가 시 일반적으로 O(1)이지만, 리스트의 중간에 삽입하는 경우는 O(n) 시간이 걸릴 수 있다.
LinkedList는 각 요소마다 참조(포인터)를 저장해야 하므로 ArrayList보다 더 많은 메모리를 사용한다.
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
// 요소 추가
list.add("Apple");
list.add("Banana");
list.add("Orange");
// 요소 출력
System.out.println(list.get(0)); // 출력: Apple
// 중간에 요소 삽입
list.add(1, "Grape");
System.out.println(list.get(1)); // 출력: Grape
// 요소 삭제
list.remove("Banana");
System.out.println(list); // 출력: [Apple, Grape, Orange]
// 리스트 크기
System.out.println("Size: " + list.size()); // 출력: Size: 3
// 리스트 비었는지 확인
System.out.println("Is empty: " + list.isEmpty()); // 출력: Is empty: false
// 첫 번째 요소 삭제
list.removeFirst();
System.out.println(list); // 출력: [Grape, Orange]
}
}
C++을 통해 직접 포인터를 제어하는 연결 리스트 구현보다는 아주 양반이다.
정적인 데이터 활용, 단순한 데이터 조회용은 ArrayList가 유리하다.
반면 동적인 데이터 추가, 삭제가 많은 작업은 LinkedList가 유리하다.
Set
Set은 중복되지 않는 요소들만 저장하는 자바의 컬렉션 인터페이스 중 하나다.
Set은 List와 다르게 순서가 보장되지 않으며, 중복된 값을 허용하지 않는다.
Set 인터페이스를 구현한 주요 클래스에는 HashSet, LinkedHashSet, TreeSet 등이 있다.
1. 종류
- HashSet: 순서를 보장하지 않는다. 데이터를 저장할 때 해시 값을 기반으로 저장되며, 순서가 중요한 경우 적합하지 않다.
- LinkedHashSet: 순서를 보장한다. 삽입된 순서대로 요소를 순차적으로 출력할 수 있다.
- TreeSet: 자연 순서(또는 Comparator에 의한 순서)대로 요소를 저장한다.
2. 주요 특징
- 중복 허용 안 함: Set에 중복된 요소를 추가하면, 이미 존재하는 요소는 추가되지 않는다.
- null 값 허용: Set은 한 개의 null 값을 허용한다. 하지만 HashSet에서만 null이 허용되고, TreeSet에서는 null을 저장할 수 없다.
- 성능: HashSet은 빠른 검색과 삽입 성능을 제공하며, TreeSet은 정렬된 데이터를 제공하지만 성능이 다소 떨어질 수 있다.
3. 주요 메서드
- add(E e): 요소를 Set에 추가한다. 이미 존재하는 요소가 있으면 추가되지 않는다.
- remove(Object o): 지정된 요소를 Set에서 제거한다.
- contains(Object o): 지정된 요소가 Set에 포함되어 있는지 확인한다.
- size(): Set의 크기를 반환한다.
- isEmpty(): Set이 비어 있는지 확인한다.
- clear(): Set의 모든 요소를 제거한다.
- iterator(): Set의 요소를 순차적으로 접근할 수 있는 Iterator를 반환한다.
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
// 요소 추가
set.add("Apple");
set.add("Banana");
set.add("Orange");
// 중복된 요소는 추가되지 않음
set.add("Apple");
// Set의 크기
System.out.println("Size: " + set.size()); // 출력: Size: 3
// 요소 확인
System.out.println("Contains Banana: " + set.contains("Banana")); // 출력: Contains Banana: true
// 요소 제거
set.remove("Orange");
// Set 출력
System.out.println(set); // 출력: [Banana, Apple]
// 비어있는지 확인
System.out.println("Is Empty: " + set.isEmpty()); // 출력: Is Empty: false
// 모든 요소 제거
set.clear();
// 비어있는지 확인
System.out.println("Is Empty: " + set.isEmpty()); // 출력: Is Empty: true
}
}
Map
Map은 키-값 쌍(key-value pair)으로 데이터를 저장하는 자바의 컬렉션 인터페이스다.
Map은 중복된 키를 허용하지 않으며 각 키는 고유해야 한다. (값(value)은 중복될 수 있다.)
Map은 순서를 보장하지 않지만, 이를 구현한 구체적인 클래스에서 순서 보장 여부가 달라질 수 있다.
1. 종류
- HashMap : 순서를 보장하지 않으며, 빠른 성능을 제공한다.
- LinkedHashMap : 삽입된 순서를 유지한다.
- TreeMap : 키를 자연 순서대로 정렬하거나, 지정된 Comparator에 따라 정렬한다.
2. 주요 특징
- 키(Key): 중복되지 않는 고유한 값이다.
- 값(Value): 중복될 수 있는 데이터로, 키에 대응하는 값을 저장한다.
- 순서 보장 여부:
- HashMap: 순서를 보장하지 않는다.
- LinkedHashMap: 삽입 순서대로 순서를 보장한다.
- TreeMap: 자연 순서나 지정된 Comparator에 의해 키가 정렬된다.
3. Map 인터페이스의 주요 메서드
- put(K key, V value): 주어진 키에 해당하는 값을 Map에 추가하거나, 이미 존재하면 값을 덮어쓴다.
- get(Object key): 주어진 키에 해당하는 값을 반환한다. 키가 없으면 null을 반환한다.
- remove(Object key): 주어진 키에 해당하는 값을 제거한다.
- containsKey(Object key): 주어진 키가 Map에 존재하는지 확인한다.
- containsValue(Object value): 주어진 값이 Map에 존재하는지 확인한다.
- size(): Map의 크기(키-값 쌍의 개수)를 반환한다.
- isEmpty(): Map이 비어 있는지 확인한다.
- clear(): Map의 모든 요소를 제거한다.
- keySet(): Map의 모든 키를 Set으로 반환한다.
- values(): Map의 모든 값을 Collection으로 반환한다.
- entrySet(): Map의 모든 키-값 쌍을 Set 형태로 반환한다.
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// HashMap 생성
Map<String, Integer> map = new HashMap<>();
// 요소 추가
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);
// 키로 값 가져오기
System.out.println("Apple: " + map.get("Apple")); // 출력: Apple: 1
// 키 존재 여부 확인
System.out.println("Contains Banana: " + map.containsKey("Banana")); // 출력: Contains Banana: true
// 값 존재 여부 확인
System.out.println("Contains value 3: " + map.containsValue(3)); // 출력: Contains value 3: true
// 모든 키 출력
System.out.println("Keys: " + map.keySet()); // 출력: Keys: [Apple, Banana, Orange]
// 모든 값 출력
System.out.println("Values: " + map.values()); // 출력: Values: [1, 2, 3]
// 크기 확인
System.out.println("Size: " + map.size()); // 출력: Size: 3
// 요소 제거
map.remove("Banana");
// 삭제 후 상태 확인
System.out.println("Contains Banana after removal: " + map.containsKey("Banana")); // 출력: Contains Banana after removal: false
// 모든 키-값 쌍 출력
System.out.println(map.entrySet());
}
}
정렬
자바에서 정렬은 데이터를 특정 기준에 맞게 순서를 바꾸는 과정이다.
자바에서 제공하는 정렬 방법은 다양한 자료 구조와 메서드를 사용하여 데이터를 정렬할 수 있다.
1. 배열 정렬
자바에서 배열을 정렬하려면 Arrays 클래스를 사용한다. Arrays.sort() 메서드는 기본적으로 오름차순으로 배열을 정렬한다.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] arr = {5, 2, 9, 1, 3};
Arrays.sort(arr); // 오름차순 정렬
System.out.println(Arrays.toString(arr)); // 출력: [1, 2, 3, 5, 9]
Arrays.sort(arr, Collections.reverseOrder()); // 내림차순 정렬
System.out.println(Arrays.toString(arr)); // 출력: [9, 5, 3, 2, 1]
}
}
- 기본적으로 오름차순으로 정렬된다.
- 내림차순 정렬은 Comparator를 사용해야 한다.
2. 리스트 정렬
리스트의 정렬은 Collections.sort() 메서드를 사용한다. 기본적으로 오름차순으로 정렬된다. 내림차순 정렬도 가능하다.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(5);
list.add(2);
list.add(9);
list.add(1);
list.add(3);
Collections.sort(list); // 오름차순 정렬
System.out.println(list); // 출력: [1, 2, 3, 5, 9]
Collections.sort(list, Collections.reverseOrder()); // 내림차순 정렬
System.out.println(list); // 출력: [9, 5, 3, 2, 1]
}
}
3. 사용자 정의 정렬 (Comparator)
자바에서 객체를 정렬하려면 Comparator 인터페이스를 구현해야 한다. 사용자 정의 객체를 정렬할 때 이 인터페이스를 사용하여 정렬 기준을 정의할 수 있다.
import java.util.*;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return Integer.compare(p1.age, p2.age); // 나이 오름차순 정렬
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
Collections.sort(people, new AgeComparator()); // 나이 기준으로 정렬
System.out.println(people); // 출력: [Bob (25), Alice (30), Charlie (35)]
}
}
4. Lambda를 활용한 정렬
자바 8 이후, Comparator를 구현할 때 람다식(Lambda)을 사용할 수 있다. 람다식을 사용하면 정렬 기준을 더 간결하게 표현할 수 있다.
import java.util.*;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
// 람다식을 사용한 정렬 (나이 기준 오름차순)
people.sort((p1, p2) -> Integer.compare(p1.age, p2.age));
System.out.println(people); // 출력: [Bob (25), Alice (30), Charlie (35)]
}
}
5. Stream을 이용한 정렬
자바 8부터 제공되는 Stream을 사용하여 컬렉션을 정렬할 수 있다. Stream API를 사용하면 데이터를 더욱 선언적이고 함수형 스타일로 다룰 수 있다.
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(5, 2, 9, 1, 3);
// Stream을 이용한 오름차순 정렬
List<Integer> sortedList = list.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedList); // 출력: [1, 2, 3, 5, 9]
// 내림차순 정렬
List<Integer> reverseSortedList = list.stream()
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
System.out.println(reverseSortedList); // 출력: [9, 5, 3, 2, 1]
}
}
복잡한 커스텀 정렬
C++ 처럼 구조체 내부에서 operator을 통한 복잡한 커스텀 정렬을 하려면 어떻게 해야할까?
예를 들면 정수형 변수 3개를 우선 순위를 주고 싶을때 말이다.
이 또한 람다식으로 표현할 수 있다.
import java.util.*;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 30));
people.add(new Person("David", 25));
// 나이 기준으로 먼저 정렬하고, 나이가 같으면 이름으로 정렬
Comparator<Person> customComparator = (p1, p2) -> {
// 나이를 기준으로 정렬
int ageComparison = Integer.compare(p1.age, p2.age);
if (ageComparison != 0) {
return ageComparison; // 나이가 다르면 나이 기준으로 정렬
}
// 나이가 같으면 이름을 기준으로 정렬
return p1.name.compareTo(p2.name);
};
// 커스텀 Comparator로 정렬
people.sort(customComparator);
System.out.println(people); // 출력: [Bob (25), David (25), Alice (30), Charlie (30)]
}
}
- Integer.compare(p1.age, p2.age): age 값을 비교하여 정렬.
- p1.name.compareTo(p2.name): age가 같으면 이름을 기준으로 정렬.
thenComparing() 메서드를 활용한다면 여러 기준으로 정렬을 더 간결하게 할 수 있다.
thenComparing() 메서드를 체이닝하여 보조 정렬 기준을 설정할 수 있다.
import java.util.*;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 30));
people.add(new Person("David", 25));
// 나이 기준으로 정렬하고, 나이가 같으면 이름 기준으로 정렬
Comparator<Person> customComparator = Comparator
.comparingInt(Person::getAge) // 나이로 오름차순 정렬
.thenComparing(Person::getName); // 나이가 같으면 이름으로 오름차순 정렬
people.sort(customComparator);
System.out.println(people); // 출력: [Bob (25), David (25), Alice (30), Charlie (30)]
}
}
'웹(WEB) > 자바(Java)' 카테고리의 다른 글
[Java] 자바 Stream API (1) | 2024.12.31 |
---|---|
[Java] 자바 람다 Lambda (0) | 2024.12.31 |
[Java] 자바 annotation (0) | 2024.12.31 |
[Java] 자바 Enum (0) | 2024.12.31 |
[Java] 자바 Generics (0) | 2024.12.30 |