오늘의 학습은???
Collection!!
Collection
- 사전적의미 : 요소를 수집하여 저장하는 것!
// 길이 10인 배열 생성
Product[] productArray = new Product[10];
// 객체 추가
productArray[0] = new Product("상품0");
productArray[1] = new Product("상품1");
productArray[2] = new Product("상품2");
// 객체 검색
Product model0 = productArray[0];
Product model1 = productArray[1];
Product model2 = productArray[2];
// 객체 삭제
productArray[0] = null;
productArray[1] = null;
productArray[2] = null;
이렇게 배열 생성, 추가, 검색, 삭제 등 쉽게 사용이 가능하지만
특정 지어져있지 않고 무수한 객체를 저장하기엔 문제가 존재한다.
배열의 크기를 처음부터 크게 설정하는것 또한 좋은 방법이 아닐 뿐더러
중간에 있는 객체를 삭제했을 때 듬성듬성 비어버리기 때문에 그곳에 새로운 객체를 넣을려면
어느 곳곳이 비었는지 알 수 있어야한다!
그림으로 보면

요렇게! 인덱스 5 객체를 삭제했을 때 비어버린곳을 찾을려면 코드가 필요함!!
이렇게 문제점이 발생하는데 이것을 해결하기 위해 추가 삭제 검색 등을
효율적으로 할 수 있도록 java.util 패키지에 컬렉션과 인터페이스, 클래스를 포함시켜놓은것이 컬렉션이라고 한다.

List 와 Set 의 경우 인터페이스들의 공통된 메소드만 모아 컬렉션 인터페이스로 정의하는 방법이 공통점을 지니고 있지만
Map은 키와 값을 하나의 쌍으로 묶어서 관리하는 구조이므로 두개와 사용방법이 많은 차이가 존재한다.

List - ArrayList, LinkedList
List의 경우 배열과 같은 특징인 객체를 일렬로 늘어놓은 구조를 가지고 있지만
배열과는 다르게 자료형의 개수가 계속 변하는 상황에서 유리한 자료구조 형태로 되어있는것이 List!!!
음.. 그러니깐 배열과 똑같은 일렬식이지만
배열은 선언시점에 크기를 결정하기에 무수한 객체를 넣을땐 선언이 어려운 단점이 있는 반면,
List는 개수가 계속 변하는 상황에서 유리하게 자료구조의 형태가 바뀐다는 건가???

그림으로 보니 확실히 선언부터 정해지는 배열보다는 특정 수가 정해져있지않다면 유리하다는 생각이 드네영

List<String> list = ...;
list.add("홍길동");
list.add(1, "삼길동");
String str = list.get(1);
list.remove(0);
list.remove("삼길동");
< List 컬렉션에 저장되는 타입을 제네릭을 이용하여 String으로 정하고 추가 검색 삭제하는 코드 >
여기서 반복해서 저장된 객체를 얻고 싶으면
당연히 반복문인 for문을 사용할 수 있겠졍? ㅎㅎㅎ
< List 컬렉션에서 공통적으로 사용 가능한 List 인터페이스 메소드 >
|
기능
|
메소드
|
설명
|
|
객체 추가
|
boolean add(E e)
|
주어진 객체를 맨 끝에 추가
|
|
|
void add(int index, E element)
|
주어진 인덱스에 객체를 추가
|
|
|
set(int index, E element)
|
주어진 인덱스에 저장된 객체를 주어진 객체로 바꿈
|
|
객체 검색
|
boolean contains(Object o)
|
주어진 객체가 저장되어있는지 여부
|
|
|
E get(int index)
|
주어진 인덱스에 저장된 객체를 리턴
|
|
|
isEmpty()
|
컬렉션이 비어있는지 여부
|
|
|
int size()
|
저장되어 있는 전체 객체 수 리턴
|
|
객체 삭제
|
void clear()
|
저장된 모든 객체를 삭제
|
|
|
E remove(int index)
|
주어진 인덱스에 저장된 객체를 삭제
|
|
|
boolean remove(Object o)
|
주어진 객체를 삭제
|
ArrayList
- List 인터페이스의 구현 클래스
일반 배열과 ArrayList는 인덱스로 객체를 관리한다는 점에서는 동일하지만
큰 차이점으론 배열은 선언 시 크기를 정해놓고 사용중엔 그 크기를 변경할 수 없지만
ArrayList는 저장용량이 초과한 객체가 들어올경우 자동적으로 저장 용량이 늘어난다.

이렇게 ArrayList를 생성하게 되면 초기용량으로 10개가 생성되는데 이때 저장 객체가 초과했을 경우
자동으로 늘어난다고 보면된다!
당연히, 처음부터 크게 잡고 싶다면 크기를 매개값을 넣는 생성자를 이용하면 가능하다!
List<String> list = new ArrayList<String>(30);

객체를 추가할경우 0부터 차례로 저장되는데
그럼 만약 삭제하고 싶으면?
위 그림과 같이 4를 제거할경우 뒤에 인덱스 5번이 1씩 밀려나면서
5가 4가 되고 6이 5가 되는 식으로 밀려나게 된다.
이렇게 많은 추가 삭제가 되는 경우는 계속적으로 밀려나고 하기 때문에 ArrayList가 적합하지 않다!
하지만 인덱스 검색과, 마지막에 객체를 추가하는 경우라면 ArrayList가 성능이 더 좋다!

확실히 마지막추가는 인덱스 번호가 바뀔일 없으니
자동적으로 저장용량을 늘려주고 하니 검색과 마지막추가는 효율적일거 같다는 생각이 들네영!!! 오호
package Java_study.Collection;
import java.util.ArrayList;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// String 객체를 저장
list.add("Java");
list.add("Spring");
list.add("Servlet/JSP");
list.add("DBMS");
list.add("JPA");
int size = list.size();
System.out.println("총 객체 수: " + size);
System.out.println();
String skill = list.get(2);
System.out.println("Skill 2: " + skill);
System.out.println();
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
System.out.println(i + ": " + str);
}
System.out.println();
list.remove(2); // 2번 인덱스(Servlet/JSP) 삭제
list.remove(2); // 2번 인덱스(DBMS) 삭제
list.remove("Java");
for (int i = 0; i < list.size(); i++) { // 저장된 총 객체 수만큼 루핑
String str = list.get(i);
System.out.println(i + ": " + str);
}
}
}
코드로 ArrayList를 살펴봤을 때,
1. List에 객체를 저장하고
list.add("Java");
list.add("Spring");
list.add("Servlet/JSP");
list.add("DBMS");
list.add("JPA");
2. 총 객체 수와 스킬 2의 list.get(2) 인덱스 2의 저장되어있는 객체를 리턴하겠졍? JSP가 리턴될거고!
int size = list.size();
System.out.println("총 객체 수: " + size);
System.out.println();
String skill = list.get(2);
System.out.println("Skill 2: " + skill);
System.out.println();
3. 반복으로 0인덱스부터 4인덱스까지 저장한객체들이 출력되겠고!
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
System.out.println(i + ": " + str);
}
System.out.println();
4. 2번 인덱스인 JSP 삭제하고,
다시 2번 인덱스를 삭제해야하는데 Arraylist는 앞으로1씩 밀린다했으니
JSP가 삭제됐으므로 DBMS가 2번이 되었으니 DBMS 삭제
마지막, Java 0인덱스 삭제
list.remove(2); // 2번 인덱스(Servlet/JSP) 삭제
list.remove(2); // 2번 인덱스(DBMS) 삭제
list.remove("Java");
5. 나머지 삭제된 객체를 제외한 저장된 객체 수 만큼 출력될 테니
for (int i = 0; i < list.size(); i++) { // 저장된 총 객체 수만큼 루핑
String str = list.get(i);
System.out.println(i + ": " + str);
}
0: Spring 1: JPA 이렇게 출력된다!
<총 실행결과>
총 객체 수: 5
Skill 2: Servlet/JSP
0: Java
1: Spring
2: Servlet/JSP
3: DBMS
4: JPA
0: Spring
1: JPA
LinkedList
- ArrayList와 사용방법은 동일하지만 내부구조가 전혀 다르다.
인접 참조를 링크해서 체인 처럼 관리한다.

이게뭔말인교??????


???????? 체인같긴한데???????? ㅋㅋㅋㅋㅋ
LinkedList에서 특정 인덱스 객체를 제거하면 앞뒤 링크면 변경되고 나머지 링크는 변경되지 않는다.
삽입할때도 동일하다.
이 말은 이해가 가능한데/../ 그림 보고 더 복잡해진 점은 또 처음이네요?ㅋㅋㅋㅋ큐
그럼 ArrayList와 LinkedList를 10,000개를 삽입하는 비교를 했을 시, 누가 성능적으로
빠를까요?
실행결과만 말하면, LinkedList가 훨씬 빠릅니다.
생각만 하더라도 arraylist는 뒤에 있는 인덱스들이 전부 1씩 증가되거나 감소되기때문에 시간이 더 필요하겠졍?
앞뒤 링크만 변경되는 LinkedList가 훨씬 빠르다는걸 직감적으로도 알 수 있다! 실행결과도 동일하지만 ㅎㅎ
public class LinkedListExample {
public static void main(String[] args) {
List<String> arrayList = new ArrayList<>();
List<String> linkedList = new LinkedList<>();
long startTime;
long endTime;
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
arrayList.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.println("ArrayList 걸린시간: " + (endTime - startTime) + "ns");
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
linkedList.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.println("LinkedList 걸린시간: " + (endTime - startTime) + "ns");
}
}
<실행결과>
ArrayList 걸린시간: 12033500ns
LinkedList 걸린시간: 2997000ns
Set
HashSet
list는 저장순서가 유지되지만 Set은 저장순서가 유지되지 않는다.
또한, 객체를 중복해서 저장할 수 없다는 특징을 지닌다.
< Set 컬렉션에서 공통적으로 사용 가능한 Set 인터페이스의 메소드>
|
기능
|
메소드
|
설명
|
|
객체 추가
|
boolean add(E e)
|
주어진 객체를 저장, 객체가 성공적으로 저장되면 true를 리턴하고 중복 객체면 false를 리턴
|
|
객체 검색
|
boolean contains(Object o)
|
주어진 객체가 저장되어 있는지 여부
|
|
|
isEmpty()
|
컬렉션이 비어 있는지 조사
|
|
|
Iterator<E> iterator()
|
저장된 객체를 한 번씩 가져오는 반복자 리턴
|
|
|
int size()
|
저장되어 있는 전체 객체 수 리턴
|
|
객체 삭제
|
void clear()
|
저장된 모든 객체를 삭제
|
|
|
boolean remove(Object o)
|
주어진 객체를 삭제
|
set는 저장순서가 유지되지않으니 당연히 인덱스로 객체를 가져올 수 없다.
그리하여, 전체 객체를 대상으로 한번씩 반복해서 가져오는 반복자(iterator)를 제공한다.
호출
Set<String> set = ...;
Iterator<String> iterator = set.iterator();
Set<String> set = ...;
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) { // 저장된 객체 수만큼 루핑
String str = iterator.next(); // String 객체 하나를 가져옴
}
Iterator 에서 하나의 객체를 가져올때 next를 사용하는데, 사용 전 저장된 객체가 있는지 알기 위해서 has.next를 사용하여 가져올 객체 있는지 확인! 가져올 객체가 있을 시, true리턴 없을시, false 리턴!
Iterator를 사용하지 않더라도 for문으로 전체 객체대상을 반복할 수 있다.
set 인터페이스의 구현 클래스
Set<String> set = new HashSet<String>();
ArrayList와 동일하게 타입 파라미터에 저장할 객체타입을 지정하면 된다! String객체라면 String넣으면 되겠졍?

HashSet는 동일한 객체는 중복 저장하지 않는다고 했는데 동일한객체란 뭘까?
동일한 객체란 꼭 같은 인스턴스를 뜻하지 않고 저장 전 hashCode() 메소드를 호출해 해시코드를 얻어내 비교한다.
true일 시, 다시한번 equals로 객체를 비교하여 true가 나오면 동일한 객체로 판단하고 저장하지 않는다.
위와 같은 그림의 방식대로 절차가 진행된다.
public class HashSetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Spring");
set.add("Servlet/JSP");
set.add("Java");
set.add("DBMS");
System.out.println("총 객체수: " + set.size()); // 저장된 객체수 출력
Iterator<String> iterator = set.iterator(); // 반복자 얻기
while (iterator.hasNext()) { // 객체 수 만큼 루핑
String element = iterator.next(); // 한 개의 객체를 가져온다
System.out.println("\t" + element);
}
set.remove("DBMS"); // 한 개의 객체 삭제
set.remove("Java"); // 한 개의 객체 삭제
System.out.println("총 객체수: " + set.size());
iterator = set.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println("\t" + element);
}
set.clear(); // 모든 객체를 제거하고 비움
if (set.isEmpty()) {
System.out.println("비어있음");
}
}
}
<실행결과>

public class Member {
String name;
int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return name.hashCode() + age;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Member) {
Member member = (Member)obj;
return member.name.equals(this.name) && member.age == this.age;
} else {
return false;
}
}
}
package Java_study.Collection;
import java.util.HashSet;
import java.util.Set;
public class HashSetExample2 {
public static void main(String[] args) {
Set<Member> set = new HashSet<>();
set.add(new Member("홍길동", 30));
set.add(new Member("홍길동", 30)); // 인스턴스는 다르지만 내부 데이터가 동일하므로 객체 1개만 저장
System.out.println("총 객체수: " + set.size());
}
}
이렇게 hashCode와 equals로 동일한 객체를 확인하는 절차를 오버라이딩해서 메소드를 추가했는데
만약 메소드를 추가하지 않는다면?
실행결과는 총객체수 1 이아닌 2가 될것이다.
동일한 홍길동,30으로 내부데이터는 동일하지만 인스턴스가 다르기떄문에
객체둘다 저장된다.
이렇게 이름, 나이가 동일하다면 동일한 객체로 간주하여 저장되지 않는 것이 위 코드와 같이 오버라이딩으로 hashCode와 equals 메소드를 추가하는것이다.
이렇게 컬렉션에 대해 배웠는데엽!!
map이 남긴했지만
아직 덜 배웠기때문에 내일 한꺼번에 복습할 예정입니다!!!!
ㅎㅎㅎ 나름 오늘 수업은 재밌었던거같아요 ㅎㅎㅎ
linkedlist 그림 빼고..ㅋㅋㅋㅋㅋㅋ
ㅎㅎㅎ 오늘도,,,, sql 공부하러 떠나야겠네용 ㅠㅠㅠㅠㅠㅠ
한 3주 남았나... 파이팅.,..하장...
오늘도 파이팅했구욥!!!
내일도 공부 파이팅!!!!!!!!!!!!!!!!!!!!!!!!!

'[4기] 백엔드 개발자 부트캠프 "오르미" ~ing > [4기] 백엔드 개발자 부트캠프 오르미 수업 복습' 카테고리의 다른 글
| [4기] 49일차 Java ( 람다식2 , 스트림-필터링 ) (0) | 2024.02.19 |
|---|---|
| [4기] 46일차 Java ( Collection - Map, 람다식 ) (4) | 2024.02.16 |
| 일기) DailyQuiz9 (제네릭) (0) | 2024.02.14 |
| [4기] 44일차 Java ( 제네릭2 ) (2) | 2024.02.14 |
| [4기] 38일차 Java ( 예외처리3, 제네릭 ) (0) | 2024.02.08 |