
Collection이란?
Set 인터페이스
List 인터페이스
Map 인터페이스
유용한 컬렉션 메서드
Collections.sort()와 자바에서의 Comparator 사용
컬랙션 동기화
[참고]https://gangnam-americano.tistory.com/41
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App {
    public static void main(String[] args) {
        //List 생성
        List<String> list = Arrays.asList("Lars","Simon");
        //List를 이렇게도 생성할수있다.
        // List는 인터페이스이므로 참조변수는 List 구현체를 가리켜야한다.
        List<String> list1 = new ArrayList<>();
        list1.add("LULU");
        list1.add("LALA");
        // 람다식을 이용하여 각 요소를 출력
        list.forEach(i-> System.out.println(i));
        list1.forEach(i-> System.out.println(i));
        
        // or
        list.forEach(System.out::println);
        list1.forEach(System.out::println);
    }
}
package me.whiteship.livestudy.Collections;
import me.whiteship.livestudy.review6.Student;
import java.util.ArrayList;
import java.util.Arrays;
public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList list= new ArrayList(); // 타입 미설정 object로 선언된다.
        ArrayList<Student> list1 = new ArrayList<Student>(); // 타입설정 Student객체만
        ArrayList<Integer> list2 = new ArrayList<Integer>(); // 타입설정 int타입만 사용가능
        ArrayList<Integer> list3 = new ArrayList<>(); // new에서 타입파라미터 생략가능.
        ArrayList<Integer> list4 = new ArrayList<Integer>(10); // 초기용량 지정
        ArrayList<Integer> list5 = new ArrayList<Integer>(Arrays.asList(1,2,3)); // 생성값 추가
    }
}
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.Arrays;
public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(3); // 값 추가
        list.add(null); // null값도 add 가능
        list.add(1,10); // index 1 위치에 10 insert
     }
}
        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(1,2,3));
        arrayList.remove(1); // index 1 제거
        arrayList.clear(); // 모든 값 제거
        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(1,2,3));
        System.out.println(arrayList.size()); // 3 출력
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(1,2,3));
        System.out.println(arrayList.get(0)); // 0번째 인덱스 출력
        for (Integer integer : arrayList) { // for문을 통한 전체 출력
            System.out.println(integer);
        }
        Iterator iterator = arrayList.iterator(); // Iterator 선언
        while(iterator.hasNext()){ // 다음값이 있는지 체크
            System.out.println(iterator.next()); // 값 출력
        }
     }
}
output
1
1
2
3
1
2
3
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(1,2,3,1));
        System.out.println(arrayList.contains(1)); // list에 1이 있는지 검색: true
        System.out.println(arrayList.indexOf(1)); // 1이 있는 index 반환 없으면 -1
     }
}
output
true
0
package me.whiteship.livestudy.Collections;
import java.util.Arrays;
import java.util.LinkedList;
public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList list = new LinkedList(); // 타입 미설정 Object로 선언된다.
        LinkedList<Integer> list1= new LinkedList<Integer>(); // 타입설정 int타입만 사용가능하다
        LinkedList<Integer> list2 = new LinkedList<>(); // new에서 타입 파라미터 생략가능
        LinkedList<Integer> list3 = new LinkedList<Integer>(Arrays.asList(1,2,3)); // 생성시 값추가
    }
}
package me.whiteship.livestudy.Collections;
import java.util.Arrays;
import java.util.LinkedList;
public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<Integer> list= new LinkedList<Integer>(); 
        list.addFirst(1); // 가장 앞에 데이터를 추가
        list.addLast(2); // 가장 뒤에 데이터 추가
        list.add(3); // 데이터 추가
        list.add(1,10); // 1번쨰 index에 데이터 10추가
    }
}
package me.whiteship.livestudy.Collections;
import java.util.Arrays;
import java.util.LinkedList;
public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<Integer> list= new LinkedList<Integer>(Arrays.asList(1,2,3,4,5));
        list.removeFirst(); // 가장 앞의 데이터 제거
        list.removeLast(); // 가장 뒤의 데이터 제거
        list.remove(); // index 생략시 0번째 index 제거
        list.remove(1); // 1번째 index 제거
        list.clear(); // 모든 값 제거
      
    }
}
LinkedList<Integer> list= new LinkedList<Integer>(Arrays.asList(1,2,3,4,5));
System.out.println(list.size());
        LinkedList<Integer> list= new LinkedList<Integer>(Arrays.asList(1,2,3,4,5));
        System.out.println(list.get(0)); // 0번째 index 출력
        System.out.println();
        for (Integer integer : list) { // for문을 이용한 전체 출력
            System.out.println(list);
        }
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){ // iterator를 이용한 전체 출력
            System.out.println(iterator.next());
        }
        LinkedList<Integer> list= new LinkedList<Integer>(Arrays.asList(1,2,3,4,5));
        System.out.println(list.contains(1)); // true 출력
        System.out.println(list.indexOf(3)); // 2 출력
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App {
    public static void main(String[] args) {
        //ArrayList에 대한 타입 추론
        List<Integer> list = Arrays.asList(3,2,1,4,5,6,6);
        //또는 다음과 같이 선언가능
        // List<Integer> list = new ArrayList<>();
        // list.add(element);
        for (Integer integer : list) {
            System.out.println(integer);
        }
    }
}
output
3
2
1
4
5
6
6
예제코드
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App {
    public static void main(String[] args) {
        // natural order로 sorting
        List<String> list = createList();
        list.sort(null);
        list.forEach((i)-> System.out.println(i));
        System.out.println();
        // 람다를 사용하여 sorting
        List<String> list1 = createList();
        list1.sort((s1,s2)->s1.compareToIgnoreCase(s2)); // 대소문자 구분없이 정렬
        list1.forEach((i)-> System.out.println(i));
        System.out.println();
        // 메서드참조를 사용하여 sorting
        List<String> list2 = createList();
        list2.sort(String::compareToIgnoreCase);
        list2.forEach(System.out::println);
    }
    private static List<String> createList(){
        return Arrays.asList("ios","android","apple","samsung");
    }
}
output
android
apple
ios
samsung
android
apple
ios
samsung
android
apple
ios
samsung
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App {
    public static void main(String[] args) {
        List<String> list = createList();
        list.removeIf(s-> s.toLowerCase().contains("x"));
        list.forEach(System.out::println);
    }
    private static List<String> createList(){
        List<String> newList = new ArrayList<>();
        newList.addAll(Arrays.asList("iPhone","Ubuntu","Andriod","MAC OS X"));
        return  newList;
    }
}
output
iPhone
Ubuntu
Andriod
        HashMap<String,String> hashMap = new HashMap<String,String>(); // HashMap 생성
        HashMap<String,String> hashMap1 = new HashMap<>(); // new에서 타입 파라미터 생략가능
        HashMap<String,String> hashMap2 = new HashMap<>(hashMap); // map의 모든 값을 가진 HashMap 생성
        HashMap<String,String> hashMap3 = new HashMap<>(10); // 초기 용량 지정
        HashMap<String,String> hashMap4 = new HashMap<>(10,0.7f); // 초기 용량 지정, load factor 지정
        HashMap<String,String> hashMap5 = new HashMap<String,String>(){{put("a","b");}
        }; // 초기값 지정
★★★해당내용참고링크
        HashMap<Integer,String> hashMap = new HashMap<>(); // HashMap 생성
        hashMap.put(1,"사과");
        hashMap.put(2,"사과");
        hashMap.put(3,"바나나");
        HashMap<Integer,String> hashMap = new HashMap<Integer,String>(){{
            put(1,"사과");
            put(2,"사과");
            put(3,"바나나");
        }};
        
        
        hashMap.remove(1); // key값 1 제거
        hashMap.clear(); // 모든 값 제거
package me.whiteship.livestudy.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapExample {
    public static void main(String[] args) {
        HashMap<Integer,String> hashMap = new HashMap<Integer,String>(){{
            put(1,"사과");
            put(2,"사과");
            put(3,"바나나");
        }};
        System.out.println(hashMap); // 전체출력
        System.out.println(hashMap.get(1)); // 키값1 출력
        System.out.println();
        // entrySet() 활용
        // for문 사용
        for (Map.Entry<Integer, String> integerStringEntry : hashMap.entrySet()) {
            System.out.println(integerStringEntry.getKey() + " " + integerStringEntry.getValue());
        }
        System.out.println();
        // iterator 사용
        Iterator<Map.Entry<Integer,String>> entryIterator = hashMap.entrySet().iterator();
        while(entryIterator.hasNext()){
            Map.Entry<Integer,String> map = entryIterator.next();
            System.out.println(map.getKey() + " " + map.getValue());
        }
        System.out.println();
        //  KeySet() 활용
        // for문 사용
        for (Integer integer : hashMap.keySet()) {
            System.out.println(integer + " " + hashMap.get(integer));
        }
        System.out.println();
        // iterator 사용
        Iterator<Integer> iterator = hashMap.keySet().iterator();
        while(iterator.hasNext()){
            int key = iterator.next();
            System.out.println(key + " " + hashMap.get(key));
        }
    }
}
        TreeMap<Integer,String> treeMap1 = new TreeMap<Integer,String> (); // TreeMap 생성
        TreeMap<Integer,String> treeMap2 = new TreeMap<> (); // new에서 파라미터 생략가능
        TreeMap<Integer,String> treeMap3 = new TreeMap<> (treeMap1); // treeMap1의 모든값을 가진 TreeMap 생성
        TreeMap<Integer,String> treeMap4 = new TreeMap<Integer,String>(){{ // 초기값 설정
            put(1,"사과");
            put(2,"사과");
            put(3,"바나나");
        }};
        TreeMap<Integer,String> treeMap1 = new TreeMap<Integer,String> (); // TreeMap 생성
        treeMap1.put(1,"사과");
        treeMap1.put(2,"사과");
        treeMap1.put(3,"바나나");
        TreeMap<Integer,String> treeMap = new TreeMap<Integer,String>(){{
            put(1,"사과");
            put(2,"사과");
            put(3,"바나나");
        }};
        treeMap.remove(1); // key값 1제거
        treeMap.clear(); // 모든 값 제거
        TreeMap<Integer,String> treeMap = new TreeMap<Integer,String>(){{
            put(1,"사과");
            put(2,"사과");
            put(3,"바나나");
        }};
        System.out.println(treeMap); // 전체출력
        System.out.println(treeMap.get(1)); // key값 1의 value 출력
        System.out.println(treeMap.firstEntry()); // 최소 entry 출력 : 1,사과
        System.out.println(treeMap.firstKey()); // 최소 key 출력 : 1
        System.out.println(treeMap.lastEntry()); // 최대 entry 출력 : 3,바나나
        System.out.println(treeMap.lastKey()); // 최대 key 출력 : 3
output
{1=사과, 2=사과, 3=바나나}
사과
1=사과
1
3=바나나
3
TreeMap<Integer,String> treeMap = new TreeMap<Integer,String>(){{
            put(1,"사과");
            put(2,"사과");
            put(3,"바나나");
        }};
        //entrySet() 활용
        //for문 활용
        for (Map.Entry<Integer, String> integerStringEntry : treeMap.entrySet()) {
            System.out.println(integerStringEntry.getKey()+ " " + integerStringEntry.getValue());
        }
        System.out.println();
        //Iterator 활용
        Iterator<Map.Entry<Integer,String>> iterator = treeMap.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<Integer,String> entry = iterator.next();
            System.out.println(entry.getKey()+ " "+ entry.getValue());
        }
        System.out.println();
        //keySet() 활용
        //for문 활용
        for (Integer integer : treeMap.keySet()) {
            System.out.println(integer + " " + treeMap.get(integer));
        }
        System.out.println();
        //iterator 활용
        Iterator<Integer> iterator1 = treeMap.keySet().iterator();
        while(iterator1.hasNext()){
            int key = iterator1.next();
            System.out.println(key + " " + treeMap.get(key));
        }
`output
1 사과
2 사과
3 바나나
1 사과
2 사과
3 바나나
1 사과
2 사과
3 바나나
1 사과
2 사과
3 바나나
package me.whiteship.livestudy.Collections;
import java.util.HashMap;
import java.util.Map;
public class App {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        fillData(map);
        map.put("Python","joa");
        map.forEach((k,v)-> System.out.format("%s %s%n", k , v));
        System.out.println();
        map.remove("IOS");
        map.forEach((k,v)-> System.out.format("%s %s%n", k , v));
 }
    private static void fillData(Map<String,String> map){
        map.put("Android","SamSung");
        map.put("IOS","Apple");
        map.put("JAVA","Oracle");
    }
}
output
JAVA Oracle
IOS Apple
Android SamSung
Python joa
JAVA Oracle
Android SamSung
Python joa
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class App {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        fillData(map);
        String[] strings = keyAsArray(map);
        for (String string : strings) {
            System.out.print(string+" ");
        }
        System.out.println();
        List<String> list =  keyAsList(map);
        list.forEach(s -> System.out.print(s+ " "));
    }
    private static void fillData(Map<String,String> map){
        map.put("Android","SamSung");
        map.put("IOS","Apple");
        map.put("JAVA","Oracle");
        map.put("Python","Rossum");
    }
    private static String[] keyAsArray(Map<String,String> map){
        return map.keySet().toArray(new String[map.keySet().size()]);
    }
    private static List<String> keyAsList(Map<String,String> map){
        List<String> newList = new ArrayList<String>(map.keySet());
        return newList;
    }
}
output
JAVA IOS Android Python 
JAVA IOS Android Python 
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class App {
    public static void main(String[] args) {
        Map<String,String> map = createMap();
        map.put("NAVER",map.getOrDefault("qweqwe","helllo"));
        map.put("NAVER2",map.getOrDefault("Android","helllo"));
        map.forEach((k,v)-> System.out.println(k+ " "+ v + " "));
    }
    private static Map<String,String> createMap(){
        Map<String,String> map = new HashMap<>();
        map.put("Android","SamSung");
        map.put("IOS","Apple");
        map.put("JAVA","Oracle");
        map.put("Python","Rossum");
        return map;
    }
}
output
JAVA Oracle 
NAVER2 SamSung 
NAVER helllo 
IOS Apple 
Android SamSung 
Python Rossum 
package me.whiteship.livestudy.Collections;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class App {
    public static void main(String[] args) {
        Map<String,String> map = createMap();
        String value = map.computeIfAbsent("JAVA", it->"good");
        System.out.println(value);
        value = map.computeIfAbsent("Java", it->"good");
        System.out.println(value);
        System.out.println();
        map.forEach((k,v)-> System.out.println(k+ " "+ v + " "));
    }
    private static Map<String,String> createMap(){
        Map<String,String> map = new HashMap<>();
        map.put("Android","SamSung");
        map.put("IOS","Apple");
        map.put("JAVA","Oracle");
        map.put("Python","Rossum");
        return map;
    }
}
output
Oracle
good
JAVA Oracle 
Java good 
IOS Apple 
Android SamSung 
Python Rossum 
또한 set은 객체를 중복해서 저장할 수 없고 하나의 중복 저장이 안되기에 null값도 하나만 저장할수있다.
대표적으로 HashSet과 TreeSet 클래스가 있다.
HashSet 클래스를 보면 ArrayList와 마찬가지로 동기화를 제공하지 않는다. 또한 추가되는 요소들의 순서도 보장하지 않는다.
Set에 추가되는 요소의 순서를 부여하기 위해서는 JDK1.4버전부터 도입된 LinkedHashSet이 있다. 이 클래스의 생성자를 살펴보면 HashSet 클래스와는 조금 다른것을 알 수 있다.
        HashSet<Integer> set1 = new HashSet<Integer>(); // HashSet 생성
        HashSet<Integer> set2 = new HashSet<>(); // new에서 타입 파라미터 생략가능
        HashSet<Integer> set3 = new HashSet<Integer>(set1); // set1의 모든 값을 가진 HashSet 생성
        HashSet<Integer> set4 = new HashSet<Integer>(10); // 초기 용량 지정
        HashSet<Integer> set5 = new HashSet<Integer>(10,0.7f); // 초기용량,load factor 지정
        HashSet<Integer> set6 = new HashSet<Integer>(Arrays.asList(1,2,3)); // 초기값 지정
        HashSet<Integer> set = new HashSet<Integer>(); // HashSet 생성
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(1); // 컴파일 오류나 런타임오류가 발생하지는 않는다
        HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(1,2,3)); // HashSet 생성
        set.remove(1); // 값 1 제거
        set.clear(); // 모든 값 제거
HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(1,2,3));//HashSet생성
System.out.println(set.size());//set 크기 : 3
        HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(1,2,3)); // HashSet 생성
        System.out.println(set);
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(1,2,3));//HashSet생성
System.out.println(set.contains(1)); //set내부에 값 1이 있는지 check : true
    TreeSet<Integer> treeSet1 = new TreeSet<Integer>(); // TreeSet 생성
        TreeSet<Integer> treeSet2 = new TreeSet<>(); // new에서 타입 파라미터 생략가능
        TreeSet<Integer> treeSet3 = new TreeSet<Integer>(treeSet1); // treeSet1의 모든 값을 가진 treeSet 생성
        TreeSet<Integer> treeSet4 = new TreeSet<Integer>(Arrays.asList(1,2,3)); // 초기값 지정
TreeSet<Integer> set = new TreeSet<Integer>();//TreeSet생성
set.add(7); //값추가
set.add(4);
set.add(9);
set.add(1);
set.add(5);
TreeSet<Integer> set = new TreeSet<Integer>();//TreeSet생성
set.remove(1);//값 1 제거
set.clear();//모든 값 제거
TreeSet<Integer> set = new TreeSet<Integer>(Arrays.asList(1,2,3));//초기값 지정
System.out.println(set.size());//크기 : 3
TreeSet<Integer> set = new TreeSet<Integer>(Arrays.asList(4,2,3));//초기값 지정
System.out.println(set); //전체출력 [2,3,4]
System.out.println(set.first());//최소값 출력
System.out.println(set.last());//최대값 출력
System.out.println(set.higher(3));//입력값보다 큰 데이터중 최소값 출력 없으면 null
System.out.println(set.lower(3));//입력값보다 작은 데이터중 최대값 출력 없으면 null
		
Iterator iter = set.iterator();	// Iterator 사용
while(iter.hasNext()) {//값이 있으면 true 없으면 false
    System.out.println(iter.next());
}
output
[2, 3, 4]
2
4
4
2
2
3
4
/* LinkedHashSet Class */
public class LinkedHashSet<E> extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {
    
    ...
    
    public LinkedHashSet() {
        super(16, .75f, true);
    }
    ...
}
/* 여기서 부모 클래스의 생성인 super, 즉 HashSet의 오버로딩 생성자로 진입해보면 */
    
public class HashSet<E> extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {
    
    ...
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
    ...
}
package me.whiteship.livestudy.Collections;
import java.util.*;
public class App {
    public static void main(String[] args) {
       // 오름차순으로 정렬하는 TreeSet
        TreeSet<Integer> treeSet = new TreeSet<Integer>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1<o2 ? -1 : ((o1==o2) ? 0:1);
            }
        });
        treeSet.add(3); treeSet.add(1); treeSet.add(2);
        Iterator<Integer> iterator = treeSet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println();
        // Using JAVA 8
        TreeSet<Integer> treeSet1 = new TreeSet<>(
                ((o1, o2) -> o1<o2 ? -1: (o1==o2 ? 0:1))
        );
        treeSet1.add(3);
        treeSet1.add(1);
        treeSet.add(2);
        treeSet.forEach(System.out::println);
    }
}
output
1
2
3
1
2
3
output
java.util.Collections의 클래스는 컬렉션을 다루는 작업에 유용한 기능들을 제공해준다.
Collections.copy(list,list): 복사본 만들기
Collections.reverse(list): 역순으로 정렬하기
Collections.shuffle(list): 무작위로 섞기
Collections.sort(list): 정렬하기
package me.whiteship.livestudy.Collections;
import java.util.*;
public class App {
    public static void main(String[] args) {
        List<String> list = createList();
        List<String> list1 = new ArrayList<>();
        Collections.shuffle(list);
        list.forEach(System.out::println);
        System.out.println();
        Collections.sort(list);
        list.forEach(System.out::println);
        System.out.println();
        Collections.reverse(list);
        list.forEach(System.out::println);
        System.out.println();
        Collections.copy(list,list1);
        list1.forEach(System.out::println);
        System.out.println();
    }
    private static List<String> createList(){
        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("hi");
        list.add("good");
        return list;
    }
}
output
good
hi
hello
good
hello
hi
hi
hello
good
package me.whiteship.livestudy.Collections;
import java.util.*;
public class App {
    public static void main(String[] args) {
       List<Integer> list = Arrays.asList(3,2,1,5,4,6,7);
       Collections.sort(list);
       list.forEach(System.out::println);
    }
}
output
1
2
3
4
5
6
7
package me.whiteship.livestudy.Collections;
import java.util.*;
public class App {
    public static void main(String[] args) {
       List<Integer> list = Arrays.asList(3,2,1,5,4,6,7);
       Collections.sort(list,((o1, o2) -> o1>o2 ? -1 : (o1==o2)? 0:1 ));
       list.forEach(System.out::println);
    }
}
output
7
6
5
4
3
2
1
다음 벡터를 살펴보자.
synchronized 키워드가 있다.        List<String> list = Collections.synchronizedList(new ArrayList<String>());
        list.add("hi");
        list.add("hallo");
        list.add("hello");
        synchronized (list){
            Iterator iterator = list.iterator();
            while(iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
HashSet<String> hashSet = new HashSet<>();
Set<String> set = Collections.synchronizedSet(hashSet);
java 1.5 버전 부터 등장한 java.util.concurrent 패키지는 다양한 동시성 기능을 제공한다.
HashMap에 동기화 기능을 적용한 ConcurrentMap이 여기에 속해있다.
동기화를 위해 SynchronizedMap을 사용할수있지만 지금 살펴볼 ConcurrentMap의 성능이 더 좋다.
그 이유는 바로 동기화 블록 범위에 있다.
ConcurrentMap은 동기화를 진행하는 경우 Map 전체에 락(Lock)을 걸지않고 Map을 여러 조각으로 나누어서 부분적으로 락을 거는 형태로 구현되어 있기 때문이다.
이러한 특징은 멀티쓰레드 환경에서 더 효율적인 성능을 보인다. 테스트를 해보자
package me.whiteship.livestudy.Collections;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.IntStream;
public class ConcurrentExample {
    private static final int MAX_THREAD_POOL_SIZE = 5;
    private static final int MAX_TEST_COUNT = 5;
    private static final int MAX_OPERATE_COUNT = 100_000;
    public static Map<String,Integer> testHashTable = null;
    public static Map<String,Integer> testSyncMap = null;
    public static Map<String,Integer> testConcMap = null;
    public static void collectionPerformTest() throws InterruptedException{
      testHashTable = new Hashtable<>();
      runSomethinTest(testHashTable);
      testConcMap = new ConcurrentHashMap<>();
      runSomethinTest(testConcMap);
      testSyncMap = Collections.synchronizedMap(new HashMap<>());
      runSomethinTest(testSyncMap);
    }
    private static void runSomethinTest(Map<String, Integer> testTarget) throws  InterruptedException {
        System.out.println("Target Class" + testTarget.getClass());
        long testAverageTime = 0L;
        for (int testCount = 0; testCount < MAX_TEST_COUNT; testCount++) {
            long testStartTime = System.nanoTime();
            ExecutorService executorService  = Executors.newFixedThreadPool(MAX_THREAD_POOL_SIZE);
            // rangeClosed 는 마지막 값을 포함하여 Looping
            IntStream.range(0,MAX_THREAD_POOL_SIZE).forEach(count -> executorService.execute(()->{
                for (int i = 0; i < MAX_OPERATE_COUNT; i++) {
                     Integer randomValue =(int) Math.ceil(Math.random()*MAX_OPERATE_COUNT);
                    testTarget.put(String.valueOf(randomValue), randomValue);
                }
            }));
            // 수행 종료. 이미 수행중인 것은 마저 진행하지만 새 작업은 허용하지 않는다.
            executorService.shutdown();
            // shutdown 이후에 모든 작업이 종료되기까지 대기한다.
            executorService.awaitTermination(Long.MAX_VALUE,TimeUnit.DAYS);
            long testEndTime = System.nanoTime();
            long testTime = (testEndTime - testStartTime) / 1_000_000L;
            testAverageTime += testTime;
            System.out.println(testTarget.getClass()+"'s Test" + (testCount-1)+":"+testTime);
        }
        System.out.println(testTarget.getClass()+"'s average time is "+ testAverageTime);
        System.out.println();
    }
    public static void main(String[] args) throws InterruptedException  {
        collectionPerformTest();
    }
}
output
arget Classclass java.util.Hashtable
class java.util.Hashtable's Test-1:376
class java.util.Hashtable's Test0:209
class java.util.Hashtable's Test1:168
class java.util.Hashtable's Test2:218
class java.util.Hashtable's Test3:194
class java.util.Hashtable's average time is 1165
Target Classclass java.util.concurrent.ConcurrentHashMap
class java.util.concurrent.ConcurrentHashMap's Test-1:165
class java.util.concurrent.ConcurrentHashMap's Test0:132
class java.util.concurrent.ConcurrentHashMap's Test1:107
class java.util.concurrent.ConcurrentHashMap's Test2:115
class java.util.concurrent.ConcurrentHashMap's Test3:110
class java.util.concurrent.ConcurrentHashMap's average time is 629
Target Classclass java.util.Collections$SynchronizedMap
class java.util.Collections$SynchronizedMap's Test-1:287
class java.util.Collections$SynchronizedMap's Test0:207
class java.util.Collections$SynchronizedMap's Test1:221
class java.util.Collections$SynchronizedMap's Test2:201
class java.util.Collections$SynchronizedMap's Test3:226
class java.util.Collections$SynchronizedMap's average time is 1142