java8 컬랙션!

Collection

Framework

어플, 솔루션 개발시 구체적 기능에 해당하는 부분 설계 구현을 재사용 하도록 협업화된 형태로 제공하는 소프트웨어 환경을 뜻함.

요약하면 프레임웍은 소프트웨어 설계, 구현을 팀작업할 수 있도록 구현된 작업 환경, 표준화된 작업환경!
경력자나 초보자나 프레임워크 안에서 개발하게 되면 만들어지는 output이 비슷하다.

데이터 집합을 처리하기위해 배열을 많이 사용했는데 단점이 많기때문에 데이터 집합을 다루기 위한 표준화된 설계를 Collection FrameWork 이라 한다.

배열에 계속 데이터 집어넣는다 생각해보자.
배열 크기 부족한지 체크하고, 부족하다면 새배열 다시 만들어서 원래 배열 집어넣고 거기다 데이터집어넣고… 삽입하려고 해도 오른쪽으로 쉬프트하고… 너무 힘들다….

이런 작업들을 개발자마다 다 다르게 코딩하고있었는데 Collection FrameWork을 사용하면 위 작업을 표준화 시킬 수 있다.

이런 표준화된 기능을 구현한 클래스를 Collection Class 라고 한다.

Collection FrameWork : 초보 개발자나 고급 개발자나 표준화된 개발환경 안에서 표준화된 개발을 하도록 구성된 환경 대표적으로 Spring이 있다…
Collection Class: 데이터를 다루기 위한 기준이 표준화된 클래스

예를들어 로또 배열 중복체크하려고 함수를 만들었는데 개발자마다 중복체크 함수 구현 방법이 다 다르다.

하지만 Set이라는 Collection Class를 사용하면 애초에 중복허용을 하지 않기 때문에 중복체크할 필요가 없다!

모든 개발자는 그저 Set에 6개의 숫자가 채워질때까지 반복하기만 하면 된다. ← 표준화!

이제 Collection Class의 특징만 알면 바로 쉽게, 표준화된 코딩을 할 수 있다!

컬렉션 의 핵심 인터페이스

Collection(인터페이스) ← List(인터페이스) ← ArrayList(클래스)

Collection(인터페이스) ← Set(인터페이스) ← HashSet(클래스)

Map(인터페이스) ← HashMap(클래스)

List의 특징은 순서가 있고 중복을 허용 한다.

Set의 특징은 순서가 없고 중복을 허용하지 않는다 (순서 없고 중복허용하는 Collection Class도 있다)

Collection은 최상위 인터페이스이기 때문에 Collection 인터페이스에 있는 메서드들은 모든 Collection Class가 구현중이다. add(), remove() 등등..

그림 참고: https://hackersstudy.tistory.com/26

ArrayList

가장 많이 사용되는 컬렉션 클레스, Vector Collection Class를 개선한 클래스이다.

차이점은 Vector는 동기화처리가 가능.
ArrayList는 동기화 처리가 안된다.

동기화처리 하려면 ArrayList에서 동기화 기능 구현하거나 Vector 를 사용하자.

ArrayList도 내부적으로는 배열을 만들고 그 안에 Object를 집어넣는 구조이다.

배열이 꽉차면 더큰 배열을 생성하고 기존 내용을 큰 배열로 이동… (사용은 편하지만 효율은 그닥…)

ArrayList 원형

public class ArrayList<E> extends AbstractList<E>
	implements List<E>, RandomAccess, Cloneable, Serializable {
	transient Object[] elementData;

AbstractListList인터페이스의 뼈대구현용 추상 클래스이다.

<E>Element(요소)의 약자, 집어넣을 변수type을 지정한다.
이렇게 요소를 집어넣는 클래스를 Generic클래스라 한다.

보통 컬렉션 클래스는 제너릭 클래스로 구현하기 때문에 컬렉션 클래스를 제너릭 클래스라고도 한다.

요소에는 참조타입만 올 수 있기때문에 기본형은 넣을 수 없다.

implements(구현)부분을 보면 3개의 인터페이스를 다중 상속중이다.

RandomAccess인터페이스를 구현함으로 랜덤 접근 가능.
Cloneable인터페이스를 구현함으로 복제가능.
Serializable인터페이스를 구현함으로 전송(네트워크, 파일) 할때 통째로 전송(직렬화)이 가능하다.

ArrayList의 인스턴스화

ArrayList<Integer> list = new ArrayList<>();
list.add(1); 
list.add(2);

뒤의 <Generic Type>은 생략 가능하다.

참고: Constructs an empty list with an initial capacity of ten. 기본생성자로 생성시 초기 용량(capacity)은 10이다.

Integer래퍼 클래스를 요소로 받기 때문에 1이 Integerauto Boxing되서 넣어진다.

int num = list.get(0);
System.out.println(num);

이것도 Integer클래스가 int형으로 auto UnBoxing되서 num을 초기화한다.

제너릭을 사용하니까 Integer로 반환되는거지 따로 지정안하면 Object로 반환된다. Object로 반환되면 우리가 직접 DownCasing해야하는데 귀찮다!
즉 제너릭을 사용하는 이유는 우리가 지정한 값으로 반환하라! 고 명시하는것.
형변환 하기 싫으니까!

배열처럼 처음 값은 0부터 시작한다.

출력값

1

ArrayList의 길이(요소의 수)를 알고 싶다면

System.out.println(list.size());

ArrayList모든 요소 출력 - toString();

for (int i = 0; i < list.size(); i++) {
	System.out.println(list.get(i));
}
System.out.println(list.toString());
System.out.println(list);

toString()메서드를 생략해도 되는 이유는
println이 매개변수를 Object로 받았을때 Object클래스의 toString() 메서드를 호출하도록 println이 오버로딩 되어있기때문.
Object의 toString()을 호출해도 list방식으로 toString()이 오버라이딩 되어있기 때문에 요소전체가 출력된다.


ArrayList - add(), set() 메서드

ArrayList<Integer> list = new ArrayList<>();
list.add(1); 
list.add(2);
list.add(1, 100);
list.set(1, 10);
System.out.println(list.toString());

출력값

[1, 10, 2]

public void add(int index, E element) list의 오버로딩된 add() 메서드
index위치에 E(요소)를 추가한다.
public void add(int index, E element) list의 set() 메서드
index위치의 E(요소)를 입력한 E(요소)로 변경.


ArrayList index값 찾기 - indexOf() 메서드

ArrayList생성후 add(Element) 호출하여 랜덤값 초기화

ArrayList<Integer> list = new ArrayList<>();
System.out.println(list.size());
Random rnd = new Random();
for (int i = 0; i < 10; i++) {
	list.add(rnd.nextInt(100) + 1);
}
System.out.println(list);
System.out.print("찾을 정수 입력: ");
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
int idx = list.indexOf(num);
System.out.println(idx);

출력값

[59, 47, 80, 66, 60, 47, 88, 57, 8, 34]
찾을 정수 입력: 66
3

indexOf(Object)를 통해 찾을 참조변수의 index를 반환.


ArrayList 요소 삭제 - remove() 메서드

ArrayList의 remove함수는 2가지

  1. remove(int index)
    E	remove(int index)
    Removes the element at the specified position in this list.
    

    해당 index의 요소를 삭제하고 삭제한 요소를 반환!

  2. remove(Object o)
    boolean	remove(Object o)
    Removes the first occurrence of the specified element from this list, if it is present.
    

    Object와 일치하는 요소를 삭제! 성공 실패 여부를 boolean타입으로 반환

예제

Integer [] m = {2,4,3,5,1};		
ArrayList<Integer> list = new ArrayList<>();
list.addAll(Arrays.asList(m));
list.remove(2); //index 2번 삭제
list.remove(new Integer(5)); //요소 5를 찾아서 삭제(Object로 전달했기떄문)
System.out.println(list);

출력값

[2, 4, 1]

ArrayList->배열, 배열->ArrayList

배열->ArrayList 방법1 - Arrays의 asList()메서드 사용하기

Integer [] m = {2,4,3,5,1};		
List<Integer> list1 =Arrays.asList(m);
ArrayList<Integer> list2 = new ArrayList<>();
list2.addAll(list1);

배열->ArrayList 방법2 - Collections의 addAll()메서드 사용하기.

Integer [] m = {2,4,3,5,1};
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list	,m);

중요한건 배열이 모두 Integer배열로 선언되었다는 것. 이는 List인터페이스를 구현하는 모든 Collection Class가 참조타입만 요소로 받을 수 있기 때문.

int배열을 Integer배열로 변환하는법

int a[] = {1,2,3,4};
Integer b[] = Arrays.stream(a).boxed().toArray(Integer[]::new);

너무 어렵다…. 그냥 for문 돌려서 바꾸는 걸로….

ArrayList->배열 방법 - ArrayList의 toArray()메서드 사용하기.

Integer [] arr = list.toArray(arr);
System.out.println(Arrays.toString(arr));

ArrayList 요소에 Collection Class를 넣는 경우

ArrayList<ArrayList<String>> class5 = new ArrayList<>();
...
while( (line = br.readLine()) != null )  {
   String[] team = line.split("-")[1].trim().split("\t");
   Collections.addAll(temp = new ArrayList<>(), team);
   class5.add(temp);
}
...

Collections.addAll(temp = new ArrayList<>(), team); addAll에 temp라는 컬랙션 클래스 객체에 인스턴스생성후 team 문자열 배열 삽입
class5.add(temp); 그리고 class5 컬렉션 객체에 temp 삽입.

2차원 배열처럼 사용할 수 있다.


Collections 클래스

배열의 보조(도와주는) 클래스 Arrays.
Object의 보조 클래스 Objects.
Collection의 보조 클래스 Collections!

즉 Collections클래스도 내부의 모든 함수가 static으로 선언되어 있다. Collections에는 컬렉션 클래스에 도움될만한 각종 함수들이 정의되어 있다.

ArrayList<Integer> list1 = new ArrayList<>();
Random rnd = new Random();
for (int i = 0; i < 10; i++)
	list1.add(rnd.nextInt(100) + 1);
System.out.println(list1);

출력값

[90, 52, 97, 26, 84, 76, 77, 10, 80, 45]

위에서 보았던 ArrayList에 랜덤한값 10개 삽입

Collections의 sort() 메서드

이제 이녀석을 Collections의 sort() 메소드를 사용해서 정렬해보자.

Collections.sort(list1);
System.out.println(list1);

출력값

[10, 26, 45, 52, 76, 77, 80, 84, 90, 97]

Collections의 sort() 메소드 원형

public static <T extends Comparable<? super T>> void sort(List<T> list)
public static <T> void sort(List<T> list,
                            Comparator<? super T> c)

뭔가 접근제어자, 기타제어자, 반환형 말고 이상한게 껴있는데… 어쨋든 sort메서드는 2가지로 오버로딩 되어있다. Comparator가 필요한 것과 필요없는 것.

Collections.sort(list1); 가능한 이유는 Integer나 String같은 녀석은 이미 Comparable라는 인터페이스를 구현중이기 때문에 매개변수로 list만 넘겨도 괜찮다.

거꾸로 출력 - Collections의 reverse()메서드

descending(내림차순)하고 싶다면 정렬하고 뒤집으면 된다.

Collections.reverse(list1);
System.out.println(list1);

Vector - Collection Class

ArrayList와 거의 동일한 역할을 하는 컬렉션 클래스, 동기화 처리가 되어있기 때문에 멀티 스레드 환경에서 편하게 사용 가능하다.

Vector 원형

public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

ArrayList랑 완벽히 동일.

Vector엔 있지만 ArrayList엔 없는기능이 몇가지 있다.

  1. 용량(capacity), 늘어날 크기 지정하기
    Vector<String> vt = new Vector<>(3,5); 
    System.out.println(vt.capacity()); //3출력
    

    용량(capacity)를 3으로 잡고, 다차면 5씩 늘어남.
    할당된 용량도 출력할 수 있음. 늘어나면 늘어난 용량 출력 둘다 ArrayList에는 없는 기능이다.

  2. 각종 Element 메서드 (동기화 메서드)
    vt.addElement("aaa"); 
    vt.add("bbb");
    vt.add("ccc");
    vt.add("ddd");
    vt.add("fff");
    System.out.println(vt.size());
    System.out.println(vt.capacity());
    

    출력값

    5
    8
    

    객체뒤에 . 찍어보면 add, set, remove에 Element가 붙는 경우가 있는데 모두 동기화 처리된 메서드라 보면 된다.

vt.trimToSize();
System.out.println(vt.size());
System.out.println(vt.capacity());

출력값

5
5

trimToSize()를 통해 size만큼 용량을 줄인다(딱맞게)

Vector의 경우 동기화 처리때문에 ArrayList보다 성능이 느리다.

LinkedList

List계열이기 때문에 순서가 있고 중복허용한다.

ArrayList와의 다른점은 배열을 사용 안하고 불연속적으로 존재하는 데이터를 연결한 형태.

LinkedList는 안에 배열을 만들어서 관리하는게 아니기때문에 new 연산을통해 heap에 인스턴스를 만들어도 일단 null값이 들어간 인스턴스가 생성되고 list가 이를 가리키고있다.
자바에는 포인터 변수가 없기에 참조변수로 이를 대체한다. LinkedList 안의 멤버는 다음과 같다.

transient int size = 0;
transient Node<E> first;
transient Node<E> last;

transient는 동기화 처리를 위한 키워드같음.
자바에서 사용하는 LinkedList는 “더블리 링크드리스트(Doubly LinkedList)”를 기반으로 하고 있습니다.

Vector나 ArrayList는 내부적으로는 배열을 만들고 이를 관리하기때문에 삭제, 추가 등의 작업에서 새 배열을 만들 필요가 있었지만 LinkedList는 삭제, 추가 작업에서 그저 연결작업을 끊고 삭제나 추가한후 연결해주면 된다.

단 무조건 처음부터 접근해야 하기때문에 수정이나 특정인덱스 조회는 좀 느릴 수 있다.


Stack

last in last out 특성을 가진 자료구조

컬렉션 상속 구조 Collection - List - Vector - Stack

Vector를 상속하는 클래스이기 때문에 List의 메서드를 모두 구현중이고 내부는 배열형태로 되어있다.

Stack<String> lifo = new Stack<>(); //생성자는 하나뿐
lifo.push("test");
lifo.push("second");
System.out.println(lifo);

출력값

[test, second]

Vector를 상속하기때문에 add나 remove같은 메서드를 사용가능하지만 stack의 특성상 push, pop, peek 3가지 메서드를 쓰는것이 좋다 (LIFO구조를 항상 지키자).
add remove쓸꺼면그냥 ArrayList쓰는것이 옳다….

empty, search 메서드도 있고 찾으면 0부터가 아닌 1부터 반환, 못찾으면 -1를 반환
search말고 indexOf 써도 상관없다.


Queue

First in First Out 자료구조

Queue는 클래스가 아닌 인터페이스이다.

Queue원형

public interface Queue<E>
extends Collection<E>

그리고 LinkedList가 Queue를 구현중이다. LinkedList원형

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable

보면 Deque라는 인터페이스를 구현하고 있는데 Deque가 Queue의 하위 인터페이스이다.
따라서 Queue의 구현클래스인 LinkedList를 인스턴스화시켜 참조하는건 문제가 안된다.

Queue주요 메소드

offer() 
poll()
peek()

Queue또한 Collection인터페이스를 상속하기 때문에 add, remove 사용 가능하지만 Queue구조상 offer와 poll을 사용하는걸 권장함.

Queue<String> queue = new LinkedList<>();

queue.offer("KO");
queue.offer("JO");
queue.offer("MO");

System.out.println(queue.size());
while (!queue.isEmpty()) {
	System.out.println(queue.poll());
}
System.out.println(queue.size());

출력값

3
KO
JO
MO
0

DelayQueue

DelayQueueBlockingQueuePriorityQueue의 기능을 가지고 있는 구현체이다.

BlockingQueue 는 스레드 동기화를 위해 생긴 인터페이스이다.

take, put 메서드를 사용할 경우 꺼낼 요소가 없거나 이미 너무 많은 요소가 들어가있어 요소를 더이상 넣을 수 없다면 해당 메서드를 호출한 스레드는 넣거나 뺄 수 있을 때까지 기다리게된다.

PriorityQueue 는 지정한 값의 우선순위에 따라 데이터가 빠져나오는 순위가 달라진다.

DelayQueue의 요소로는 Delayed 인터페이스의 구현체만 들어갈 수 있는데

모든 요소는 DelayedgetDelay() 오버라이드 메서드를 구현해야 한다.
getDelayed()의 반환값이 크면 클수록 우선순위가 빨라진다.

보통 요소에는 해당 요소가 생성되고 등록된 시간을 필드로 지정하고 getDelayed()를 통해 현재시간 - 등록시간 계산을 많이 함으로
대부분의 DelayQueue에서 가장 빨리 등록된 요소가 가장 높은 우선순위를 가지게 된다.

먼저 DelayedQueue의 요소로 사용할 클래스 정의

class DelayedEvent implements Delayed
{
    private long id;
    private String name;
    private LocalDateTime activationDateTime;
 
    public DelayedEvent(long id, String name, LocalDateTime activationDateTime) {
        super();
        this.id = id;
        this.name = name;
        this.activationDateTime = activationDateTime;
    }
 
    public long getId() {
        return id;
    }
 
    public String getName() {
        return name;
    }
 
    public LocalDateTime getActivationDateTime() {
        return activationDateTime;
    }
 
    @Override
    public int compareTo(Delayed that)
    {
        long result = this.getDelay(TimeUnit.NANOSECONDS)
                        - that.getDelay(TimeUnit.NANOSECONDS);
        if (result < 0) {
            return -1;
        } else if (result > 0) {
            return 1;
        }
        return 0;
    }
 
    @Override
    public long getDelay(TimeUnit unit) {
        LocalDateTime now = LocalDateTime.now();
        long diff = now.until(activationDateTime, ChronoUnit.MILLIS);
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }
 
    @Override
    public String toString() {
        return "DelayedEvent [id=" + id + ", name=" + name + ", activationDateTime=" + activationDateTime + "]";
    }
}

출처: https://howtodoinjava.com/java/multi-threading/java-delayqueue/

그리고 다음 메인함수를 정의

public class TestDelayQueue {
    public static void main(String[] args) {
        System.out.println("test delay queue");
        DelayQueue<DelayedEvent> queue = new DelayQueue<>();
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < 10; i++) {
            queue.offer(new DelayedEvent(i, "user" + i, now.plusSeconds(i)));
            System.out.println("add " + i);
        }

        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DelayedEvent event = null;
        while ((event = queue.poll()) != null) {
            System.out.println(event);
            System.out.println(Duration.between(event.getActivationDateTime(), LocalDateTime.now()).toMillis());
        }
    }
}

Thread.sleep을 통해 4초간 쉬었다 while문으로 꺼낼 수 있는 요소를 꺼내 출력한다.

결과값

test delay queue
add 0
add 1
add 2
add 3
add 4
add 5
add 6
add 7
add 8
add 9
DelayedEvent [id=0, name=user0, activationDateTime=2019-08-13T13:43:14.379]
4012
DelayedEvent [id=1, name=user1, activationDateTime=2019-08-13T13:43:15.379]
3013
DelayedEvent [id=2, name=user2, activationDateTime=2019-08-13T13:43:16.379]
2013
DelayedEvent [id=3, name=user3, activationDateTime=2019-08-13T13:43:17.379]
1014
DelayedEvent [id=4, name=user4, activationDateTime=2019-08-13T13:43:18.379]
14

딱 5개까지, 심지어 마지막은 아슬아슬하게 0.014초 넘겨서 출력되고 메인함수가 끝나버렸다.
poll 메서드의 경우엔 스레드가 기다리고 그런거 없이 Delay때문에 못꺼내면 그냥 null반환한다.

현재시간 - 지정한시간 이 0보다 커야 (getDelay()메서드 반환값이 0보다 커야) DelayQueue에서 꺼낼 수 있다.

이번엔 for문을 for (int i = 10; i > 0; i--)으로 설정해서 큐에 집어넣고 4초후에 꺼내보도록 설정.

public class TestDelayQueue {
    public static void main(String[] args) {
        System.out.println("test delay queue");
        DelayQueue<DelayedEvent> queue = new DelayQueue<>();
        LocalDateTime now = LocalDateTime.now();
        for (int i = 10; i > 0; i--) {
            queue.offer(new DelayedEvent(i, "user" + i, now.plusSeconds(i)));
            System.out.println("add " + i);
        }

        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DelayedEvent event = null;
        while ((event = queue.poll()) != null) {
            System.out.println(event);
            System.out.println(Duration.between(event.getActivationDateTime(), LocalDateTime.now()).toMillis());
        }
    }
}

출력값

test delay queue
add 10
add 9
add 8
add 7
add 6
add 5
add 4
add 3
add 2
add 1
DelayedEvent [id=1, name=user1, activationDateTime=2019-08-13T13:44:11.634]
3011`
DelayedEvent [id=2, name=user2, activationDateTime=2019-08-13T13:44:12.634]
2012
DelayedEvent [id=3, name=user3, activationDateTime=2019-08-13T13:44:13.634]
1013
DelayedEvent [id=4, name=user4, activationDateTime=2019-08-13T13:44:14.634]
13

분명 역순으로 집어넣었는데 id=1부터 출력된다. Priority가 있기때문

take 메서드를 사용해서 DelayQueue안의 요소를 꺼내보자. 꺼낼 메서드가 없다면 꺼낼수 있을때 까지 스레드는 잠들게된다.

public class TestDelayQueue {
    public static void main(String[] args) {
        System.out.println("test delay queue");
        DelayQueue<DelayedEvent> queue = new DelayQueue<>();
        LocalDateTime now = LocalDateTime.now();
        for (int i = 10; i > 0; i--) {
            queue.offer(new DelayedEvent(i, "user" + i, now.plusSeconds(i)));
            System.out.println("add " + i);
        }

        DelayedEvent event = null;
        try {
            while ((event = queue.take()) != null) {
                System.out.println(event);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Thread.sleep() 메서드도 지웠고 바로 출력시킨다.

1초에 하나씩 출력된다.

test delay queue
add 10
add 9
add 8
add 7
add 6
add 5
add 4
add 3
add 2
add 1
DelayedEvent [id=1, name=user1, activationDateTime=2019-08-13T13:55:41.091]
DelayedEvent [id=2, name=user2, activationDateTime=2019-08-13T13:55:42.091]
DelayedEvent [id=3, name=user3, activationDateTime=2019-08-13T13:55:43.091]
DelayedEvent [id=4, name=user4, activationDateTime=2019-08-13T13:55:44.091]
DelayedEvent [id=5, name=user5, activationDateTime=2019-08-13T13:55:45.091]
DelayedEvent [id=6, name=user6, activationDateTime=2019-08-13T13:55:46.091]
DelayedEvent [id=7, name=user7, activationDateTime=2019-08-13T13:55:47.091]
DelayedEvent [id=8, name=user8, activationDateTime=2019-08-13T13:55:48.091]
DelayedEvent [id=9, name=user9, activationDateTime=2019-08-13T13:55:49.091]
DelayedEvent [id=10, name=user10, activationDateTime=2019-08-13T13:55:50.091]

일반적으로 Delay큐는 스레드와 같이 사용한다.

public class TestDelayQueue implements InitializingBean {
	private DelayQueue<DelayedEvent> delayQueue = new DelayQueue<DelayedEvent>();

	@Override
	public void afterPropertiesSet() throws Exception {
		init();
	}

    public void init() {
		new DelayQueueConsumeThread().start();
	}

    class DelayQueueConsumeThread extends Thread {
        @Override
        public void run() {
            while (true) {
                try {
                    if (delayQueue.isEmpty() == false) {
                            DelayedEvent message = delayQueue.take();
                            ...
                            ...
                        } else {
                            Thread.sleep(50);
                        }
                } else {
                    Thread.sleep(50);
                }
            } 
        }
    }
}

Comparable인터페이스 & Comparator인터페이스

Collection 제너릭 클래스 정렬방법은 2가지이다.

Class자체에서 Comparable인터페이스를 구현하던가, 정렬을 위한 Comparator인터페이스를 구현한 별도의 정렬 클래스를 만들어 주던가.

Comparable인터페이스

Collections 클래스의 sort메서드의 원형

public static <T> void sort(List<T> list, Comparator<? super T> c)

매개변수로 정렬할 List객체와 정렬을 위한 Comparator객체 2개를 필요로 한다. 하지만 Integer를 제너릭으로 갖고 있을경우 Comparator객체는 넘기지 않아도 오류가 뜨지 않는다.

ArrayList<Integer> list = new ArrayList<>();
list.add(0); list.add(2);
list.add(5); list.add(3);
Collections.sort(list);  //그냥 정렬된다! 오름차순으로
System.out.println(list);

출력값

[0, 2, 3, 5]

이유는 Integer클래스 같은 래퍼클래스들은 Comparable인터페이스를 구현중이기 때문이다.

Integer원형

public final class Integer
extends Number
implements Comparable<Integer>

Integer가 Comparable의 compateTo(Object o)메서드를 오버라이딩 중이기 때문에 Integer를 요소로 갖는 컬렉션은 Comparator없이 단독으로 sorting가능하다.

앞으로 우리가 만들 클래스를 요소로 같는 Collection클래스를 정렬할 때도 마찬가지. Comparable을 implement하거나 Comparator를 implement하는 클래스를 별도로 만들어 주거나!

class Student implements Comparable<Student>
{
	private int no;
	private String name;
	private int kor, eng, mat;
	private int tot;
	private double avg;
	private int rank;
	
	@Override
	public int compareTo(Student o) {
		return this.name.compareTo(o.name);
	}
}

우리가 만든 Student클래스에 Comparable를 구현하고 Collections의 sort메서드로 바로 정렬 가능하다.

Comparator인터페이스

Comparator를 구현해서 정렬하면 정렬기준을 원하는대로 바꿀 수 있다. 단순히 오름차순, 내림차순이 아닌 이름과 나이를 합쳐 비교한다던지…등

class StudentComparator implements Comparator<Student>
{
	private StudentSortOption sortOption;
	public StudentComparator(StudentSortOption name) {
		super();
		sortOption = name;
	}
	@Override
	public int compare(Student o1, Student o2) {
		int result = 0;
		switch (this.sortOption) {
		case NAME:
			result = o1.getName().compareTo(o2.getName());
			break;
		case SCORE:
			result = Integer.compare(o1.getTot(), o2.getTot());
			break;
		case NO:
			result = Integer.compare(o1.getNo(), o2.getNo());
			break;
			//the value 0 if x == y;a value less than 0 if x < y; anda value greater than 0 if x > y
		}
		return result;
	}
}

별도의 클래스를 위처럼 만들고

list.sort(new StudentComparator(StudentSortOption.SCORE));

객체 생성해서 ArrayList의 sort메서드에 전달, 위처럼 클래스를 따로 만들기 싫어서 익명클래스를 써도 좋다.

요약하면 Comparable을 implement해서 comparTo메서드를 구현해서 정렬하던가.
Comparator를 implement하는 클래스를 만들고 그 클래스 안에서 compare메서드를 구현해서 정렬하던가.

참고: https://cwondev.tistory.com/15

환경변수 읽기 - getEnv()

환경변수 : OS에서 Name과 value로 관리되는 문자열

String javaHome = System.getenv("JAVA_HOME");
System.out.println(javaHome);

출력

//C:\Program Files\Java\jdk1.8.0_192

모든 환경변수 출력, 처음쓰는 컬렉션!

Map<String,String> map = System.getenv();

Set<String> s = map.keySet();
//Set<K> keySet()
//Returns a Set view of the keys contained in this map, 
//Set이라는 Key와 Value가 들어간 자료형 반환

Iterator<String> ir = s.iterator();  //Iterator : 반복자
while(ir.hasNext())
{
	String envName = ir.next();
	System.out.printf("%s: %s\n", envName, System.getenv(envName));
}

출력

C:\Program Files\Java\jdk1.8.0_192
USERDOMAIN_ROAMINGPROFILE: KGY19
LOCALAPPDATA: C:\Users\kgy19\AppData\Local
PROCESSOR_LEVEL: 6
USERDOMAIN: KGY19
FPS_BROWSER_APP_PROFILE_STRING: Internet Explorer
LOGONSERVER: \\KGY19
....

카테고리:

업데이트: