카테고리 없음

자바의 자료구조의 대한 노트

일반정보 2021. 7. 31. 08:05

 

 

○ 들어가는 글

이번 글은 원래 자바를 공부하거나, 혹은 추후에 사용할 때 헷갈리는 부분을 한번에 보기 위해서 정리해 놓은 노트였습니다. 따라서 비공개 였으나, 계속 쓰다 보니 양이 좀 되는 것 같아서 따로 하나의 문서로 만들게 되었습니다. 

저는 쉽게 쉽게, 자바를 사용하다가 햇갈리는 부분이 있으면 그 때 그 때 참고하려고 합니다. 자주쓰는 코드나, 패키지 등을 확인하는데 유용할 것입니다. 

예시코드는 아래 웹 컴파일러를 기준으로 작성하였습니다.  

https://replit.com/languages/java10

 

Java Online Compiler & Interpreter

Write and run Java code using our Java online compiler & interpreter. You can build, share, and host applications right from your browser!

replit.com

 

 

1. 배열

○ 배열은 사실 기초가 되는 자료구조이자, 심화적으로 보면 신셩쓸 것도 많은 것은 사실입니다만, 우선 여기에서는 간단히만 넘어가려고 합니다. 이 부분은 따로 글을 쓸 수 있을 때 써 보도록 하죠. 우선 간단히 자주 쓰는 것들만 적어 놓았습니다. 

  • 배열을 출력할 때는 Array.toString() 메서드나, Array.deepToString() 을 사용할 수 있다. 
System.out.println(Arrays.toString(StringArr));
  • copyOf, copyOfRange도 사용 가능  -> 배열을 그냥 대입식면 참조된다. 따라서 위와 같이 복사 해야 한다. 
int[] temp = Arrays.copyOf(array, arrayLength);
int[] temp = Arrays.copyOfRange(array, startIdx, endIdx);

 


 

2. 문자열 - String, StringBuilder, StringJoiner

○ 스트링도 어떻게 보면 자료구조라고 볼 수 있을 것 입니다. 문자의 배열 버전이라고 볼 수 있으니까요. 다만 String 은 결국 정적 이기때문에 자료구조로 사용하기에는 조금 부족한 감이 있습니다. 따라서, 여기에서는 자료구조로 사용하기 위한 StringBuilder를 기준으로 정리하려고 합니다. StringBuilderd은 쉽게 생각하면 Mutable 한 String이라고 생각하시면 될 것입니다. 수정이 가능하지요.

  • 기본적으로 String은 클래스이다. 
  • StringBuilder와 StringJoiner를 활용할 수 있다. String과 동일하지만, 내부를 변경이 가능하다.
    • StringBuilder   
      • StringBuilder 생성 :  StringBuilder str = new StringBuilder()
      • Stringbuilder 에 문자열 추가 : StringBuilder.append() 
    • StringJoiner 
      • StringJoiner 생성 : StringJoiner strJoiner = new StringJoiner( -Split String- )
      • StringJoiner 에 문자열 추가 : StringJoiner.add() 
  • 그 외 유용한 String클래스의 메서드 들이 존재한다. 
    • String.join() - 배열을 구분자를 기준으로 String 으로 결합
    • String.split() - String을 구분자를 기준으로 배열로 분리
    • String.charAt(Idx) - String의 요솟값에 접근
    • String.substring(start_Idx , end_Idx) - String중 범위 지정한 String을 반환
import java.util.Arrays;
import java.util.StringJoiner;

class Main {  
  public static void main(String args[]) { 

	//1
	String str = "hello world!";
	System.out.println(str);

	  
	//2
	String[] strArr = {"Hello","World","!!"};
 
	StringBuilder strBuilder = new StringBuilder();
	StringJoiner strJoiner = new StringJoiner(" ");

	for(String i : strArr){
		strBuilder.append(i);
	}
	
	for(String i : strArr){
		strJoiner.add(i);
	}

	System.out.println(strBuilder);
	System.out.println(strJoiner);

	  
	//3
	String str2 = "hello java!!"; 
	String[] strArr2 = {"apple","banana","cat"};  
	  
	String strToJoin = String.join("",strArr2);
	String[] strToSplit = str2.split(" ");
	  
	System.out.println(strToJoin);
	System.out.println(Arrays.toString(strToSplit));
	System.out.println(str2.substring(3,7) ); 
	System.out.println(str2.charAt(0));
	  
  } 
}

 


 

3. List(arrayList) 활용

○ 자바의 컬렉션 중 하나인 List입니다. 기본적으로 다른 언어에서 볼 수 있는 List와 비슷합니다. Kotlin에서 설명한 것과 크게 다른 것은 없습니다. 인터페이스 구조는 여기서는 다루지 않겠습니다.

  • List1.add(Item) - 리스트에 추가시에 사용된다. 
  • List1.get(Item) - 리스트에 참조시에 사용된다.
  • List1.contains(Item) - 리스트에 항목 존재 여부 참조시에 사용된다.
  • List1.indexOf(Item) - 리스트에 항목의 인덱스 참조에 사용된다.
  • List1.add(Item) - 리스트에 추가시에 사용된다.
  • List1.sort(null) - 리스트에 정렬시 사용된다.
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;


class Main {  
  public static void main(String args[]) { 
	ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(10,7,8,1));

	System.out.println(list);

	list.sort(null);
	Collections.sort(list); 
    System.out.println(list);
	  
	list.add(5);
	list.add(null);
	list.add(0,3);  
    System.out.println(list);
	  
	System.out.println(list.get(0));
	System.out.println(list.contains(5)); 
	System.out.println(list.indexOf(5)); 
	System.out.println(list);

	list.remove(1);
	list.clear();

	System.out.println(list);
  } 
}

 


 

4. set의 활용

○ 이 또한 크게 다른 점은 없습니다. 요소간의 중복을 허용하지 않지요. 간단히만 짚고 넘어가겠습니다. 개인적으로 자주쓰는 컬렉션중 하나입니다. 집합연산이 의외로 많이 쓰이지요.

  • 마땅히 변환활 수 없을 때에는 for문으로 일일히 수행해야 한다. 
  • 자바에서 for문은 아래처럼 지원하기도 한다. 
  • hashSet은 합집합, 교집합등등을 지원하기도 한다. kotlin에서는 연산기호로 가능했지만 여기에서는 특정 메서드를 사용해야 한다. 
  • set1.addAll(set2) - 합집합이 반환된다. 
  • set1.retainAll(set2) - 교집합이 반환된다.
  • set1.removeAll(set2) - 차집합이 반환된다. 
  • set1.containsAll(set2) - 부분 집합 여부 -> 이는 참 거짓이 반환된다. 
  • set1.add(item) - 요소를 추가할 때 사용한다. 
  • set1.remove(item) - 요소를 지울 때 사용한다. 
  • set1.sorted() - 요소를 정렬하는데 사용된다. 
import java.util.Arrays;
import java.util.HashSet;

class Solution {
    public int solution(int n, int[] lost, int[] reserve) {
    
        HashSet<Integer> reserveNum = new HashSet<>();
        HashSet<Integer> lostNum = new HashSet<>();
        HashSet<Integer> retainNum = new HashSet<>();
        
        for( int i : lost ){
            lostNum.add(i);
        }
        
        for( int i : reserve ){
             reserveNum.add(i);
        }
        
        retainNum.addAll(lostNum);
        retainNum.retainAll(reserveNum);
        
        reserveNum.removeAll(retainNum);
        lostNum.removeAll(retainNum);
            
        int answer = n - lostNum.size();
        
        
        
        for( int i : lostNum ){
            for( int j : reserveNum ){
                
                if( i == j + 1 || i == j - 1 ){
                    answer++;
                    reserveNum.remove(j);
                    break;
                } 
            }            
        }

        return answer;
    }
}

 

 


 

5. Map의 활용

○ Key와 Value로 이루어진 구조체 입니다. 이 또한 크게 다른 점은 없기 때문에 간단히만 짚고 넘어가겠습니다. kotlin과 비교할 만 한게 있다면, 참조시에 null을 피하기 위해서라도 .getOrDefault()를 자주 사용하게 된다는 점 입니다. 

  • 요소의 참조시에 .get(key)
  • 만약 해당 key가 없다면 null을 반환하게 된다. 이는 오류가 발생할 수 있으니. 요소의 참조시에 .getOrDefault(key,defaultValue)를 사용하자.
  • .merge(key,Value,Lamda) 메서드는 업데이트 시에 유용하다. 메서드 참조나 람다를 같이 이용해보자. 
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Collections;
import java.util.HashMap;


class Main {  
  public static void main(String args[]) { 
	HashMap<Integer,String> map = new HashMap<Integer,String>(){{put(0,"딸기");}};

	map.put(1,"사과");
	map.put(2,"바나나");
	map.put(3,"포도");

	System.out.println(map);
	System.out.println(map.get(1));
    System.out.println(map.getOrDefault(5,"없음"));

	map.remove(0);
	System.out.println(map);

	map.clear();
	System.out.println(map);	 
	  
  } 
}

 


 

6. 컬렉션의 공통

위의 컬렉션들(Map 제외)들은 기본적으로 컬렉션을 상속받는 인터페이스 입니다.  따라서 각 컬렉션 마다 보통은 공통적으로 사용하는 메서드나 고려해야할 사항이 있지요. 여기에 대강 적어두었습니다. 

  • 대부분의 컬렉션은 괄호안에 숫자를 넣으면 크기지정이 된다. 
  • 반대로 컬렉션(List,Set)등을 넣으면 그 요소가 들어있는 컬력션이 생성된다.
  • Map의 경우 컬렉션을 초깃값으로 지정할 수 없다.  put을 사용해야 한다.
  • 요소의 추가는 약간 다르지만, 다음과 같은 공통이 있다. 
    • 요소의 참조는 .get() 
    • 요소의 설정은 .set()
    • 요소의 삭제는 .remove()
    • 요소의 전체삭제는 .clear()
    • 요소의 크기 조회 .size()
    • 요소의 추가(List,Set) -> .add()  // (Map) -> .put()
    • 요소의 여부 확인(List,Set) -> .contains() 
    • 요소의 정렬(List,Set) -> .sort(null)  ||  Collections.sort() ||  .stream().sorted()
    • 요소 자르기(List,Set) -> .subList(start_Idx,) , subSet(end_Idx)
  • Arrays.asList()는 바로 list를 간편하게 생성할 수 있는 키워드이다. 간편하니 외워두자
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.HashMap;


class Main {  
  public static void main(String args[]) { 
    HashSet<Integer> set = new HashSet<>(Arrays.asList(1,2,3)); //Set

	ArrayList<Integer> list = new ArrayList<>(set); //Set -> ArrayList

	HashMap<String,String> map = new HashMap<String,String>(){{//초기값 지정
    put("a","b");}};
        
	System.out.println(set);
	System.out.println(list);
	System.out.println(map);
  } 
}

 


 

7.정적 컬렉션

○ Mutable 하지 않은, 즉 변경할 수 없는 컬렉션을 의미합니다. 요소를 변경할 수 없지만, 간편하기 때문에 의외로 자주 쓰게 됩니다. 

  • 기본 컬렉션 (List, Set, Map)의 경우에는 of 메서드로 정적 메서드를 만들 수 있다. 
  • 기본 컬렉션 (List, Set, Map)외의 컬렉션은 of 메서드사용할 수 없는 듯 하다. 
  • Map의 경우 .ofEntries() 메서드를 통해서 정적메서드를 만들 수 있다. (import static java.util.Map.*
    ) 필요
  • 정적메서드는 Mutable컬렉션이 아니다. 따라서 Mutable컬렉션으로 사용하려면 컬렉션 생성시, 정적 컬렉션을 생성자의 파라미터로 넣으면 된다. -> ( ex.  ArrayList<Integer> arrList = new ArrayList<>(List.of(1,2,3)) )
  • 수정 불가 컬렉션도 존재한다. (ex. UnModifiableList) -> 읽기 전용
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static java.util.Map.*;

class Main {  
  public static void main(String args[]) { 

	List<Integer> list = List.of(1,2,3);
	Set<Integer> set = Set.of(1,2,3);
	Map<String, Integer> map = Map.of("a",1,"b",2);

	System.out.println(list);
	System.out.println(set);
	System.out.println(map);

	ArrayList<Integer> arrList = new ArrayList<>(list);
	HashSet<Integer> hsSet = new HashSet<>(set);
	HashMap<String, Integer> hsMap = new HashMap<>(map);

	System.out.println(arrList);
	System.out.println(hsSet);
	System.out.println(hsMap);

	Map<String,String> entries = ofEntries(
		entry("hello","world")); 

	System.out.println(entries);
	  
  } 
}

 


 

8. 스트림

스트림은 컬렉션의 연산을 더 유용하게 해 줍니다. 여러가지 특징이 있고 이를 이해만 한다면 매우 유용합니다. 

  • 스트림은 다음과 같은 특징이 있다. 
    • 모든 컬렉션은 스트림 메서드를 가지고 있다. 
    • 종류로는 .stream() .parallelStream() 등이 있다. 
    • 스트림은 지연방식을 사용한다. 즉 스트림의 마지막 연산이 나올때까지 계속 연산한다. (아마도)
    • 컬렉션의 종류와 무관하게 반환은 기본적으로 Stream 클래스이다. 
    • 스트림은 중간 연산자 종료연산자(리덕션)으로 나뉘며, 람다함수와 메서드:생성자 참조 사용이 가능하다.
    • 중간연산자는 스트림 도중에 연산을 수행한다. (filter(), map(), flatMap() 등..)
    • 종료연산자는 스트림의 연산을 끝내고, 특정 형식으로 변환해서 반환한다. (count(), sum(), max() 등)
  • 스트림은 다음과 같은 방식으로 생성이 가능하다. 
    • Stream.of( ... ) - 가변인수 또는 배열을 넣어 만들 수 있다. 
    • Stream.empty() - 빈 스트림을 만든다. 
    • Stream.generate( Lamda ) - 무한 스트림을 만든다. 
    • Arrays.stream( arr, from. to ) - 배열 일부만을 잘라서 만들 수 있다.
import java.util.Arrays;
import java.util.stream.Stream;

class Main {  
  public static void main(String args[]) { 

	String[] arr = {"a","b","c","d"};
	  
	Stream<Integer> stm1 = Stream.of(1,2,3,4);
	Stream<String> stm2 = Arrays.stream( arr, 1, 3 );
	Stream<Integer> emptyStm = Stream.empty();

	stm1.forEach(System.out::print);
	System.out.println("");
	  
	stm2.forEach(System.out::print);
	System.out.println("");
	  
	emptyStm.forEach(System.out::print);
	System.out.println("");
  } 
}

 


 

9. 스트림 중간 연산자

○ 스트림 중 중간연산을 할 수 있는 연산자들입니다.

  • 스트림의 대표적인 중간 연산자로는 map(), filter(), flatMap() 등이 있다. 
    • map() - 스트림, 컬렉션의 요소들을 매핑한 스트림을 반환한다. 
    • filter() - 스트림, 컬렉션의 요소들 중 조건에 맞는 것들의 스트림을 반환한다. 
    • flatMap() -  map()과 비슷하지만, 내부의 요소까지 참조해서 하나의 스트림으로 반환하는 차이점이 있다. 
  • 컬렉션에서 사용하려면, 컬렉션 내부의 .stream() 메서드를 통해 스트림으로 바꿀 수 있다. 
  • 중간연산자, 종료연잔자와 혼합하여 사용 가능하다. 
import java.util.stream.Stream;
import java.util.List;

class Main {  
  public static void main(String args[]) { 

	  
	Stream<Integer> stm = Stream.of(1,2,3,4,5,6,7,8,9,10);
	Stream<Integer> stm2 = Stream.of(1,2,3,4,5,6,7,8,9,10);
	List<Integer> list = List.of(1,2,3,4,5,6,7,8,9,10); 
	  
	stm.map(w-> w * 2).forEach(System.out::print);
	System.out.println("");
	  
	stm2.filter(w-> w > 5).forEach(System.out::print);
	System.out.println("");
		
	long num = list.stream().map(w-> w * 2).filter(w-> w > 5).count();
	System.out.println(num);
	  
  } 
}

 


 

10. 종료 연산자

○ 리덕션이라고도 합니다. 스트림의 결과를 모으거나 정리해서 반환하는 역활을 합니다. 반환형식은 기본적으로 optional 임에 주의합니다. 

1. 리덕션 - 스트림을 다시 바꾸어서 사용할 수 있다. 

  • 단순 출력  :   .forEach(System.out::println)
  • 배열로 변환  :   .toArray(String[]::new)
  • 컬랙션으로 변환  :   .collect(Collectors.toList())  //   .collect(Collectors.toSet())
  • 컬렉션으로 변환(map이 객체를 담고 있을 경우) :  .collect(Collectors.toMap(class::key,class::value))
  • joinToString의 효과  :   .collect(Collectors.joining()) 

 

2. 단순 리덕션 - 스트림의 요소 중에서 메서드의 따라 반환형식이나 결과가 다르게 나온다. 대표적으로 다음이 있다. 

  • .count()  :  요소들의 갯수를 반환 
  • .max()  :  요소중의 최댓값을 반환 
  • .min()  :  요소중의 최솟값을 반환
  • .sum()  :  요소의 총합을 반환
  • .average()  :  요소의 평균을 반환 
  • .reduce() : map()처럼 활용하면서 연산을 할 때 사용된다. 
  • 그 외 : .findFrist(), findAny() 등등 다양한 연산자가 존재한다. 
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

class Main {  
  public static void main(String args[]) { 

	List<Integer> list = List.of(1,2,3,4); 
	Set<String> set = Set.of("A","B","C","D"); 
	
	List<Integer> newList = list.stream().map(i->i+1).collect(Collectors.toList());
	Set<Integer> newSet =  set.stream().map(i-> i.length()).collect(Collectors.toSet());

	System.out.println(newList);
	System.out.println(newSet);

	int sum = newList.stream().mapToInt(i->i).sum();
	long count = newSet.stream().count();

	System.out.println(sum);
	System.out.println(count);

		
  } 
}

 


 

11. 스트림을 이용한 형변환

○ 스트림 연산을 유용하게 하려면 요소간의 형변환이 필요하게 될 경우가 있습니다. 아래에는 자주 사용 될 수 있는 것들을 모아봤습니다. 

1. 기본 타입 스트림과 map 

  • 스트림의 요소들은 기본적으로 요소들은 오브젝트이여야 한다. 
  • 만약 기본 연산자(int, long)는 기본타입 스트림을 사용해야 한다.
    • 기본타입 스트림을 사용할 경우 - IntStream, LongStream, DoubleStream등
  • 만약 스트림의 요소를 기본타입으로 바꾸려면 map을 통해 바꿀 수 있다. 반환은 각 기본타입 스트림이 된다.  
    • mapToInt() - [ Stream -> IntStream ]
    • mapToLong() - [ Stream -> LongStream ]
    • mapToDouble() - [  Stream -> DoubleStream ]

 

2. map의 활용한 형변환

map()과 참조 메서드, 생성자를 사용하면 스트림상 형변환이 가능하다. 

  • 기본적으로 클래스 형으로 바꾸고자 한다면 .valueOf() 를 사용한다. 
    • Integer::valueOf :   ( Any -> Integer )
    • String::valueOf :   ( Any-> String )
  • int로 바꾸고자 한다면 Integer의 .parseInt() 를 사용한다. 
    • Integer::parseInt :   ( Any -> int )

 

3. 스트림을 배열로 변환

  • 스트림은 .toArray()메서드를 가지고 있다. 이를 통해 스트림을 배열로 변환 가능하다. 
  • int를 클래스 형으로 바꿀때에는 생성자를 이용해야 한다. 참조 생성자를 사용하면 편리하다. 
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;

class Main {  
  public static void main(String args[]) { 

	List<Integer> intList = List.of(1,2,3,4,5,6,7,8,9,10); 
	List<String> stringList = List.of("1","2","3","4"); 

	String[] StringArr = intList.stream().map(String::valueOf).toArray(String[]::new); // Integer List -> Stirng arr  
	int[] intArr = stringList.stream().mapToInt(Integer::parseInt).toArray(); // String List -> int arr

	System.out.println(Arrays.toString(StringArr));
	System.out.println(Arrays.toString(intArr));

	List<Integer> newIntList = Arrays.stream(intArr).boxed().collect(Collectors.toList()); // int arr -> Integer List  
	List<String> newStringList = List.of(StringArr); // Stirng arr  -> Stirng List

	System.out.println(newIntList);
	System.out.println(newStringList);
	  
  } 
}

 

 

 


 

 

참고자료는 다음과 같습니다. 

 

JAVA - ArrayList에서 배열로, 배열에서 ArrayList로

프로그래밍을 하다보면 데이터 자료구조를 변환해야 할 때가 있다. 오늘 포스팅은 ArrayList or List 배열(Array)로 변환하는걸 다루어본다. 중요한건 자료구조를 바꾸는 것이지 자료형은 일치해야 한

mommoo.tistory.com