수업내용/Java

[2022.10.05.수] 콜렉션(List<E>)

주니어주니 2022. 10. 5. 19:49

 

 

2. 콜렉션 

2-2. Collection의 주요 하위 인터페이스 

 

2) List<E> 인터페이스의 구현클래스 

 

 

  • ArrayList<E>
    • 가장 많이 사용되는 List<E> 인터페이스의 구현 클래스
    • 0번째부터 차례대로 저장하기, 0번째부터 차례대로 꺼내기 작업에 가장 적합
    • 내부적으로 가변길이 배열을 활용해서 객체에 자동으로 저장 
      • * ArrayList<E>의 주요 메소드 (=Vector<E>)

        - boolean      add(E e)                                         
        : 리스트의 맨 마지막에 새로운 객체 저장
        - void            add(int index, E e)                           
        : 리스트의 저장된 위치에 새로운 객체 추가
        : 해당 위치부터 맨 마지막 객체들이 전부 한칸씩 뒤로 이동
        - boolean      addAll(Collenction<? extends E> c) 
         : 리스트에 다른 콜렉션객체에 저장된 모든 객체가 저장
        - boolean      addAll(int index, Collection<? extends E> c)
        : 리스트의 지정된 위치에 다른 콜렉션객체에 저장된 모든 객체 추가 
        - void            clear()
        : 리스트에 저장된 모든 객체 삭제 
        - boolean      contains(Object o)
        : 리스트에 저장된 객체가 존재하면  true 반환
        - E                 get(int index)
        : 리스트에서 지정된 위치에 저장된 객체 반환
        - boolean      isEmpty()
        : 리스트가 비어있으면 true 반환
        - Iterator<E> iterator()
        : 리스트에 저장된 객체를 반복처리하는 Iterator객체 반환
        - boolean      remove(Object o)
        : 리스트에서 지정된 객체 삭제
        - E                remove(int index)
        : 리스트에서 지정된 위치에 저장된 객체 삭제
        - E                 set(int index, E e)
        : 리스트에서 지정된 위치의 객체를 새 객체로 교체
        - int               size()
        : 리스트에 저장된 객체의 개수를 반환
  • LinkedList<E>
    • 중간에 객체를 삽입하거나, 중간에 저장된 객체를 삭제하는 일이 빈번한 경우에 사용하는 구현 클래스
      (속도가 빠름)  
    • 앞뒤 객체와 열차처럼 쌍방 연결 (한 객체에서 previous, next 연결) 
    • List<E> 인터페이스의 구현 클래스이면서, Queue<E> 인터페이스의 구현 클래스
      * Queue<E>는 FIFO(First-In First-Out) 자료구조를 표현하는 인터페이스 
    • LinkedList<E>의 FIFO 기능을 지원하는 메소드
      boolean offer(E item) : 리스트의 last element로 새로운 객체를 추가 
      E peek()                     : 리스트의 first element 반환 
      E poll()                       : 리스트의 first element를 삭제하고, 그 엘리먼트 반환 
    • *                          --------------       ----------------         ------------- 
      *                          |  |          |  |<----|- |         |  |   <----|- |        |  |
      *    E poll() <---    |  | 객체  |  |       |  | 객체 |  |         |  | 객체 |  |    <--- offer(E e)
      *                          |  |          | -|---->|  |         | -|---->   |  |         |  |
      *                           --------------       ----------------        -------------
  • Vector<E>
    • ArrayList<E>와 구현이 완전히 동일
    • ArrayList<E>는 Thread-unsafe하고, Vector<E>는 Thread-safe
  • Stack<E> 
    • FILO(First-In Last-Out) 자료구조를 구현한 객체
    • Stack<E>의 고유 기능을 지원하는 메소드
      E push(E item) : Stack에 새로운 객체를 저장
      E peek()           : Stack의 맨 꼭대기에 위치한 객체를 반환
      E pop()             : Stack의 맨 꼭대기에 위치한 객체를 삭제하고, 그 객체를 반환 

    •        *         E push(E item)        E pop()
             *                  |                         ∧
             *                  |                          |
             *                  ∨                         |
             *               ----------------------------
             *               |                              |
             *               ----------------------------
             *               |                              |
             *               ----------------------------
             *               |                              |
             *               ----------------------------
             *               |                              |
             *               ----------------------------

 

-ArrayList에 값 추가하고 출력하기

import java.util.ArrayList;

public class ListApp1 {

	public static void main(String[] args) {
		
		ArrayList<String> names = new ArrayList<>();
		names.add("홍길동");
		names.add("김유신");
		names.add("홍길동");
		names.add("강감찬");
		names.add("홍길동");
		names.add("이순신");
		names.add("홍길동");
		names.add("류관순");
		
		for(String name : names) {
			System.out.println("이름: "+name);	
		}
	}
}

 

이름: 홍길동
이름: 김유신
이름: 홍길동
이름: 강감찬
이름: 홍길동
이름: 이순신
이름: 홍길동
이름: 류관순

 

-ArrayList 메소드 이용해보기 

import java.util.ArrayList;

public class ListApp2 {

	public static void main(String[] args) {
		
		ArrayList<String> names = new ArrayList<>();	// ArrayList를 Vector로 바꿔도 똑같음
		
		// boolean add(E e)를 사용해서 리스트에 객체 추가하기
		names.add("홍길동");
		names.add("김유신");
		names.add("강감찬");		// String객체만의 특징(toString안써도 됨) 
		System.out.println(names);	// 향상된for문으로도 출력가능
		
		// void add(int index, E e)를 사용해서 리스트에 객체 추가하기
		names.add(1,"류관순");
		System.out.println(names);
		
		// E get(int index)를 사용해서 리스트에 저장된 객체 조회하기
		System.out.println(names.get(0));
		System.out.println(names.get(1));
		System.out.println(names.get(2));
		System.out.println(names.get(3));
		
		// E set(int index, E e)를 사용해서 리스트에 저장된 객체 교체하기
		names.set(2, "윤봉길");
		System.out.println(names);
		
		// void clear()를 사용해서 리스트에 저장된 객체 삭제하기
		names.clear();
		System.out.println(names);
	}
}

 

[홍길동, 김유신, 강감찬]
[홍길동, 류관순, 김유신, 강감찬]
홍길동
류관순
김유신
강감찬
[홍길동, 류관순, 윤봉길, 강감찬]
[]

 

 

-stack 메소드 이용해보기

import java.util.Stack;

public class ListApp3 {

	public static void main(String[] args) {
		Stack<String> stack = new Stack<>();
		
		stack.push("홍길동1");
		stack.push("홍길동2");
		stack.push("홍길동3");
		stack.push("홍길동4");
		stack.push("홍길동5");
		System.out.println(stack);
			
		String name1 = stack.pop();	// pop메소드의 반환값 = String
		System.out.println(name1);
		System.out.println(stack);
		
		String name2 = stack.pop();	// pop메소드의 반환값 = String
		System.out.println(name2);
		System.out.println(stack);
		
		String name3 = stack.pop();	// pop메소드의 반환값 = String
		System.out.println(name3);
		System.out.println(stack);
		
		String name4 = stack.pop();	// pop메소드의 반환값 = String
		System.out.println(name4);
		System.out.println(stack);
		
		String name5 = stack.pop();	// pop메소드의 반환값 = String
		System.out.println(name5);
		System.out.println(stack);	
	}
}

 

[홍길동1, 홍길동2, 홍길동3, 홍길동4, 홍길동5]
홍길동5
[홍길동1, 홍길동2, 홍길동3, 홍길동4]
홍길동4
[홍길동1, 홍길동2, 홍길동3]
홍길동3
[홍길동1, 홍길동2]
홍길동2
[홍길동1]
홍길동1
[]

 

 


 

 

 

3) Iterator<E>

 

  • 인터페이스이다.
  • 콜렉션에 대한 반복작업을 수행하는 객체들이 구현할 기능이 정의되어 있다.
  • 향상된 for문이 제공되기 전까지 콜렉션에 저장된 객체들을 반복처리할 때 Iterator<E> 구현객체를 사용했다.
  • 주요 메소드
    • boolean hasNext()   : 반복처리할 객체가 남아 있으면 true 반환, false가 나올 때까지 반복
      E           next()          : 객체를 꺼낸다
      void       remove()     : 이번 반복작업에서 다루고 객체를 삭제

  • Iterator<E> 인터페이스의 구현객체를 획득하는 방법
    • Collection<E> 인터페이스를 구현한 모든 자료구조 구현 객체는
      Iterator<E> 구현 객체를 제공하는 iterator() 메소드가 있다.

 

 

-

import java.util.ArrayList;
import java.util.Iterator;

public class ListApp1 {

	public static void main(String[] args) {
		
		ArrayList<String> names = new ArrayList<>();
		names.add("홍길동");
		names.add("김유신");
		names.add("홍길동");
		names.add("강감찬");
		names.add("홍길동");
		names.add("이순신");
		names.add("홍길동");
		names.add("류관순");
		
		Iterator<String> itr = names.iterator();
		
		while(itr.hasNext()) {
			String name = itr.next();
			System.out.println(name);
		}
	}
}

 

홍길동
김유신
홍길동
강감찬
홍길동
이순신
홍길동
류관순

 

 

 

 

import java.util.Iterator;
import java.util.Set;

public class SetApp1 {

	public static void main(String[] args) {
		
		Set<String> names = Set.of("이순신", "김유신", "강감찬", "류관순", "윤봉길");	//간단하게 Set을 만들 떄
		Iterator<String> itr = names.iterator();	// iterator의 반환값이 Iterator인데, 우리가 String을 다루고 있으니까 <String>
		
		System.out.println(itr.hasNext());
		System.out.println(itr.next());		// set이니까 순서는 없음(다음 객체 아무거나 반환)
		System.out.println(itr.hasNext());
		System.out.println(itr.next());
		System.out.println(itr.hasNext());
		System.out.println(itr.next());
		System.out.println(itr.hasNext());
		System.out.println(itr.next());
		System.out.println(itr.hasNext());
		System.out.println(itr.next());
		System.out.println(itr.hasNext());
		System.out.println(itr.next());
				
	}
}

 

true
강감찬
true
류관순
true
윤봉길
true
김유신
true
이순신
false
Exception in thread "main" java.util.NoSuchElementException
	at java.base/java.util.ImmutableCollections$SetN$SetNIterator.next(ImmutableCollections.java:981)
	at day23.collection.iterator.SetApp1.main(SetApp1.java:24)

 

===> hasNext() : 반복할 객체가 남아 있으면 true, 반복할 객체가 없으면 false

===> true인 동안만 반복 

===> while문 필요 

 

 

 


 

 

4) while문

 

반복문

for문
          for ( 초기식; 조건식; 증감식 ) {
                   수행문;
          }
          for ( 타입 변수명 : 배열혹은콜렉션 ) { 
                   수행문;
          }

 

 

  • while ( 조건식 )  { 
               수행문;
    }
  • 조건식이 true로 판정되면 수행문을 실행
  • 조건식이 반복작업을 지속할지 여부를 결정
  • while문은 반복작업을 지속할지 여부를 알려주는 기능이 제공되는 객체에 대해서만 사용
  • 대표적인 객체
    • Iterator<E>            : boolean hasNext()                    반복처리할 객체가 남아있으면 true
                                       E             next()                         객체를 꺼낸다
    • Enumeration<E>  : boolean hasMoreElements()   반복처리할 요소(객체)가 남아있으면 true
                                       E             nextElement()           요소를 꺼낸다
    • StringTokenizer    : boolean hasMoreTokens()      반복처리할 토큰(문자열)이 남아있으면 true
                                        String     nextToken()              토큰을 꺼낸다
    • ResultSet               : boolean next()                          반복처리할 행이 존재하면 true
                                        int          getInt(String columnName)  행에서 지정된 컬럼의 값을 꺼낸다
                                        long       getLong(String columnName)
                                        double   getDouble(String columnName)
                                        String    getString(String columnName)
                                        Date      getDate(String columnName)
    • 사용예) 

      List<Set> nameSet = new HashSet<>();
      // ~~ 객체를 추가하는 작업(nameSet.add)은 생략
      Iterator<String> itr = nameSet.iterator(); 
      while(itr.hasNext()) {
         String name = itr.next();

 

 

  • 반복작업 처리
    1) 향상된 for문 (거의 얘를 사용해)
    2) Iterator<E> 

    근데, 반복문 수행 중에 내가 원하는 객체를 삭제하고 싶다? -> 향상된 for문 불가 -> Iterator<E> 사용
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetApp1 {

	public static void main(String[] args) {
		
		Set<String> names = new HashSet<>();	
		names.add("김유신");
		names.add("강감찬");
		names.add("이순신");
		names.add("류관순");
		names.add("윤봉길");
		
		
		// 반복문 처리 1) 향상된 for문을 사용해서 반복작업 수행하기
		System.out.println("### 향상된 for문을 사용해서 콜렉션 객체에 저장된 객체들을 반복처리하기");
		for(String name : names) {
			System.out.println(name);
			// 향상된 for문 내부에서는 콜렉션에 저장된 객체를 절대로 삭제할 수 없다.
//			if(name.equals("김유신")) {
//				names.remove("김유신");
//			}
		}
		
		// 반복문 처리 2) Iterator<E> 객체를 획득해서 반복작업 수행하기 (훨씬 복잡함)
		System.out.println("### Iterator를 사용해서 콜렉션 객체에 저장된 객체들을 반복처리하기");
		Iterator<String> itr = names.iterator();
		while(itr.hasNext()) {
			String name = itr.next();
			System.out.println(name);
			// 콜렉션의 객체들을 반복처리하면서 특정 객체를 삭제할 수 있다.
			if(name.equals("김유신")) {
				itr.remove();
			}
		}
		System.out.println(names);
	}
}

 

### 향상된 for문을 사용해서 콜렉션 객체에 저장된 객체들을 반복처리하기
윤봉길
김유신
류관순
강감찬
이순신
### Iterator를 사용해서 콜렉션 객체에 저장된 객체들을 반복처리하기
윤봉길
김유신
류관순
강감찬
이순신
[윤봉길, 류관순, 강감찬, 이순신]

 

 

 

 

  • iterator()를 실행한 결과로 반환된 객체는 Iterator 인터페이스를 구현함 

 

HashSet<String> 객체가 만들어지고 그 안에 "string"들이 있음

이 Set객체 안에서 Iterator()를 실행하면, Iterator<String> 인터페이스를 구현한 객체가 반환됨

 

이 Iterator<String> 구현객체는 Iterator<String> 인터페이스를 가지고 있고, 그 안의 메소드들을 재정의 함

그리고 구현객체에서는 반복작업을 하니까, Set객체의 string 객체들의 주소값을 가지고 있을거야 

그러면 hasNext()를 실행했을 때, 내부적으로 return position < limit; 일때 true값 반환 이런식으로 실행

next()를 실행했을 때도 { String value = values[position];  position++;  return value; } 이런식으로

값을 증가시켜가면서 반환하는 기능이 구현되어 있을거야 

그래서 알아서 position을 증가시켜가면서 반복작업을 수행

 

 

 

그리고, 

iterator()를 실행하면 인터페이스를 구현한 객체가 나와야되는데, 반환타입이 Iterator 이니까,

실제로는 참조변수 iter가 Iterator 인터페이스를 바라보고 있음 ( 클래스 형변환 )

이때 iterator의 메소드를 실행하면, 재정의된 메소드가 실행 

 

따라서, 우리는 구현클래스의 구체적인 이름을 몰라도 됨

( 어차피 인터페이스로 클래스 형변환 될거고, 메소드 재정의가 자동으로 실행되니까 ) 

 

 

 

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListApp1 {

	public static void main(String[] args) {
		
		List<String> names = new ArrayList<>();
		
		names.add("홍길동");
		names.add("김유신");
		names.add("홍길동");
		names.add("강감찬");
		names.add("홍길동");
		names.add("이순신");
		names.add("홍길동");
		names.add("류관순");
		names.add("김유신");
		
		Iterator<String> itr = names.iterator();
		
		while(itr.hasNext()) {
			String name = itr.next();
			System.out.println(name);
		}
	}
}

 

홍길동
김유신
홍길동
강감찬
홍길동
이순신
홍길동
류관순
김유신

 

 

* 배열/콜렉션에 대한 반복작업 처리할 때

1순위)
             향상된 for문 사용


2순위)
            <삭제작업을 할 때>
            Iterator 사용
            (반복작업을 처리하면서 콜렉션에 저장된 객체를 삭제해야 되는 경우에만!  - for문에서는 삭제가 안됨) 

            <index를 사용해야 할 때> (Set<E> 구현객체는 사용불가 - index가 없어서 몇번째인지 알 수 없어) 
            for문

 

List는 향상for문, iterator, index 모두 쓸 수 있음 (순서도 있음)

Set은 향상for문, iterator만 사용 가능

 

 

 


 

 

 

2-3. Null 체크

 

* 콜렉션

- 인덱스, 배열크기 신경 안써도 됨 (자동으로 설정) 

- n개의 배열크기가 있을 때, 배열은 값이 없는 것(null값)까지 꺼내오는데,

  얘는 실제 값이 들어있는 값까지만 꺼냄  -> null값 검사 필요 x 

 

 

* null 체크를 이렇게 해도 됨!

if(customer != null) {
    수행문 실행 ~~
}   else if {
    "[오류] 존재하지 않습니다."

 

 

* null 체크

1) 반환타입이 기본자료형

public int method() { ... }
int value = x.method();
System.out.println(value);

* null이 반환되지 않음



2) 반환타입이 참조자료형이고 객체 하나가 반환된다.

public Book method() { ... }
Book obj = x.method();

* obj는 null을 가질 수 있다. ( 객체 하나가 반환되거나, null이 반환되거나 이니까 ) 
* obj는 Book객체의 참조값을 가질 수 있다.

if( obj != null ) {
    System.out.println(obj.getTitle());
} else { 
     System.out.println("책정보가 존재하지 않습니다.");




3) 반환타입이 참조자료형이고, 콜렉션(List, Set, Map)이 반환된다. (객체가 여러개)

public List<Book> method() { ... } 
List<Book> book = x.method(); 

* book은 절대로 null이 반환되게 하지 않는다. (null 값을 가지지 않는다.)
( 배열은 값이 들어있지 않은 객체(null)까지 반환하지만, 콜렉션은 값이 들어있는 객체만 반환하기 때문 ) 
*
따라서 null값이 아닌, 콜렉션이 비어있는지를 확인 

if( !books.isEmpty ) {                         ---> 비어있지 않으면 
     for (Book book : books) { 
            System.out.println(book.getTitle());
     }
} else { 
     System.out.println("책정보가 존재하지 않습니다.");