자바프로그래밍 컬렉션 (1) List 종류

최주영·2023년 3월 27일
0

자바

목록 보기
15/30
post-thumbnail

✅ 빅오(O) 표기법

  • 데이터 양 증가에 따른 성능 변화 추세를 비교하는데 사용
  • 정확한 성능 측정 목표가 아닌 매우 큰 데이터가 들어왔을 때 대략적인 추세를 비교하는 것이 목적

위 표에서 배열에서 인덱스를 사용하는 경우 가 가장 이상적이며 (최고의 효율이 나옴)
인덱스를 사용할 수 있다면 최대한 활용하는 것이 좋다


✅ 배열의 문제점

  • 한번 크기를 지정하면 변경 x

  • 데이터에 대한 중간위치의 추가, 삭제가 불편하다.

  • 한 타입의 데이터만 저장 가능하다.


컬렉션

  • 자바에서 제공하는 자료구조를 담당하는 프레임워크

  • 추가, 삭제, 정렬 등의 기능처리가 간단히 해결되어 자료구조적 알고리즘을 구현할 필요 없음

  • java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용

  • 여러 타입의 데이터가 저장 가능하며 저장하는 크기의 제약이 없다


✅ (1) ArrayList

  • add 메소드 : 데이터를 리스트에 저장할 때 사용
    -> 방법 2가지
    (1) : 맨 마지막에 추가하는 방법
    (2) : 원하는 인덱스 위치에 추가하는 방법

ArrayList people = new ArrayList(); // 리스트 저장공간 만들어줌

people.add(new Person("유병승",19,'남',180.5,65.5));  // 값 저장할때 add메소드 사용 => 인덱스 알아서 늘려줌

people.add(2, new Person("최주영",26,'남',177.3,70.5)); // 2번째에 값추가하고 그 2번째부터 뒤로 자동으로 밀림



  • get 메소드 : 저장된 데이터 가져오기(호출하기)
    -> get 함수의 반환형은 Object
  • size 메소드 : 리스트 자료형 크기 반환 (int 형)
ArrayList people = new ArrayList();
System.out.println(people.get(0)); // 0번째 인덱스에 있는 값 가져오기

// 전체 출력 방법 3가지
// (1) : for문 + get()함수 + size()함수 사용
// people.get(i) 출력시 -> Person 클래스의 toString 함수가 출력됨
// Person 클래스의 toString 오버라이딩 함수가 없으면 Object의 toString이 호출되서 주소값 출력
		for(int i=0; i<people.size(); i++) {   
			Person p = (Person)people.get(i);  
			System.out.println(p.getName()+" "+p.getAge()+" "+p.getGender()+" "+
					p.getHeight()+" "+p.getWeight());
		}


// (2) : for-each 문
		for(Object o : people) {   	
			Person p = (Person)o;   
            // people 자체는 반환형이 Object 타입이기 때문에 왼쪽 오른쪽에 서로 Objcet로 맞춰준다
            // Person 안의 set,get함수 사용하기 위해서
			 // Object 타입을 Person 타입으로 형변환 시켜준다.
			System.out.println(p.getName()+" "+p.getAge()+" "+p.getGender()+" "+
						p.getHeight()+" "+p.getWeight());
		}


// (3) : for-each 메소드 사용
// forEach()는 Consumer라는 함수형 인터페이스를 인자로 받음
// Consumer 함수형 인터페이스 -> 1개의 인자를 받고 리턴값이 없는 accept() 메소드를 갖고 있음
// accept() -> 추상 메서드임
// Consumer은 단지 매개값을 소비하는 역할만 하며, 사용만하고 리턴값이 없음
// 밑에 사진 참고
// people의 toString() 오버라이딩 부분을 깔끔하게 수정해서 출력하면 잘 나온다.
		people.forEach((o)-> System.out.println(o));
        

        
        
// (4) : iterator() 메소드 사용 (Iterator 객체를 이용)
		Iterator it = people.iterator(); // 0번~마지막까지 모든 인덱스를 이터레이터 방식으로 뽑음
		while(it.hasNext()) {  // 다음 뽑을 객체가 있다면
			Person a = (Person)it.next(); // 그 다음값을 형변환해서 Person 객체로 형변환한 후
		  	System.out.println(a);  // 출력
//			System.out.println(it.next());  // it.next()를 두번 출력하면 데이터의 개수가 홀수 일 경우 
//			System.out.println(it.next());  // java.util.NoSuchElementException 예외가 발생
		}
        
        
((Person)people.get(0)).setAge(20); // 이와 같은 형변환 방식으로 값을 바꿀 수 있음



  • isEmpty()메소드 : 리스트에 데이터가 있는지 없는지 확인 + 데이터가 없으면 true 리턴
    -> isEmpty 반환형은 boolean 형임
	ArrayList people = new ArrayList();
		if(people.isEmpty()) { 
			System.out.println("사람 없어요~");
		}else {
			System.out.println("사람 있어요~");
		}
// 위 리스트에는 데이터가 없기 때문에 사람 없어요가 출력됨!

	//위 isEmpty 메소드와 비슷하게 사용할 수 있는 메서드 : size();
    	if(people.size() == 0) {  // isEmpty() 메소드와 기능 동일
			System.out.println("사람 없어요~");
		}

		if(people.size() > 0) {  // 1개이상 있다는 말 -> 비어있지 않다는 말
			System.out.println("사람 있어요~");
		}	

  • set 메소드 : 원하는 인덱스의 값을 수정하기
people.set(3, new Person("이동제",25,'남',175.3,68.3)); // 3번째 인덱스 값에 넣어버리고 원래있던 값은 삭제

  • remove 메소드
    -> 방법 2가지
    (1) : remove(index) -> 원하는 인덱스의 값을 삭제
    (2) : remove(Object o) -> 매개변수와 일치하는 값 삭제
people.remove(4); // 4번째 인덱스에 있는 값 삭제
// 해당 객체가 있는 위치의 인덱스에 있는 값 삭제
people.remove(people.indexOf(new Person("김두환",43,'남',188.2,95.5)));



// 매개변수와 일치하는 값 삭제하기
// remove(Object o) -> 대상 클래스에 equals, hashCode가 오버라이딩 되어있어야한다.
// 대상 Person 클래스안에 equals와 hashCode가 오버라이딩 되어있어야함
people.remove(new Person("주몽",58,'남',189.4,90.3)); // 해당 대상 삭제

  • contains 메소드 : 특정 객체가 리스트에 포함되어 있는지 확인하는 메소드
    -> boolean 형으로 반환 (포함 시 true)
// contains(Object) : boolean형으로 반환함
		if(people.contains(new Person("고길동",20,'남',175.5,70.5))) {
			System.out.println("이미 존재하는 사람입니다."); // 해당 고길동 정보들이 있을시 문구 출력
		}else {
			people.add(new Person("고길동",20,'남',175.5,70.5)); // 없으면 리스트의 마지막에 추가
		}

  • indexOf 메소드 : 동일한 객체를 찾아서 그 인덱스를 반환해주는 메소드
    -> int 형으로 반환 (해당 객체를 찾지 못하면 -1로 반환)
// indexOf(Object) -> 해당 객체를 못찾으면 -1로 리턴
int index = people.indexOf(new Person("선덕여왕",35,'여',150.2,50.5));

  • clear 메소드 : 저장된 데이터를 한번에 전체데이터 삭제하기
people.clear();

  • toArray 메소드 : ArrayList로 저장된 데이터를 배열로 변환해주는 메소드
    -> 반환형 : Object []
  • asList 메소드 : 배열을 List로 변환해주는 메소드
    -> 반환형 : List
		Object[] objArr = people.toArray(); // ArrayList가 배열로 변환됨
		boolean flag = false;
		for(int i=0; i<objArr.length; i++){
			if(objArr[i] != null) {
				flag = true;
			}
		}
		
		String msg = (flag == true) ? "사람있어요" : "사람없어요";
		System.out.println(msg);
        
        
        List people1 = Arrays.asList(objArr);  // 배열 objArr이 ArrayList로 변환됨

  • Collection 인터페이스
		// Collection, List 인터페이스는 부모타입으로
		// ArrayList 객체를 저장할 수 있다.
		Collection c; // = new Collection(); // 이런식으로 객체를 스스로 생성은 불가능함(인터페이스이므로)
		c = new ArrayList();

  • List 인터페이스
List intList = List.of(1, 2, 3, 4, 5); // 고정값임 (수정이 불가능함) = final

List animalList = List.of(new Animal(), new Animal(), new Animal());
		// animalList 배열의 주소값을 수정불가능한것이지, 안에있는 값들은 변경가능함
((Animal) animalList.get(0)).setName("햄찌"); // 이와 같이 안에 값들은 변경 가능

  • Comparator 인터페이스 : 순서가 없는 개체 컬렉션에 대한 순서를 제공하는 비교 기능
    -> 이 클래스의 구현자는 추상 메서드를 재정의 해야함!
		// 값을 비교할 기준을 정해줘서 Comparator을 재정의해줌
		// 1. Comparator를 구현한 클래스 생성하기
        
        foods.sort(new FoodPriceAes()); // FoodPriceAes 클래스를 통해서 가격을 기준으로 오름차순
		System.out.println("===== 정렬후 =====");
		for(Object o : foods) {
			System.out.println(o);
		}
        
        
        // FoodPriceAes 클래스  (가격 오름차순)
        public class FoodPriceAes implements Comparator{ // Comparator 인터페이스를 구현해야함
	
		@Override
		public int compare(Object o1, Object o2) {
		Food f = (Food)o1;
		Food f2 = (Food)o2;
		
		// 가격 기준으로 정렬
		// 반환값설정 
		// + : 두개의 객체 위치 변경
		// -,0 : 변경하지 않음
		// 오름차순정렬 : 앞에있는것이 크면은 +기 때문에 자리빠꿔야함 -> 즉 오름차순임
		if(f.getPrice() > f2.getPrice()) return +1;	  // 두 위치를 바꿈
		else if(f.getPrice() < f2.getPrice()) return -1; // 변경하지 않음
		else return 0; // 변경하지 않음
	}
    
    
    	// FoodNameAscending 클래스 (이름 오름차순)
   	    public class FoodNameAscending implements Comparator{
	
		@Override
		public int compare(Object o1, Object o2) { // compare 추상 메소드 구현해줌
			Food prev = (Food)o1;
			Food next = (Food)o2;
			
			return prev.getName().compareTo(next.getName()); // 이름순으로 오름차순
            // compareTo() 메서드는 문자열의 사전순 값을 비교하여 그에 해당되는 int 값을 리턴
			// A=A = 0 (동일한 경우)
			// A>B = 1 (좌측값이 큰 경우)
			// A<B = -1 (좌측값이 작은 경우)			
		}
        
        
        // (2) 클래스를 생성하지 않고 익명클래스로 생성해서 만드는 방법
        foods.sort(new Comparator() {  
			@Override
			public int compare(Object o, Object o1) {
				Food f = (Food)o;
				Food f2 = (Food)o1;
				return f.getPrice()-f2.getPrice();
			}
		});
        
	
    	// (3) 람다식으로 출력하는 방법
        foods.sort((o,o2)-> ((Food)o).getName()
				.compareTo(((Food)o2).getName()));

✅ (2) LinkedList

  • 값을 대입, 출력, 순회 방법은 ArrayList와 동일함
  • List 인터페이스를 구현한 클래스
  • 이중 연결구조를 가진다
    -> node.next = 다음노드
    -> node.prev = 이전노드

✅ ArrayList와 LinkedList의 차이점

  • ArrayList 는 배열형식이며 순차적으로 인덱스 구조를 가짐
  • LinkedList 는 앞뒤로 서로 연결되있는 구조
  • 둘의 차이는 수정할때 퍼포먼스 속도 차이가 남
  • 저장된 데이터를 조작(중간에 삽입, 수정, 삭제)이 많을 때는 LinkdeList 사용하는것이 좋다
  • 기본적으로 데이터를 저장, 출력할 때에는 ArrayList 사용
		LinkedList linkList = new LinkedList();

		linkList.add("최주영");
		linkList.add("이동제");
		linkList.add("최인호");

		System.out.println(linkList.get(0));  // 최주영
		System.out.println(linkList.getFirst());  // 최주영
		System.out.println(linkList.getLast()); // 최인호

✅ 컴파일 타임, 런타임 의존관계

  • 컴파일 타임 : 코드 컴파일 시점
  • 런타임 : 프로그램 실행 시점

✅ 컴파일 타임 의존관계

  • 자바 컴파일러가 보는 의존관계로, 클래스에 모든 의존관계가 다 나타남
  • 실행하지 않은 소스 코드에 정적으로 나타나는 의존 관계
  • BatchProcessor 클래스를 보면 MyList 인터페이스만 사용한다
    코드 어디에서도 MyArrayList, MyLinkedList 같은 정보는 보이지 않는다
    따라서 BatchProcessorMyList 인터페이스에만 의존한다


✅ 런타임 의존관계

  • 실제 프로그램이 작동할 때 보이는 의존관계
  • 프로그램이 실행될 때 인스턴스 간에 의존관계
  • 런타임 의존관계는 프로그램 실행중에 계속 변할 수 있음
// BatchProcessor 클래스
 public class BatchProcessor {
 
     private final MyList<Integer> list;
     
     public BatchProcessor(MyList<Integer> list) {
     		this.list = list;
     }
     
 	public void logic(int size) {
         long startTime = System.currentTimeMillis();
         for (int i = 0; i < size; i++) {
             list.add(0, i); //앞에 추가
      }
      
     long endTime = System.currentTimeMillis();
     System.out.println("크기: " + size + ", 계산 시간: " + (endTime - startTime) 
    + "ms");
    }
 }
// main문
 MyArrayList<Integer> list = new MyArrayList<>();
 BatchProcessor processor = new BatchProcessor(list); 
 processor.logic(50_000);

BatchProcessor 인스턴스의 MyList list는 생성자를 통해 MyArrayList 인스턴스를 참조한다
BatchProcessor 인스턴스에 MyArrayList 의존관계를 주입한다
따라서 이후 logic()을 호출하면 MyArrayList 인스턴스를 사용하게 된다

쉽게말해서 BatchProcessor 클래스는 구체적인 MyArrayListMyLinkedList에 의존하는 것이 아니라
추상적인 MyList에 의존하며, 런타임에 MyList의 구현체를 얼마든지 선택할 수 있다

의존관계를 클래스에서 미리 결정하는 것이 아니라, 런타임에 객체를 생성하는 시점으로 미룬다
따라서 런타임에 MyList의 구현체를 변경해도 BatchProcessor의 코드는 전혀 변경하지 않아도 됨

이렇게 생성자를 통해 런타임 의존관계를 주입하는 것을 생성자 의존관계 주입 또는 생성자 주입이라 한다

위 코드는 디자인 패턴중 전략 패턴 에 속한다

profile
우측 상단 햇님모양 클릭하셔서 무조건 야간모드로 봐주세요!!

0개의 댓글