컬렉션 (collection) 의개념 Collections, Generic 514770 2018 년가을학기 10/1/2018 박경신 컬렉션 요소 (element) 라고불리는가변개수의객체들의저장소 객체들의컨테이너라고도불림 요소의개수에따라크기자동조절 요소의삽입, 삭제에따른요소의위치자동이동 고정크기의배열을다루는어려움해소 다양한객체들의삽입, 삭제, 검색등의관리용이 컬렉션인터페이스와클래스 Collection<E> Map<K, V> Set<E> List<E> Queue<E> 인터페이스 클래스 HashSet<E> ArrayList<E> Vector<E> LinkedList<E> HashMap<K, V> Stack<E> Collection 인터페이스메소드 Method Description boolean add(object element) is used to insert an element in this collection. boolean addall(collection c) is used to insert the specified collection elements in the coll ection. boolean remove(object element) is used to delete an element from this collection. boolean removeall(collection c) is used to delete all the elements of specified collection fro m the collection. boolean retainall(collection c) is used to delete all the elements of invoking collection exce pt the specified collection. int size() return the total number of elements in the collection. void clear() removes the total no of element from the collection. boolean contains(object element) is used to search an element. boolean containsall(collection c) is used to search the specified collection in this collection. Iterator iterator() returns an iterator. Object[] toarray() converts collection into array. boolean isempty() checks if collection is empty. boolean equals(object element) matches two collection. int hashcode() returns the hashcode number for collection.
List 인터페이스메소드 Method Description void add(int index, Object elemen is used to insert an element into the list at index passed in t t) he index. boolean addall(int index, Collecti on c) is used to insert all elements of c into the list at the index p assed in the index. object get(int index) is used to return the object stored at the specified index wit hin the collection. object set(int index, Object eleme is used to assign element to the location specified by index nt) within the list. object remove(int index) is used to delete all the elements of invoking collection exce pt the specified collection. ListIterator listiterator() is used to return an iterator to the start of the list. ListIterator listiterator(int index) is used to return an iterator to the list that begins at the sp ecified index. 컬렉션과제네릭 컬렉션은제네릭 (Generics) 기법으로구현됨 컬렉션의요소는객체만가능 기본적으로 int, char, double 등의기본타입사용불가 JDK 1.5 부터자동박싱 / 언박싱기능으로기본타입사용가능 제네릭 (Generics) 특정타입만다루지않고, 여러종류의타입으로변신할수있도록클래스나메소드를일반화시키는기법 <E>, <K>, <V> : 타입매개변수 요소타입을일반화한타입 제네릭클래스사례 제네릭벡터 : Vector<E> E 에특정타입으로구체화 정수만다루는벡터 Vector<Integer> 문자열만다루는벡터 Vector<String> 컬렉션과자동박싱 / 언박싱 JDK 1.5 이전 기본타입데이터를 Wrapper 클래스를이용하여객체로만들어사용 Vector<Integer> v = new Vector<Integer>(); v.add(new Integer(4)); 컬렉션으로부터요소를얻어올때, Wrapper 클래스로캐스팅필요 Integer n = (Integer)v.get(0); int k = n.intvalue(); // k = 4 JDK 1.5부터 자동박싱 / 언박싱이작동하여기본타입값사용가능 Vector<Integer> v = new Vector<Integer> (); v.add(4); // 4 new Integer(4) 로자동박싱 int k = v.get(0); // Integer 타입이 int 타입으로자동언박싱, k = 4 제네릭의타입매개변수를기본타입으로구체화할수는없음 Vector<int> v = new Vector<int> (); // 오류 제네릭의기본개념 JDK 1.5 에서도입 (2004 년기점 ) 모든종류의데이터타입을다룰수있도록일반화된타입매개변수로클래스나메소드를작성하는기법 C++ 의템플릿 (template) 과동일 class Stack<E> { void push(e element) { E pop() { 제네릭스택 특정타입으로구체화 정수만저장정수스택 void push(integer element) { Integer pop() { void push(string element) { String pop() { 문자열스택 문자열만저장 20-345 123 10 Good C# C++ Java
Vector<E> Vector<E> 의특성 java.util.vector <E> 에서 E 대신요소로사용할특정타입으로구체화 여러객체들을삽입, 삭제, 검색하는컨테이너클래스 배열의길이제한극복 원소의개수가넘쳐나면자동으로길이조절 Vector 에삽입가능한것 객체, null 기본타입은박싱 / 언박싱으로 Wrapper 객체로만들어저장 Vector 에객체삽입 벡터의맨뒤에객체추가 벡터중간에객체삽입 Vector 에서객체삭제 임의의위치에있는객체삭제가능 : 객체삭제후자동자리이동 Vector<Integer> 컬렉션내부구성 add() 를이용하여요소를삽입하고 get() 을이용하여요소를검색합니다 Vector<Integer> v = new Vector<Integer>(); Vector<E> 클래스의주요메소드 ArrayList<E> ArrayList<E> 의특성 java.util.arraylist, 가변크기배열을구현한클래스 <E> 에서 E 대신요소로사용할특정타입으로구체화 ArrayList에삽입가능한것 객체, null 기본타입은박싱 / 언박싱으로 Wrapper 객체로만들어저장 ArrayList에객체삽입 / 삭제 리스트의맨뒤에객체추가 리스트의중간에객체삽입 임의의위치에있는객체삭제가능 벡터와달리스레드동기화기능없음 다수스레드가동시에 ArrayList에접근할때동기화되지않음 개발자가스레드동기화코드작성
ArrayList<String> 컬렉션의내부구성 ArrayList<E> 클래스의주요메소드 ArrayList<String> = new ArrayList<String>(); add() 를이용하여요소를삽입하고 get() 을이용하여요소를검색합니다 HashMap<K,V> HashMap<K,V> 키 (key) 와값 (value) 의쌍으로구성되는요소를다루는컬렉션 java.util.hashmap K는키로사용할요소의타입, V는값으로사용할요소의타입지정 키와값이한쌍으로삽입 키는해시맵에삽입되는위치결정에사용 값을검색하기위해서는반드시키이용 삽입및검색이빠른특징 요소삽입 : put() 메소드 요소검색 : get() 메소드 예 ) HashMap<String, String> 생성, 요소삽입, 요소검색 HashMap<String, String> 의내부구성과 put(), get() 메소드 HashMap<String, String> map = new HashMap<String, String>(); HashMap<String, String> h = new HashMap<String, String>(); h.put("apple", " 사과 "); // "apple" 키와 " 사과 " 값의쌍을해시맵에삽입 String kor = h.get("apple"); // "apple" 키로값검색. kor 는 " 사과
HashMap<K,V> 의주요메소드 LinkedList<E> LinkedList<E> 의특성 java.util.linkedlist E 에요소로사용할타입지정하여구체와 List 인터페이스를구현한컬렉션클래스 Vector, ArrayList 클래스와매우유사하게작동 요소객체들은양방향으로연결되어관리됨 요소객체는맨앞, 맨뒤에추가가능 요소객체는인덱스를이용하여중간에삽입가능 맨앞이나맨뒤에요소를추가하거나삭제할수있어스택이나큐로사용가능 LinkedList<String> 의내부구성과 put(), get() 메소드 컬렉션순차검색을위한 Iterator 인터페이스 LinkedList<String> l = new LinkedList<String>(); Iterator<E> 인터페이스 Vector<E>, ArrayList<E>, LinkedList<E> 가상속받는인터페이스 리스트구조의컬렉션에서요소의순차검색을위한메소드포함 Iterator<E> 인터페이스메소드 iterator() 메소드 iterator() 를호출하면 Iterator 객체반환 Iterator 객체를이용하여인덱스없이순차적검색가능
컬렉션의순차검색을위한 Iterator Vector<Integer> v = new Vector<Integer>(); Iterator<Integer> it = v.iterator(); while(it.hasnext()) { // 모든요소방문 int n = it.next(); // 다음요소리턴 또는 for (int n : v) { Remove Objects from Collection while Iterating ArrayList 는 remove(int index) 또는 remove(object obj) 메소드를제공함. 단 remove() 메소드는 ArrayList 를 iterating 하지않은경우에만사용함. ArrayList 에서 iterating 하면서 remove() 해야할경우, Iterator 를사용함. ArrayList<String> list = new ArrayList<String>(Arrays.asList( a, b, c, d )); for (int I = 0; i < list.size(); i++) { list.remove(i); // 원소가삭제될때 list 사이즈가줄면서다른원소들의 index 도바뀜 for (String s : list) { list.remove(s); // ConcurrentModificationException 발생 Iterator<String> it = list.iterator(); while (it.hasnext()) { String s = it.next(); // Iterator 의 next() 가 remove() 보다먼저호출되어야함 it.remove(); Collections 클래스활용 Collections 클래스 java.util 패키지에포함 컬렉션에대해연산을수행하고결과로컬렉션리턴 모든메소드는 static 타입 주요메소드 컬렉션에포함된요소들을소팅하는 sort() 메소드 요소의순서를반대로하는 reverse() 메소드 요소들의최대, 최소값을찾아내는 max(), min() 메소드 특정값을검색하는 binarysearch() 메소드 예제 : Collections 클래스의활용 Collections 클래스를활용하여문자열정렬, 반대로정렬, 이진검색등을실행하는사례를살펴보자. import java.util.*; public class CollectionsEx { static void printlist(linkedlist<string> l) { Iterator<String> iterator = l.iterator(); while (iterator.hasnext()) { String e = iterator.next(); String separator; if (iterator.hasnext()) separator = "->"; else separator = "\n"; System.out.print(e+separator);
예제 : Collections 클래스의활용 예제 : Collections 클래스의활용 public static void main(string[] args) { LinkedList<String> mylist = new LinkedList<String>(); mylist.add(" 트랜스포머 "); mylist.add(" 스타워즈 "); mylist.add(" 매트릭스 "); mylist.add(0," 터미네이터 "); mylist.add(2," 아바타 "); Collections.sort(myList); // 요소정렬 printlist(mylist); // 정렬된요소출력 static 메소드이므로클래스이름으로바로호출 Collections.reverse(myList); // 요소의순서를반대로 printlist(mylist); // 요소출력 소팅된순서대로출력 거꾸로출력 매트릭스 -> 스타워즈 -> 아바타 -> 터미네이터 -> 트랜스포머트랜스포머 -> 터미네이터 -> 아바타 -> 스타워즈 -> 매트릭스아바타는 3 번째요소입니다. int index = Collections.binarySearch(myList, " 아바타 ") + 1; System.out.println(" 아바타는 " + index + " 번째요소입니다."); Custom 클래스에대한 sort 메소드사용 개인적으로만든클래스에대해서컬렉션에추가하고, Collections.sort 기능을이용해서정렬하고싶다면 java.lang.comparable 인터페이스를구현해주어야함 public interface Comparable<T> { int compareto(t o); CompareTo(T o) 메소드는현객체를인자로주어진 o 와비교해서순서를정한후에정수 (int) 값을반환함 만약현객체가주어진인자보다작다면음수를반환 만약현객체가주어진인자와동일하다면 0 을반환 만약현객체가주어진인자보다크다면양수를반환 Custom 클래스에대한 sort 메소드사용 import java.util.collections; class A implements java.lang.comparable<a> { int num; String s; public A(String s, int n) { this.s = s; num = n; public int compareto(a a) { if (s.compareto(a.s) == 0) { if (num > a.num) return 1; else if (num < a.num) return -1; else return 0; else { return s.compareto(a.s); public String tostring() { return "String: " + s + "\t num = " + num;
Custom 클래스에대한 Collections.sort 함수사용 public class Main { public static void main(string[] args) { ArrayList<A> list = new ArrayList<A>(); list.add(new A("Kim", 30)); list.add(new A("Cho", 20)); list.add(new A("Cho", 30)); list.add(new A("Lee", 20)); for (A b : list) { System.out.println(b); System.out.println("After sorting"); Collections.sort(list); for (A b : list) { System.out.println(b); == & equals & hashcode equals 는두객체의내용이같은지동등성 (equality) 을비교하는연산자 Person p1 = new Person( Jason, 10); Person p2 = new Person( Jason, 10); Person p3 = p1; // == if (p1 == p2) System.out.println( p1 == p2 ); else System.out.println( p1!= p2 ); // 동일한 ref 아니므로 p1!= p2 if (p1 == p3) System.out.println( p1 == p3 ); // 동일한 ref 므로 p1 == p3 else System.out.println( p1!= p3 ); // equals // equals override 되어있으면 true, 안되어있으면 false if (p1.equals(p2)) System.out.println( p1 equals p2 ); else System.out.println( p1 is not equal to p2 ); == & equals & hashcode hashcode 는두객체가같은객체인지동일성 (identity) 을비교하는연산자 Map<Person, Integer> pmap = new HashMap<Person, Integer>(); pmap.put(p1, 1); // equals&hashcode override 있다면, p1 과 p2 는동일 pmap.put(p2, 2); // equals override&no hashcode 라면, p1 과 p2 는다름 for (Map.Entry<Person, Integer> entry : pmap.entryset()) { System.out.println("P : "+entry.getkey()+" Index : " +entry.getvalue()); System.out.println("pMap=" + pmap.size()); // pmap=1 pmap.remove(p1); // p1 과 p2 가같은 hashcode, p1 으로 p2 를같이지움 for (Map.Entry<Person, Integer> entry : pmap.entryset()) { System.out.println("P: "+entry.getkey()+" Index : " +entry.getvalue()); System.out.println("after remove pmap=" + pmap.size()); // pmap=0 val 의타입은 T 제네릭만들기 제네릭클래스와인터페이스 클래스나인터페이스선언부에일반화된타입추가 public class MyClass<T> { T val; void set(t a) { val = a; T get() { return val; 제네릭클래스레퍼런스변수선언 MyClass<String> s; List<Integer> li; Vector<String> vs; 제네릭클래스 MyClass 선언, 타입매개변수 T T 타입의값 a 를 val 에지정 T 타입의값 val 리턴
제네릭객체생성 구체화 (specialization) 구체화 제네릭타입의클래스에구체적인타입을대입하여객체생성 컴파일러에의해이루어짐 // 제네릭타입 T 에 String 지정 MyClass<String> s = new MyClass<String>(); s.set("hello"); System.out.println(s.get()); // "hello" 출력 // 제네릭타입 T 에 Integer 지정 MyClass<Integer> n = new MyClass<Integer>(); n.set(5); System.out.println(n.get()); // 숫자 5 출력 구체화된 MyClass<String> 의소스코드 제네릭객체생성 구체화 (specialization) public class MyClass<T> { T val; void set(t a) { val = a; T get() { return val; T 가 String 으로구체화 public class MyClass<String> { String val; // 변수 val 의타입은 String void set(string a) { val= a; // String 타입의값 a 를 val 에지정 String get() { return val; // String 타입의값 val 을리턴 구체화오류 타입매개변수에기본타입은사용할수없음 Vector<int> vi = new Vector<int>(); // 컴파일오류. int 사용불가수정 Vector<Integer> vi = new Vector<Integer>(); // 정상코드 타입매개변수 타입매개변수 < 과 > 사이에하나의대문자를타입매개변수로사용 많이사용하는타입매개변수문자 E : Element를의미하며컬렉션에서요소를표시할때많이사용한다. T : Type을의미한다. V : Value를의미한다. K : Key를의미 타입매개변수가나타내는타입의객체생성불가 //T a = new T(); // 오류!! 타입매개변수는나중에실제타입으로구체화 어떤문자도매개변수로사용가능
예제 : 제네릭스택만들기 스택을제네릭클래스로작성하고, String 과 Integer 형스택을사용하는예를보여라. class GStack<T> { int tos; Object [] stck; public GStack() { tos = 0; stck = new Object [10]; public void push(t item) { if(tos == 10) return; stck[tos] = item; tos++; public T pop() { if(tos == 0) return null; tos--; return (T)stck[tos]; 예제 : 제네릭스택만들기 public class MyStack { public static void main(string[] args) { GStack<String> stringstack = new GStack<String>(); stringstack.push("seoul"); stringstack.push("busan"); stringstack.push("la"); for(int n=0; n<3; n++) System.out.println(stringStack.pop()); GStack<Integer> intstack = new GStack<Integer>(); intstack.push(1); intstack.push(3); intstack.push(5); for(int n=0; n<3; n++) System.out.println(intStack.pop()); LA busan seoul 5 3 1 제네릭과배열 제네릭에서배열의제한 제네릭클래스또는인터페이스의배열을허용하지않음 //GStack<Integer>[] gs = new GStack<Integer>[10]; // 오류!! 제네릭타입의배열도허용되지않음 //T[] a = new T[10]; // 오류!! 앞예제에서는 Object 타입으로배열생성후실제사용할때타입캐스팅 return (T)stck[tos]; // 타입매개변수 T 타입으로캐스팅 타입매개변수의배열에레퍼런스는허용 public void myarray(t[] a) { 제네릭메소드 제네릭메소드선언가능 class GenericMethodEx { static <T> void tostack(t[] a, GStack<T> gs) { for (int i = 0; i < a.length; i++) { gs.push(a[i]); 제네릭메소드를호출할때는컴파일러가메소드의인자를통해이미타입을알고있으므로타입을명시하지않아도됨 String[] sa = new String[100]; GStack<String> gss = new GStack<String>(); GenericMethodEx.toStack(sa, gss); sa 는 String[], gss 는 GStack<String> 타입이므로 T 를 String 으로유추
예제 : 스택의내용을반대로만드는제네릭메소드만들기 GStack 을이용하여주어진스택의내용을반대로만드는제네릭메소드 reverse() 를작성하라. public class GenericMethodExample { // T 가타입매개변수인제네릭메소드 public static <T> GStack<T> reverse(gstack<t> a) { GStack<T> s = new GStack<T>(); while (true) { T tmp; tmp = a.pop(); // 원래스택에서요소하나를꺼냄 if (tmp==null) // 스택이비었음 break; else s.push(tmp); // 새스택에요소를삽입 return s; // 새스택을반환 public static void main(string[] args) { // Double 타입의 GStack 생성 GStack<Double> gs = new GStack<Double>(); // 5 개의요소를스택에 push for (int i=0; i<5; i++) { gs.push(new Double(i)); gs = reverse(gs); for (int i=0; i<5; i++) { System.out.println(gs.pop()); 0.0 1.0 2.0 3.0 4.0 타입경계 (Bounded Type Parameter) 제네릭클래스나제네릭메소드가받는타입인자를제한하고싶은경우에타입경계를사용할수있다. public class GenericMethodExample2 { // 입력 list 에서처음 3 요소만새 list 로반환 public static <T> List<T> firstthree(list<t> list) { return list.stream().limit(3).collect(); // 입력 list 에서처음 char 만새 char list 로반환 (T 는 CharSequence 의서브타입만가능 ) public static <T extends CharSequence> List<Character> firstchars(list<t> list) { return list.stream().map(e -> e.charat(0)).collect(collectors.tolist()); public static void main(string[] args) { List<String> cities = new ArrayList<String>(); cities.add( Seoul ); cities.add( Busan ); cities.add( Incheon ); cities.add( Daejeon ); for (String city : firstthree(cities)) System.out.println(city.toUpperCase()); for (Character c : firstchars(cities)) System.out.println(c); 와일드카드 (Wildcard) 와일드카드 ( 즉, unknown type) 제네릭클래스나제네릭메소드에서사용하는? 를와일드카드 ( 즉, unknown type) 라고부른다. 매개변수, 멤버필드, 지역변수, 반환인자등다양하게사용한다. Unbounded wildcard // 입력 list 의원소를모두출력 (? 는모든객체타입, 즉내부적으로는 Object) public static void print(list<?> list) { list.foreach(e -> System.out.println(e)); print(cities); // List<String> cities = new ArrayList<>();. print(nums); // List<Integer> nums = new ArrayList<>(); print(people); // List<Person> people = new ArrayList<>();. // It only prints a list of Object (It cannot print a list of String, a list of Integer, etc) public static void print(list<object> list) { list.foreach(e -> System.out.println(e)); 와일드카드 (Wildcard) 서브타입와일드카드 (Upper bounded wildcard) Unknown type 이특정타입의서브타입만가능하도록 // 입력 list 에서처음 char 만새 char list 로반환 (? 는 CharSequence 의서브타입만가능 ) public static List<Character> firstchars(list<? extends CharSequence> list) { return list.stream().map(e -> e.charat(0)).collect(collectors.tolist()); 슈퍼타입와일드카드 (Lower bounded wildcard) Unknown type 이특정타입의슈퍼타입만가능하도록 // 입력 list 에 10 을추가 (? 는 Integer 의슈퍼타입만가능. 즉, Integer, Number, Object) public static void addten(list<? super Integer> list) { list.add(10);
Java9 Immutable Collection 불변컬렉션 (Immutable Collection) 아이템추가, 수정, 제거가불가능한컬렉션 따라서, 신규아이템을추가하거나기존아이템을수정또는제거하려고하면 java.lang.unsupportedoperationexception 예외발생 Java8까지는불변컬렉션생성방법 Collections.unmodifiableList(list) 사용 Arrays.asList( ) 사용 Stream.of(.).collect(collectingAndThen(toList(), Collections::unmodifiableList)) 사용 Guava 라이브러리사용 Java9 Immutable Collection Java9 불변컬렉션생성방법 List.of() 사용 List<String> fruits = List.of( apple, banana, cherry ); Set.of() 사용 Set<String> fruits = Set.of( apple, banana, cherry ); Set<String> fruits = Set.of( apple, banana, cherry, apple ); // Set 은중복인자를넣으면 IllegalArgumentException Map.of() 또는 Map.ofEntries() 사용 Map<Integer, String> fruits = Map.of(1, apple, 2, banana, 3, cherry ); Map<Integer, String> fruits = Map.ofEntries(Map.entry(1, apple ), Map.entry(2, banana ), Map.entry(3, cherry ));