Java공부(코딩)

코딩초보의 자바(Java)공부 26일차 { 컬렉션프레임워크 - List }

동곤일상 2025. 1. 9. 16:58
반응형
오늘은 List에 대해서
알아보겠습니다.


List자료구조

순서가 있고, 중복을 허용하는 자료 구조를 리스트(`List` ) 한다.

우리가 지금까지 만든 `MyArrayList` `MyLinkedList` 내부 구현만 다를 같은 기능을 제공하는 리스트이다.

물론 내부 구현이 다르기 때문에 상황에 따라 성능은 달라질 있다.

핵심은 사용자 입장에서 보면 같은 기능 제공한다는 것이다.

public interface MyList<E> {
	
	int size();
	
	void add(E e);
	
	void add(int index, E e);
	
	E get(int index);
	
	E set(int index, E element);
	
	E remove(int index);
	
	int indexOf(E o);
	

}
package collection.list;

import java.util.Arrays;

public class MyarrayList<E> implements MyList<E> {
	private static final int DEFAULT_CAPACITY = 5;

    private Object[] elementData;
    private int size = 0;

    public MyarrayList() {
        elementData = new Object[DEFAULT_CAPACITY];
    }

    public MyarrayList(int initialCapacity) {
        elementData = new Object[initialCapacity];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public void add(E e) {
        if (size == elementData.length) {
            grow();
        }
        elementData[size] = e;
        size++;
    }

    @Override
    public void add(int index, E e) {
        if (size == elementData.length) {
            grow();
        }
        shiftRightFrom(index);
        elementData[index] = e;
        size++;
    }

    //요소의 마지막부터 index까지 오른쪽으로 밀기
    private void shiftRightFrom(int index) {
        for (int i = size; i > index; i--) {
            elementData[i] = elementData[i - 1];
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public E get(int index) {
        return (E) elementData[index];
    }

    @Override
    public E set(int index, E element) {
        E oldValue = get(index);
        elementData[index] = element;
        return oldValue;
    }

    @Override
    public E remove(int index) {
        E oldValue = get(index);
        shiftLeftFrom(index);

        size--;
        elementData[size] = null;
        return oldValue;
    }

    //요소의 index부터 마지막까지 왼쪽으로 밀기
    private void shiftLeftFrom(int index) {
        for (int i = index; i < size - 1; i++) {
            elementData[i] = elementData[i + 1];
        }
    }

    @Override
    public int indexOf(E o) {
        for (int i = 0; i < size; i++) {
            if (o.equals(elementData[i])) {
                return i;
            }
        }
        return -1;
    }

    private void grow() {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity * 2;
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(elementData, size)) + 
        		" size=" + size + ", capacity=" + elementData.length;
    }

}

package collection.list;

public class MyLinkedList<E> implements MyList<E>{
	private Node<E> first;
    private int size = 0;

    @Override
    public void add(E e) {
        Node<E> newNode = new Node<>(e);
        if (first == null) {
            first = newNode;
        } else {
            Node<E> lastNode = getLastNode();
            lastNode.next = newNode;
        }
        size++;
    }

    private Node<E> getLastNode() {
        Node<E> x = first;
        while (x.next != null) {
            x = x.next;
        }
        return x;
    }

    @Override
    public void add(int index, E e) {
        Node<E> newNode = new Node<>(e);
        if (index == 0) {
            newNode.next = first;
            first = newNode;
        } else {
            Node<E> prev = getNode(index - 1);
            newNode.next = prev.next;
            prev.next = newNode;
        }
        size++;
    }

    @Override
    public E set(int index, E element) {
        Node<E> x = getNode(index);
        E oldValue = x.item;
        x.item = element;
        return oldValue;
    }

    @Override
    public E remove(int index) {
        Node<E> removeNode = getNode(index);
        E removedItem = removeNode.item;
        if (index == 0) {
            first = removeNode.next;
        } else {
            Node<E> prev = getNode(index - 1);
            prev.next = removeNode.next;
        }
        removeNode.item = null;
        removeNode.next = null;
        size--;
        return removedItem;
    }

    @Override
    public E get(int index) {
        Node<E> node = getNode(index);
        return node.item;
    }

 
    private Node<E> getNode(int index) {
        Node<E> x = first;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        return x;
    }

    @Override
    public int indexOf(E o) {
        int index = 0;
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
        return -1;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public String toString() {
        return "MyLinkedListV1{" +
                "first=" + first +
                ", size=" + size +
                '}';
    }

    private static class Node<E> {
        E item;
        Node<E> next;

        public Node(E item) {
            this.item = item;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            Node<E> temp = this;
            sb.append("[");
            while (temp != null) {
                sb.append(temp.item);
                if (temp.next != null) {
                    sb.append("->");
                }
                temp = temp.next;
            }
            sb.append("]");
            return sb.toString();
        }
    }

}

 

데이터를 앞에서 추가하거나 삭제하는 일이 많다면 `MyArrayList` 보다는 `

MyLinkedList` 사용하는 것이 훨씬 효율적이다.

 

**데이터를 앞에서 추가하거나 삭제할 빅오 비교**

`MyArrayList` : O(n)

`MyLinkedList` : O(1)

 

다음코드를 통해 비교해보자

public class BatchProcessor {
	
	private MyList<Integer> list;
	
	public BatchProcessor(MyList<Integer> e) {
		list=e;
	}
	
	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");
	}

}

 

`BatchProcessor` 생성자에 `MyArrayList` 사용할지, `MyLinkedList` 사용할지 결정해서 넘겨야

한다.

이후에 `processor.logic()` 호출하면 생성자로 넘긴 자료 구조를 사용해서 실행한다.

 

public class BatchProcessorMain {
	public static void main(String[] args) {
		BatchProcessor arrayBatch = new BatchProcessor(new MyarrayList<>());
		BatchProcessor linkedBatch= new BatchProcessor(new MyLinkedList<>());
		
		arrayBatch.logic(49999);
		linkedBatch.logic(49999);
		
		

	}

}

앞에 데이터49999번 추가하는 데 걸리는 시간 : 2432ms

앞에 데이터49999번 추가하는 데 걸리는 시간 : 4ms

이코드로 앞에 데이터를 추가하는 것은

LinkedList가 O(1)로 엄청난 차이로 우세한것을 알수 있음.

 

위 메인코드를 보면 알겠지만 

구체적인 MyarrayList , MyLinkedList 등에 의존하지 않고

추상적인 MyList에 의존하고있다!!

 

이것은 `BatchProcessor` 외부에서 의존관계가 결정되어서 `BatchProcessor` 인스턴스에 들어오는

같다. 마치 의존관계가 외부에서 주입되는 같다고 해서 이것을 **의존관계 주입**이라 한다.

 


 

MyArrayList<Integer> list = new MyArrayList<>();
BatchProcessor processor = new BatchProcessor(list);
processor.logic(50_000);
`BatchProcessor` 인스턴스의 `MyList list` 는 생성자를 통해 `MyArrayList(x001)` 인스턴스를 참조한
다.
`BatchProcessor` 인스턴스에 `MyArrayList(x001)` 의존관계를 주입한다.
따라서 이후 `logic()` 을 호출하면 `MyArrayList` 인스턴스를 사용하게 된다.

**전략 패턴(Strategy Pattern)**

디자인 패턴 중에 가장 중요한 패턴을 하나 뽑으라고 하면 전략 패턴을 뽑을 있다. 전략 패턴은 알고리즘을

라이언트 코드의 변경 없이 쉽게 교체할 있다. 방금 설명한 코드가 바로 전략 패턴을 사용한 코드이다.

`MyList` 인터페이스가 바로 전략을 정의하는 인터페이스가 되고, 각각의 구현체인 `MyArrayList` ,

`MyLinkedList` 전략의 구체적인 구현 된다. 그리고 전략을 클라이언트 코드(`BatchProcessor` ) 변경

없이 손쉽게 교체할 있다.

 


성능비교

package collection.list;



public class MyListPerformanceTest {

public static void main(String[] args) {

int size = 50_000;

System.out.println("==MyArrayList 추가==");

addFirst(new MyarrayList<>(), size);

addMid(new MyarrayList<>(), size);

MyarrayList<Integer> arrayList = new MyarrayList<>(); //조회용 데이터로 사용

addLast(arrayList, size);

System.out.println("==MyLinkedList 추가==");

addFirst(new MyLinkedList<>(), size);

addMid(new MyLinkedList<>(), size);

MyLinkedList<Integer> linkedList = new MyLinkedList<>(); //조회용 데이터로 사용

addLast(linkedList, size);



int loop = 10000;

System.out.println("==MyArrayList 조회==");

getIndex(arrayList, loop, 0);

getIndex(arrayList, loop, size / 2);

getIndex(arrayList, loop, size - 1);

System.out.println("==MyLinkedList 조회==");

getIndex(linkedList, loop, 0);

getIndex(linkedList, loop, size / 2);

getIndex(linkedList, loop, size - 1);

System.out.println("==MyArrayList 검색==");

search(arrayList, loop, 0);

search(arrayList, loop, size / 2);

search(arrayList, loop, size - 1);

System.out.println("==MyLinkedList 검색==");

search(linkedList, loop, 0);

search(linkedList, loop, size / 2);

search(linkedList, loop, size - 1);

}



private static void addFirst(MyList<Integer> list, 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");

}



private static void addMid(MyList<Integer> list, int size) {

long startTime = System.currentTimeMillis();

for (int i = 0; i < size; i++) {

list.add(i / 2, i);

}

long endTime = System.currentTimeMillis();

System.out.println("평균 추가 - 크기: " + size + ", 계산 시간: " + (endTime -

startTime) + "ms");

}



private static void addLast(MyList<Integer> list, int size) {

long startTime = System.currentTimeMillis();

for (int i = 0; i < size; i++) {

list.add(i);

}

long endTime = System.currentTimeMillis();

System.out.println("뒤에 추가 - 크기: " + size + ", 계산 시간: " + (endTime -

startTime) + "ms");

}



private static void getIndex(MyList<Integer> list, int loop, int index) {

long startTime = System.currentTimeMillis();

for (int i = 0; i < loop; i++) {

list.get(index);

}

long endTime = System.currentTimeMillis();

System.out.println("index: " + index + ", 반복: " + loop + ", 계산 시간: " +

(endTime - startTime) + "ms");

}



private static void search(MyList<Integer> list, int loop, int findValue) {

long startTime = System.currentTimeMillis();

for (int i = 0; i < loop; i++) {

list.indexOf(findValue);

}

long endTime = System.currentTimeMillis();

System.out.println("findValue: " + findValue + ", 반복: " + loop + ", 계산"

+ "시간: " + (endTime - startTime) + "ms");

}

==MyArrayList 추가==

앞에 추가 - 크기: 50000, 계산 시간: 2403ms

평균 추가 - 크기: 50000, 계산 시간: 1182ms

뒤에 추가 - 크기: 50000, 계산 시간: 3ms

 

==MyLinkedList 추가==

앞에 추가 - 크기: 50000, 계산 시간: 3ms

평균 추가 - 크기: 50000, 계산 시간: 1647ms

뒤에 추가 - 크기: 50000, 계산 시간: 3258ms

 

==MyArrayList 조회==

index: 0, 반복: 10000, 계산 시간: 0ms

index: 25000, 반복: 10000, 계산 시간: 1ms

index: 49999, 반복: 10000, 계산 시간: 0ms

 

==MyLinkedList 조회==

index: 0, 반복: 10000, 계산 시간: 1ms

index: 25000, 반복: 10000, 계산 시간: 645ms

index: 49999, 반복: 10000, 계산 시간: 1293ms

 

==MyArrayList 검색==

findValue: 0, 반복: 10000, 계산시간: 0ms

findValue: 25000, 반복: 10000, 계산시간: 183ms

findValue: 49999, 반복: 10000, 계산시간: 350ms

 

==MyLinkedList 검색==

findValue: 0, 반복: 10000, 계산시간: 1ms

findValue: 25000, 반복: 10000, 계산시간: 725ms

findValue: 49999, 반복: 10000, 계산시간: 1456ms

 

**배열 리스트 vs 연결 리스트**

대부분의 경우 배열 리스트가 성능상 유리하다. 이런 이유로 실무에서는 주로 배열 리스트를 기본으로 사용한다.

만약 데이터를 앞쪽에서 자주 추가하거나 삭제할 일이 있다면 연결 리스트를 고려하자.


자바리스트

자바가 제공하는 프레임워크이다.!!

 

 

Collection 인터페이스**`

Collection` 인터페이스는 `java.util` 패키지의 컬렉션 프레임워크의 핵심 인터페이스 하나이다. 인터페이

스는 자바에서 다양한 컬렉션, 데이터 그룹을 다루기 위한 메서드를 정의한다. `Collection` 인터페이스는 `List` ,

`Set` , `Queue` 같은 다양한 하위 인터페이스와 함께 사용되며, 이를 통해 데이터를 리스트, 세트, 등의 형태로

리할 있다. 자세한 내용은 뒤에서 다룬다.

 

List 인터페이스**

`List` 인터페이스는 `java.util` 패키지에 있는 컬렉션 프레임워크의 일부다. `List` 객체들의 순서가 있는 컬렉

션을 나타내며, 같은 객체의 중복 저장을 허용한다. 리스트는 배열과 비슷하지만, 크기가 동적으로 변화하는 컬렉션

다룰 유연하게 사용할 있다.

 

List 인터페이스의 주요 메서드

메서드 설명

`add(E e)` 리스트의 끝에 지정된 요소를 추가한다.

`add(int index, E element)` 리스트의 지정된 위치에 요소를 삽입한다.

`addAll(Collection<? extends E> c)` 지정된 컬렉션의 모든 요소를 리스트의 끝에 추가한다.

`addAll(int index, Collection<? extends E> c)`지정된 컬렉션의 모든 요소를 리스트의 지정된 위치에 가한다.

`get(int index)` 리스트에서 지정된 위치의 요소를 반환한다.

set(int index, E element) 지정한 위치의 요소를 변경하고, 이전 요소를 반환한다.

`remove(int index)` 리스트에서 지정된 위치의 요소를 제거하고 요소를 환한다.

`remove(Object o)` 리스트에서 지정된 번째 요소를 제거한다.

`clear()` 리스트에서 모든 요소를 제거한다.

`indexOf(Object o)` 리스트에서 지정된 요소의 번째 인덱스를 반환한다.

`lastIndexOf(Object o)` 리스트에서 지정된 요소의 마지막 인덱스를 반환한다.

`contains(Object o)` 리스트가 지정된 요소를 포함하고 있는지 여부를 반환한.

`sort(Comparator<? super E> c)` 리스트의 요소를 지정된 비교자에 따라 정렬한다.

`subList(int fromIndex, int toIndex)` 리스트의 일부분의 뷰를 반환한다.

`size()` 리스트의 요소 수를 반환한다.

`isEmpty()` 리스트가 비어있는지 여부를 반환한다.

`iterator()` 리스트의 요소에 대한 반복자를 반환한다.

`toArray()` 리스트의 모든 요소를 배열로 반환한다.

`toArray(T[] a)` 리스트의 모든 요소를 지정된 배열로 반환한다.

 


자바ArrayList

 

**자바 ArrayList 특징**

배열을 사용해서 데이터를 관리한다.

기본 `CAPACITY` 10이다.(`DEFAULT_CAPACITY = 10` )

`CAPACITY` 넘어가면 배열을 50% 증가한다.

10 15 22 33 49 증가한다. (최적화는 자바 버전에 따라 달라질 있다.)

메모리 고속 복사 연산을 사용한다.

`ArrayList` 중간 위치에 데이터를 추가하면, 추가할 위치 이후의 모든 요소를 칸씩 뒤로 이동시켜야

한다.

자바가 제공하는 `ArrayList` 부분을 최적화 하는데, 배열의 요소 이동은 시스템 레벨에서 최적화된

메모리 고속 복사 연산을 사용해서 비교적 빠르게 수행된다. 참고로 `System.arraycopy()` 사용한다.

 

원래 배열리스트는

앞에 데이터를 추가하면 뒤에 데이터를 한칸 씩 다 이동시켜야했던 것을

기억해보자

 

고속복사연산은 다음과 같은 방식이다


자바 LinkedList

**자바의 LinkedList 특징**

이중 연결 리스트 구조

번째 노드와 마지막 노드 둘다 참조

 

원래 다음으로만 갈 수 있었던 LinkedList가

이제는 뒤로도 이동할 수 있게 됨.

node.next` 호출하면 다음 노드로, `node.prev` 호출하면 이전 노드로 이동한다.

 

마지막 노드에 대한 참조를 제공한다. 따라서 데이터를 마지막에 추가하는 경우에도 O(1) 성능을 제공한다.

 

이전 노드로 이동할 있기 때문에 마지막 노드부터 앞으로, 그러니까 역방향으로 조회 있다.

덕분에 인덱스 조회 성능을 최적화 있다.

 

예를 들어 인덱스로 조회하는 경우 인덱스가 사이즈의 절반 이하라면 처음부터 찾아서 올라가고, 인덱스가

사이즈의 절반을 넘으면 마지막 노드 부터 역방향으로 조회해서 성능을 최적화 있다.

 

 

자바리스트의 성능

 

MyList-->List

MyarrayList --> ArrayList

MyLinkedList --> LinkedList

package collection.list;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class JavaListPerformanceTest {
	public static void main(String[] args) {
		int size = 50_000;
		System.out.println("==MyArrayList 추가==");
		addFirst(new ArrayList<>(), size);
		addMid(new ArrayList<>(), size);
		List<Integer> arrayList = new ArrayList<>(); //조회용 데이터로 사용
		addLast(arrayList, size);
		System.out.println("==MyLinkedList 추가==");
		addFirst(new LinkedList<>(), size);
		addMid(new LinkedList<>(), size);
		List<Integer> linkedList = new LinkedList<>(); //조회용 데이터로 사용
		addLast(linkedList, size);
		
		int loop = 10000;
		System.out.println("==MyArrayList 조회==");
		getIndex(arrayList, loop, 0);
		getIndex(arrayList, loop, size / 2);
		getIndex(arrayList, loop, size - 1);
		System.out.println("==MyLinkedList 조회==");
		getIndex(linkedList, loop, 0);
		getIndex(linkedList, loop, size / 2);
		getIndex(linkedList, loop, size - 1);
		System.out.println("==MyArrayList 검색==");
		search(arrayList, loop, 0);
		search(arrayList, loop, size / 2);
		search(arrayList, loop, size - 1);
		System.out.println("==MyLinkedList 검색==");
		search(linkedList, loop, 0);
		search(linkedList, loop, size / 2);
		search(linkedList, loop, size - 1);
		}
	
		private static void addFirst(List<Integer> list, 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");
		}
		
		private static void addMid(List<Integer> list, int size) {
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < size; i++) {
		list.add(i / 2, i);
		}
		long endTime = System.currentTimeMillis();
		System.out.println("평균 추가 - 크기: " + size + ", 계산 시간: " + (endTime -
		startTime) + "ms");
		}
		
		private static void addLast(List<Integer> list, int size) {
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < size; i++) {
		list.add(i);
		}
		long endTime = System.currentTimeMillis();
		System.out.println("뒤에 추가 - 크기: " + size + ", 계산 시간: " + (endTime -
		startTime) + "ms");
		}
		
		private static void getIndex(List<Integer> list, int loop, int index) {
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < loop; i++) {
		list.get(index);
		}
		long endTime = System.currentTimeMillis();
		System.out.println("index: " + index + ", 반복: " + loop + ", 계산 시간: " +
		(endTime - startTime) +"ms");
		}
		
		private static void search(List<Integer> list, int loop, int findValue) {
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < loop; i++) {
		list.indexOf(findValue);
		}
		long endTime = System.currentTimeMillis();
		System.out.println("findValue: " + findValue + ", 반복: " + loop + ", 계산"
				+ "시간: " + (endTime - startTime) + "ms");
		}

}

==MyArrayList 추가==

앞에 추가 - 크기: 50000, 계산 시간: 196ms

평균 추가 - 크기: 50000, 계산 시간: 99ms

뒤에 추가 - 크기: 50000, 계산 시간: 3ms

==MyLinkedList 추가==

앞에 추가 - 크기: 50000, 계산 시간: 5ms

평균 추가 - 크기: 50000, 계산 시간: 1685ms

뒤에 추가 - 크기: 50000, 계산 시간: 3ms

==MyArrayList 조회==

index: 0, 반복: 10000, 계산 시간: 1ms

index: 25000, 반복: 10000, 계산 시간: 1ms

index: 49999, 반복: 10000, 계산 시간: 0ms

==MyLinkedList 조회==

index: 0, 반복: 10000, 계산 시간: 1ms

index: 25000, 반복: 10000, 계산 시간: 648ms

index: 49999, 반복: 10000, 계산 시간: 0ms

==MyArrayList 검색==

findValue: 0, 반복: 10000, 계산시간: 1ms

findValue: 25000, 반복: 10000, 계산시간: 194ms

findValue: 49999, 반복: 10000, 계산시간: 354ms

==MyLinkedList 검색==

findValue: 0, 반복: 10000, 계산시간: 0ms

findValue: 25000, 반복: 10000, 계산시간: 731ms

findValue: 49999, 반복: 10000, 계산시간: 1466ms

 

 

**데이터를 추가할 자바 ArrayList 직접 구현한 MyArrayList보다 빠른 이유**

자바의 배열 리스트는 이때 메모리 고속 복사를 사용하기 때문에 성능이 최적화된다.

메모리 고속 복사는 시스템에 따라 성능이 다르기 때문에 정확한 계산은 어렵지만 대략 O(n/10) 정도로 추정하

. 상수를 제거하면 O(n) 된다. 하지만 메모리 고속 복사라도 데이터가 아주 많으면 느려진다.

 


문제와 풀이1

문제1 - 배열을 리스트로 변경하기

**문제 설명**

`ArrayEx1` 배열을 사용한다. 코드를 배열 대신에 리스트를 사용하도록 변경하자.

다음 코드와 실행 결과를 참고해서 리스트를 사용하는 `ListEx1` 클래스를 만들어라.

package collection.list.test.ex1;
public class ArrayEx1 {
public static void main(String[] args) {
int[] students = {90, 80, 70, 60, 50};
int total = 0;
for (int i = 0; i < students.length; i++) {
total += students[i];
}
double average = (double) total / students.length;
System.out.println("점수 총합: " + total);
System.out.println("점수 평균: " + average);
}
}
```
**실행 결과**
```
점수 총합: 350
점수 평균: 70.0

 

바꾼 코드

public class ListEx1 {
	public static void main(String[] args) {
		int total=0;
		ArrayList<Integer> arrayList = new ArrayList<Integer>();
		arrayList.add(90);
		arrayList.add(80);
		arrayList.add(70);
		arrayList.add(60);
		arrayList.add(50);
		for (Integer integer : arrayList) {
			total+=integer;
		}
		System.out.println("점수 총합 : "+total);
		double average =(double)total/arrayList.size();
		System.out.println("점수평균 : "+average);
	}
}

문제2 - 리스트의 입력과 출력

**문제 설명**

사용자에게 `n` 개의 정수를 입력받아서 `List` 저장하고, 입력 순서대로 출력하자.

`0` 입력하면 입력을 종료하고 결과를 출력한다.

출력시 출력 포멧은 1, 2, 3, 4, 5 같이 `,` 쉼표를 사용해서 구분하고, 마지막에는 쉼표를 넣지 않아야 한다.

실행 결과 예시를 참고하자.

문제는 `ListEx2` 풀자

n개의 정수를 입력하세요 (종료 0)

1

2

3

4

5

0출력

1, 2, 3, 4, 5

public class ListEx2 {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		ArrayList<Object> arrayList = new ArrayList<>();
		System.out.println("정수를 입력하세요 [종료 : 0 ]");

		while(true) {
			int a = scan.nextInt();
			if(a==0) {
				break;
			}arrayList.add(a);
		}

		for (int i = 0; i < arrayList.size(); i++) {
			if(i<arrayList.size()-1) {
				System.out.print(arrayList.get(i)+",");
			}
			else{System.out.print(arrayList.get(i));
			}
		}
	}

}

문제3 - 합계와 평균

사용자에게 `n` 개의 정수를 입력받아서 `List` 보관하고, 보관한 정수의 합계와 평균을 계산하는 프로그램을 작성하

.

`ListEx3` 작성하자.**실행 결과 예시**

```

n개의 정수를 입력하세요 (종료 0)

1

2

3

4

5

0

입력한 정수의 합계: 15

입력한 정수의 평균: 3.0

 

public class ListEx3 {
	static int total;
	public static void main(String[] args) {
		
		Scanner scan = new Scanner(System.in);
		ArrayList<Integer> arrayList = new ArrayList<>();
		System.out.println("정수를 입력하세요 [종료 : 0 ]");

		while(true) {
			int a = scan.nextInt();
			if(a==0) {
				break;
			}
			arrayList.add(a);
		}

		for (int i = 0; i < arrayList.size(); i++) {
			total += arrayList.get(i);
		}
		double average = (double)total / arrayList.size();
		System.out.println("정수의 합 : "+total);
		System.out.println("입력된 정수의 갯수 : "+arrayList.size());
		System.out.printf("평균 : %.3f",average);
		
	}

}

***출력****
정수를 입력하세요 [종료 : 0 ]
5
6
12
87
24
56
12
24
0
정수의 합 : 226
입력된 정수의 갯수 : 8
평균 : 28.250

문제와 풀이2

문제 - 리스트를 사용한 쇼핑 카트

`ShoppingCartMain` 코드가 작동하도록 `ShoppingCart` 클래스를 완성해라.

`ShoppingCart` 내부에 리스트를 사용해야 한다.\

**Item 클래스**
```java
package collection.list.test.ex2;
public class Item {
private String name;
private int price;
private int quantity;
public Item(String name, int price, int quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}
public String getName() {
return name;
}
public int getTotalPrice() {
return price * quantity;
}
}

 

public class ShoppingCartMain {
	public static void main(String[] args) {
		Shoppingcart cart = new Shoppingcart();
		Item item1 =new Item("상추", 1200, 5);
		Item item2 =new Item("마늘", 3200, 2);
		Item item3 =new Item("대파", 2500, 5);
		
		cart.add(item1);
		cart.add(item2);
		cart.add(item3);
		cart.displayItem();
		
		

	}

}

출력 예시
상품명 : xx 가격 : xxxx
총 가격 : xxx

배열을 사용한 ShoppingCart클래스(배열)

public class Shoppingcart2 {
	int total;
	int itemCount;
	Item[] items = new Item[10];
	

	public void add(Item item1) {
		if(itemCount >= items.length) {
			System.out.println("장바구니가 가득 찼어요");
			return;
		}
		items[itemCount] = item1;
		System.out.println("장바구니에 담았어요 , 현재수량 : "+(itemCount+1));
		itemCount++;
		
		
	}
	
	public void displayItem() {
		for (int i = 0; i < itemCount; i++) {
			Item item = items[i];
			System.out.println("상품명 : "+item.getName()
			+" 가격 : "+item.totalPrice());
			total+=item.totalPrice();			
		}
		System.out.println("총 가격 : "+total);
		
	}

}

완성한Shoppingcart 클래스(리스트)

public class Shoppingcart {
	int total;
	ArrayList<Item> list = new ArrayList<>();
	

	public void add(Item item1) {
		list.add(item1);
	}
	
	public void displayItem() {
		for (Item item : list) {
			System.out.println("상품명 : "+item.getName()+
					"  합계 : "+item.totalPrice());	
			total+=item.totalPrice();
		}
		System.out.println("총 구매 금액 : "+total);
		
		
	}

}

 

출력:

상품명 : 상추 합계 : 6000

상품명 : 마늘 합계 : 6400

상품명 : 대파 합계 : 12500

총 구매 금액 : 24900

 

 

배열과 비교한 리스트의 이점

자료 구조의 크기가 동적으로 증가한다.

 따라서 배열처럼 입력 가능한 크기를 미리 정하지 않아도 된다.

`itemCount`  같이 배열에 몇게의 데이터가 추가 되었는지 추척하는 변수를 제거할  있다. 

리스트는

`size()` 메서드를 통해 입력된 데이터의 크기를 제공한다.