[Java] Stream, Collection

2025. 8. 15. 16:33·Java

개요

Java에서는 방대한 데이터를 효율적으로 다루기 위해 Collection과 Stream이라는 강력한 도구를 제공합니다. Collection은 데이터를 저장하고 관리하기 위한 자료구조의 집합이며, Stream은 이러한 데이터를 보다 선언적이고 간결하게 처리할 수 있도록 돕는 API입니다. 이 두 가지를 이해하면 반복문과 조건문에 의존하던 기존 방식에서 벗어나, 가독성과 유지보수성이 높은 코드를 작성할 수 있게 됩니다. 

 

이해를 돕기 위해 Stream, Collection 관련 예제 코드를 작성해 보았는데, 첨부된 링크를 통해 확인하실 수 있습니다.

https://github.com/daily1313/java-stream-collection

 

GitHub - daily1313/java-stream-collection: java stream and collection (java 17)

java stream and collection (java 17). Contribute to daily1313/java-stream-collection development by creating an account on GitHub.

github.com

 

 

Stream

  • 일련의 데이터의 흐름을 표준화된 방법으로 쉽게 가공, 처리할 수 있도록 도와주는 클래스
  • 요소들의 Stream에 함수형 연산을 지원하는 클래스
  • Stream API는 이러한 작업을 간편하게 수행할 수 있도록 다양한 기능을 제공할 뿐만 아니라, 병렬 처리를 통해 처리 속도를 높일 수 있습니다.
  • 따라서, Collection F/W를 통해 관리하는 데이터를 처리하기 위해 주로 사용합니다.
  • Stream API의 다양한 기능들은 대부분 람다를 필요로 하기 때문에 람다를 이해하고 사용할 수 있어야 합니다.

 

Stream 연산 

  • 각 연산의 연결을 통해 파이프라인을 구성합니다.
  • 파이프라인을 구성할 수 있다는 것은 스트림 대상 데이터에 대한 다양한 연산을 조합할 수 있다는 것을 의미합니다.
  • 스트림을 이용한 연산 처리는 스트림 객체의 생성부터 중간 연산, 그리고 최종 연산 단계로 구분합니다.
  • 스트림 객체가 제공하는 다양한 연산을 이해하고 연산에 필요한 람다표현식을 이해하고 적용하는 것이 중요합니다.

  

즉, 스트림 생성 -> 가공(중간 연산) -> 최종연산의 과정을 거치게 되는데, 해당 과정에 대해 상세하게 설명드리고 관련 예제도 살펴보도록 하겠습니다.

 

Stream 생성

  • 데이터의 컬렉션(집합)을 Stream으로 변환하는 과정입니다.
  • Stream API를 사용하기 위해서 최초 1번 수행되어야 하며, 생성 단계에서는 모든 데이터를 한꺼번에 불러오지 않고 필요할 때만 불러옵니다.
    • 이를 통해 메모리 사용량을 최적화하고 효율성이 증대됩니다.

Stream 가공(중간 연산)

  • 가공(중간연산): 소스의 데이터 집합을 원하는 형태로 가공하는 것
    • filter, map과 같은 연산으로 Stream을 반환합니다.
    • 중간 연산은 연속에서 호출하는 메소드 체이닝으로 구현이 가능합니다.
    • 최종 연산이 실행되어야 중간연산이 처리되므로 중간연산들로만 구성된 메서드 체인은 실행되지 않습니다. (Lazy Evaluation)
    • Lazy Evaluation: 최종 연산을 호출하기 전까지 중간 연산을 지연시키는 행위
  • 가공의 종류
    • filter: 필터 처리 (조건문을 통한 데이터 선별)
    • map: 데이터 변환
    • sorted: 정렬
    • peek: 가공된 데이터를 파악하기 위한 용도
    • disctinct: 중복 제거
    • limit: 개수 제한

Stream 최종 연산

  • 최종연산: Stream에 대한 최종 연산을 수행하는 것. (최종적인 목적물을 얻는 처리과정)
    • forEach, collect와 같은 연산으로 void를 반환하거나 컬렉션 타입을 반환
    • 스트림이 관리하는 전체 데이터에 대한 순회 작업은 최종 연산인 forEach() 메서드를 이용합니다.
    • collect() 메소드는 스트림 처리 이후 처리된 데이터에 대해 Collection 객체로 반환하는 메서드입니다.
    • 스트림의 최종 연산은 forEach()와 같은 스트림 처리 결과를 바로 확인할 수 있는 연산이 있고, 데이터를 모두 소모한 이후에 그 결과를 알 수 있는 count()와 같은 연산이 있습니다.
    • 이 외에도 특정 데이터를 검색할 수 있는 allMatch(), anyMatch() 등과 같은 다양한 메서드들을 제공합니다.
  • 최종 연산 종류
    • forEach(): stream의 각 요소를 순회하면서 출력 등의 처리를 위해 사용합니다.
    • reduce(): stream의 요소를 줄여나가면서 연산을 수행합니다.
    • findFirst(), findAny(): 특정 조건에 맞는 요소를 찾기 위해 사용합니다.
    • anyMatch(), allMatch(), noneMatch(): 조건에 맞는지 확인을 위해 사용합니다.
    • count(), min(), max(), sum(), average(): 요소의 개수, 최소(대)값, 합계, 평균을 위해 사용합니다.
    • collect(): stream의 요소를 수집하여 원하는 형태로 변환하기 위해서 사용합니다.
      • toList(), toSet(), toCollection(), toArray(), toMap()

Stream 특징

  • 선언적으로 코딩이 가능합니다.
  • 연속적으로 필터링, 매핑, 정렬을 체이닝으로 표현할 수 있습니다.
  • 간결하고 명확한 코드로 데이터를 처리할 수 있어서 코드의 유지보수성과 가독성이 향상됩니다.
  • 병렬처리를 지원합니다. (멀티스레드로 병렬처리 후 대량의 데이터를 빠르고 쉽게 처리) (parallel(), parallelStream())

Stream의 전 과정에 대해 상세하게 설명드렸으니, Stream을 활용한 예제 코드를 살펴보겠습니다. 

 

Stream Example

classpath에 user.csv 파일이 제공되어 있다고 가정합니다.

이름, 취미, 소개
김프로, 축구:농구:야구, 구기종목 좋아요
정프로, 개발:당구:축구, 개발하는데 뛰긴 싫어
앙몬드, 피아노, 죠르디가 좋아요 좋아좋아너무좋아
죠르디, 스포츠댄스:개발, 개발하는 죠르디 좋아
박프로, 골프:야구, 운동이 좋아요
정프로, 개발:축구:농구, 개발도 좋고 운동도 좋아

 

1.  취미별 선호 인원 구하기

- Solution-1
public Map<String, Integer> quiz1() throws IOException {
    List<String[]> csvLines = readCsvLines();

    Map<String, Integer> results = csvLines.stream() // 스트림 생성
            .flatMap(line -> Arrays.stream(line[1].replaceAll("\\s", "").split(":"))) // 중간 연산
            .collect(Collectors.toMap(k -> k, v -> 1, Integer::sum)); // 최종 연산

    results.entrySet().forEach(entry -> {
        System.out.println(entry.getKey() + ":" + entry.getValue());
    });

    return results;
}

- Solution-2
public Map<String, Integer> quiz1() throws IOException {
    List<String[]> csvLines = readCsvLines();

    Map<String, Integer> results = new HashMap<>();

    csvLines.stream()
            .flatMap(line -> Arrays.stream(line[1].replaceAll("\\s", "").split(":")))
            .forEach(hobby -> results.merge(hobby, 1, Integer::sum));

    results.entrySet().forEach(entry -> {
        System.out.println(entry.getKey() + ":" + entry.getValue());
    });

    return results;
}

private List<String[]> readCsvLines() throws IOException {
    CSVReader csvReader = new CSVReader(new FileReader(getClass().getResource("/user.csv").getFile()));
    csvReader.readNext();
    return csvReader.readAll();
}
  1. csv 파일을 CsvReaders 클래스를 통해 한 줄씩 파싱합니다.
  2. flatMap 메서드를 통해 콜론을 기반으로 파싱 한 데이터를 한 번에 불러옵니다. 
    1. flatMap: Stream<String> 형식으로 모든 원소가 한 줄로 펼쳐집니다. --> flatMap을 활용하려면 새롭게 스트림을 생성 (Arrays.stream())을 해주어야 합니다. 
    2. Map: Stream<Stream<String>> 형식으로 스트림 안에 스트림이 들어있는 형태입니다.
  3. collect(), forEach() 메서드를 통해 각 취미별 선호하는 count를 집계합니다.

 

2.  List 데이터 가공하기 

private static List<String> WORDS = Arrays.asList("TONY", "a", "hULK", "B", "america", "X", "nebula", "Korea");

    // 2.1 List에 저장된 단어들의 접두사가 각각 몇개씩 있는지 Map<String, Integer>으로 변환하여라.
    // ex) ("T", 1), ("a", 2) ...
    public Map<String, Integer> quiz1() {
        Map<String, Integer> results = WORDS.stream()
                .map(word -> word.substring(0, 1))
                .collect(Collectors.toMap(key -> key, value -> 1, Integer::sum));

        results.entrySet().forEach(entry -> {
            System.out.println(entry.getKey() + " : " + entry.getValue());
        });

        return results;
    }

    // 2.2 List에 저장된 단어들 중에서 단어의 길이가 2 이상인 경우에만, 모든 단어를 대문자로 변환하여 스페이스로 구분한 하나의 문자열로 합한 결과를 반환하여라.
    // ex) ["Hello", "a", "Island", "b"] -> “H I”
    public String quiz2() {
        String result = WORDS.stream()
                .filter(word -> word.length() >= 2)
                .map(word -> word.substring(0, 1).toUpperCase())
                .collect(Collectors.joining(" "));

        System.out.println(result);
        return result;
    }
  1. 조건에 입각하여 filter 처리를 해줍니다. (Prefix 추출, 단어수 2 이상)
  2. map으로 Prefix 데이터를 변환해 줍니다.
  3. collect()를 통해 최종 연산의 결과를 테스트 케이스에 맞게 반환합니다. 

3. 문자열 가공, 임의 로또 번호 생성, 주사위 값 6인 리스트 반환

public class Q5 {

    private static final String[] STRING_ARR = {"aaa", "bb", "c", "dddd"};

    // 5.1 모든 문자열의 길이를 더한 결과를 출력하여라.
    public int quiz1() {
        return Arrays.stream(STRING_ARR)
                .mapToInt(String::length)
                .sum();
    }

    // 5.2 문자열 중에서 가장 긴 것의 길이를 출력하시오.
    public int quiz2() {
        return Arrays.stream(STRING_ARR)
                .mapToInt(String::length)
                .max().orElse(0);
    }

    // 5.3 임의의 로또번호(1~45)를 정렬해서 출력하시오.
    public List<Integer> quiz3() {
        return IntStream.rangeClosed(1, 46)
                .distinct()
                .limit(6)
                .sorted()
                .boxed() // IntStream -> Stream<Integer>로 변환
                .collect(Collectors.toList());
    }

    // 5.4 두 개의 주사위를 굴려서 나온 눈의 합이 6인 경우를 모두 출력하시오.
    public List<Integer[]> quiz4() {
        return IntStream.rangeClosed(1, 5) 
            .mapToObj(i -> new Integer[]{i, 6 - i})
            .collect(Collectors.toList());
    }
}

 

  1. 5-1, 5-2: 문자열 배열을 Int 형식으로 변환하여 문자열의 길이의 합, 최대 길이를 구해줍니다.
  2. IntStream을 활용하여 로또 번호를 생성합니다.
    1. distinct(): 중복을 제거
    2. limit(): 6개만 선택
    3. sorted(): 오름차순 정렬
    4. boxed(): IntStream -> Stream<Integer>로 변환  
  3. IntStream을 활용하여 주사위의 눈의 합이 될 수 있는 수를 생성해 줍니다. (1~5)
    1. mapToObj(): 각 i에 대해 주사위의 눈이 합이 6이 되는 (i, 6-i) 쌍을 Integer[]로 생성합니다.
    2. 이후 List로 수집합니다.

Collection

Collection, Map 인터페이스 및 구현체

Java Collection Framework (JCF)

  • 데이터를 crud 하는데 필요한 자료구조와 알고리즘을 표준화해서 제공해 주는 클래스, 인터페이스의 집합
  • Collection 인터페이스
    • List, Set, Queue 인터페이스의 구현체가 존재합니다.
  • Map 인터페이스
    • Collection과는 별개로 Map 인터페이스의 구현체가 존재합니다.

 

Iterable Interface

  1. 컬렉션 인터페이스들의 가장 최상의 인터페이스
  2. 컬렉션들을 배우다 보면 자료들을 순회할 때 이터레이터 객체를 다뤄보게 되는데, 이터레이터 객체를 관리하는 인터페이스
메서드 설명
default void forEach(Consumer<? super T> action) 함수형 프로그래밍 전용 루프 메서드
Iterator<T> iterator() 컬렉션에서 이터레이터 구현
default Spliterator<T> splierator() 파이프라이닝 관련 메서드

 

 

Collection Interface

  • List, Set, Queue를 상속하는 상위 컬렉션 타입
  • 업캐스팅으로 다양한 종류의 컬렉션 자료형을 받아 자료를 crud할 수 있습니다.
메서드 설명
boolean add(Object o)
boolean addAll(Collection c)
Collection에 객체 추가
boolean contains(Object o)
boolean containsAll(Collection c)
Collection에 객체들이 포함되어있는지 check
boolean remove(Object o)
boolean removeAll(Collction c)
Collection에서 객체 삭제
boolean retainAll(Collection c) Collection에 지정한 객체를 제외한 모든 객체 삭제
void clear() Collection의 모든 객체를 삭제
boolean equals(Object o) 동일한 Collection인지 비교
int hashCode() Collection의 hash code를 반환
boolean isEmpty() Collection이 비어있는지 확인
Iterator iterator() Collection의 iterator를 얻어서 반환
int size() Collection에 저장된 객체의 개수를 반환

 

List (ArrayList, LinkedList, Vector, Stack)

ArrayList (조회 성능 우수)

https://www.geeksforgeeks.org/java/custom-arraylist-java/

  • 배열을 이용하여 만든 리스트입니다.
  • 데이터의 저장순서가 유지되고 중복을 허용합니다.
  • 데이터량에 따라 공간(capacity)을 자동으로 설정합니다. (Array와의 큰 차이점)
  • 단방향 포인터 구조로 자료에 대한 순차적인 접근에 강점이 있어 조회가 빠릅니다. (삽입/삭제는 성능이 떨어집니다.)

LinkedList (삽입/삭제 성능 우수)

https://www.geeksforgeeks.org/java/linkedlist-getfirst-method-in-java/

  • 노드를 연결하여 리스트처럼 만든 컬렉션 (배열 X)
  • 데이터의 중간 삽입, 삭제가 빈번할 경우 빠른 성능을 보장합니다.
  • 임의 요소에 대한 조회 성능이 좋지 않습니다.
  • 자바의 LinkedList는 양방향 포인터 구조로 이루어집니다.
  • LinkedList는 리스트 용도 이외에도 스택, 큐, 트리 등의 자료구조의 근간이 됩니다.

Vector (동기화 보장)

  • ArrayList의 구형 버전으로서 모든 메서드가 동기화(synchronized) 되어 있어 Thread-safe 합니다.
  • 구버전 자바와의 호환성을 가집니다.
  • 내부에서 자동으로 동기화가 일어나, 성능이 좋지 않으며 무거워서 잘 사용하지 않습니다.
  • 컬렉션에 동기화가 필요하면, Collections.synchronizedList() 메서드를 이용해 ArrayList를 동기화 처리 합니다.

Stack

  • LIFO(Last-In-First-out) 구조의 자료구조
  • 마지막에 들어온 원소가 처음으로 나갑니다.
  • 들어올 때는 push, 나갈 때는 pop을 사용합니다.
  • Stack은 Vector를 상속하기 때문에 문제점이 많아 잘 안 쓰입니다. (ArrayDeque로 대체)

Set (HashSet, LinkedHashSet, TreeSet)

  1. 데이터의 중복을 허용하지 않고 순서를 유지하지 않는 데이터의 집합 리스트
  2. 순서 자체가 없으므로 인덱스로 객체를 검색해서 가져오는 get(index) 메서드도 존재하지 않습니다.
  3. 중복 저장이 불가능하기에 심지어 null도 하나만 저장할 수 있습니다.

 

Set Method

메서드 설명
boolean add(E e) 주어진 객체를 저장 후 true, false 리턴
boolean contains(Object o) 주어진 객체가 저장되었는지의 여부를 리턴
Iterator<E> iterator() 저장된 객체를 한번씩 가져오는 반복자를 리턴
isEmpty() 컬렉션이 비었는지 여부를 검사
int Size() 저장되어 있는 전체 객체 수를 리턴
void clear() 저장된 모든 객체를 삭제
boolean remove(Object o) 주어진 객체를 삭제

 

HashSet

  • 배열과 연결노드를 결합한 자료구조 형태
  • 가장 빠른 임의 검색 접근 속도를 보장합니다.
  • 추가, 삭제, 검색, 접근성이 모두 뛰어납니다.
  • 대신 순서를 전혀 예측할 수 없습니다.

LinkedHashSet

  • 순서를 가지는 Set 자료구조
  • 추가된 순서 또는 가장 최근에 접근한 순서대로 접근 가능
  • 만일 중복을 제거하는 동시에 저장한 순서를 유지하고 싶다면, HashSet 대신 LinkedHashSet을 사용하면 됩니다.

TreeSet

  • 이진 검색 트리 (binary search tree) 자료구조 형태로 데이터 저장
  • 중복을 허용하지 않고, 순서를 가지지 않습니다.
  • 대신 데이터를 정렬하여 저장하고 있다는 특징이 있습니다.
  • 정렬, 검색, 범위 검색에 높은 성능을 가집니다.

Map (HashMap, LinkedHashMap, TreeMap, HashTable)

  • key와 value 쌍으로 연관 지어 이루어진 데이터의 집합
  • value는 중복해서 저장될 수 있지만, key는 고유한 값이어야 합니다.
  • 기존에 데이터와 중복된 키와 값을 저장하면 기존의 값은 없어지고, 마지막에 저장된 값만 남게 됩니다.
  • 저장 순서가 유지되지 않습니다.

 

Map Method

메서드 설명
void clear() Map의 모든 객체를 삭제
boolean containsKey() 지정된 key 객체와 일치하는 객체가 있는지 확인
boolean containsValue() 지정된 value 객체와 일치하는 객체가 있는지 확인
Set entySet() Map에 저장된 key-value 쌍을 Map.Entry 타입의 객체로 저장한 Set을 반환
boolean equals() 동일한 Map인지를 비교
Object get() 지정한 key 객체에 대응하는 value 객체를 반환
int hashCode() 해시 코드를 반환
boolean isEmpty() Map이 비어있는지 확인
Set keySet() Map에 저장된 모든 key 객체를 반환
Object put() Map에 저장된 key 객체와 value 객체를 연결하여 저장
putAll(Map t) 지정된 key 객체와 일치하는 key-value 쌍을 추가
remove() 지정된 key 객체와 일치하는 key-value 객체를 삭제
int size() Map에 저장된 key-value 쌍의 개수를 반환

 

Map.Entry 인터페이스

  • Map.Entry 인터페이스는 Map 인터페이스 안에 있는 내부 인터페이스입니다.
  • Map에 저장되는 key-value 쌍의 Node 내부 클래스가 이를 구현하고 있습니다.
HashMap<String, Integer> map = new HashMap<>();
map.put("A", 0);
map.put("B", 0);
map.put("C", 0);

Set<Map.Entry<String, Integer>> entry = map.entrySet();

System.out.println(entry);

for (Map.Entry<String, Integer> e : entry) {
    System.out.println(e.getKey() + " = " + e.getValue());
}

 

HashMap 

  • HashTable을 보완한 컬렉션
  • 배열과 연결이 결합된 Hashing 형태로, key, value를 묶어 하나의 데이터로 저장합니다.
  • 중복을 허용하지 않고 순서를 보장하지 않습니다.
  • key, value 값으로 null을 허용합니다.
  • 추가, 삭제, 검색, 접근성이 모두 뛰어납니다.
  • 비동기로 작동하기 때문에 멀티쓰레드 환경에서는 어울리지 않습니다.

LinkedHashMap (순서 보장)

  • HashMap을 상속하고, Entry들이 연결 리스트를 구성하여 데이터의 순서를 보장합니다.
  • 일반적인 Map 자료구조는 순서를 가지지 않지만, LinkedHashMap은 들어온 순서대로 순서를 가집니다.

TreeMap (정렬 O)

  • 이진 검색 트리의 형태로 키와 값의 쌍으로 이루어진 데이터를 저장합니다. (TreeSet과 동일한 원리)
  • TreeMap은 SortedMap 인터페이스의 구현체로서, Key값을 기준으로 정렬되는 특징을 가지고 있습니다.
  • 정렬된 순서로 key/value 값을 저장하므로 조회 성능이 뛰어나지만, 저장과 동시에 정렬 과정이 일어나므로 저장 시간이 오래 걸립니다.

HashTable

  • 자바 초기 버전에 나온 클래스
  • Key를 특정 해시 함수를 통해 해싱한 후 나온 결과를 배열의 인덱스로 사용하여 Value를 찾는 방식으로 동작됩니다.
  • HashMap보다는 느리지만 동기화가 기본적으로 지원됩니다.

 

 

<참고 자료>

https://www.elancer.co.kr/blog/detail/255

 

java stream이란 특징부터 사용하는 이유까지 모두 알려드립니다. I 이랜서 블로그

데이터가 중요해 질수록 강력한 데이터 처리 기능을 선보이며 데이터 처리 효율을 높여주는 ‘Java Stream’를 찾는 사람들이 많아지고 있는데요. 이랜서에서 java stream이란 무엇인지 자세히 알려

www.elancer.co.kr

https://jeong-pro.tistory.com/212

 

개발자 기술 과제, 라이브 코딩 테스트 후기(자바 스트림 활용 능력 with flatMap)

과제 겸 라이브 코딩 1. 후기 제가 생각하는 일반적인 개발자 채용 프로세스는 아래와 같습니다. 서류전형 → 코딩테스트(온라인) → 기술면접 → 임원면접 → 최종합격 여기에 조금 추가되면 코

jeong-pro.tistory.com

https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-Collections-Framework-%EC%A2%85%EB%A5%98-%EC%B4%9D%EC%A0%95%EB%A6%AC

 

🧱 Java Collections Framework 종류 💯 총정리

Java Collection Framework 자바 새내기분들은 컬렉션 프레임워크라는 단어에 뭔가 거창하고 어려운 느낌이 들수 있겠지만, 그냥 자료 구조(Data Structure) 종류의 형태들을 자바 클래스로 구현한 모음집

inpa.tistory.com

https://gangnam-americano.tistory.com/41

 

[JAVA] Java 컬렉션(Collection) 정리

[JAVA] Java 컬렉션(Collection) 정리 ■ Java Collections Framework(JCF) Java에서 컬렉션(Collection)이란 데이터의 집합, 그룹을 의미하며 JCF(Java Collections Framework)는 이러한 데이터, 자료구조인 컬렌션과 이를 구

gangnam-americano.tistory.com

 

 

저작자표시 비영리 변경금지 (새창열림)

'Java' 카테고리의 다른 글

[Java] Garbage Collection  (1) 2024.12.05
[Java] ClassNotFoundException VS NoClassDefFoundError  (1) 2024.02.06
[Java] Exception  (0) 2023.08.21
'Java' 카테고리의 다른 글
  • [Java] Garbage Collection
  • [Java] ClassNotFoundException VS NoClassDefFoundError
  • [Java] Exception
SeungbeomKim
SeungbeomKim
[IT(PS, CS, SW, etc.) 지식 기록] Github : https://github.com/daily1313/
  • SeungbeomKim
    개발 블로그
    SeungbeomKim
  • 전체
    오늘
    어제
    • 분류 전체보기 (389)
      • 일상 (33)
        • 여행 (17)
        • 회고록 (9)
        • 리뷰 (7)
      • PS (138)
        • 그리디 알고리즘[Greedy] (25)
        • 정렬 알고리즘[Sort] (18)
        • 문자열 알고리즘[String] (14)
        • 동적 계획 알고리즘[DP] (17)
        • 깊이 우선 탐색, 너비 우선 탐색[DFS, BFS.. (34)
        • 재귀[Recursion] (2)
        • 백트래킹[Backtracking] (5)
        • 브루트포스 알고리즘[Bruteforce] (16)
        • 자료 구조[Data Structure] (4)
        • 분할 정복 알고리즘[Divide & Conquer.. (3)
      • CS (24)
      • Network (11)
      • Database (8)
        • Elasticsearch (3)
      • Linux (2)
      • JavaScript (4)
        • AngularJS (1)
      • Java (4)
        • Effective Java (7)
        • Java Concept (20)
        • Spring (61)
        • Design Pattern (3)
      • Python (2)
      • Vscode (1)
      • DevOps (43)
        • AWS (27)
        • Git (7)
        • Docker (6)
        • Nginx (1)
      • 자격증 (10)
        • SQL (4)
      • 사이드 프로젝트 (3)
        • MatJido (3)
      • 기타 (9)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 소개
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    Effective Java
    docker
    너비 우선 탐색
    Spring
    sqld
    AWS
    정보처리기사 필기
    정보처리기사 실기
    백트래킹
    Wi-Fi
    BFS
    dp
    컴퓨터구조
    다이나믹 프로그래밍
    springboot
    dfs
    메타코딩
    정보처리기사
    이펙티브 자바
    일본여행
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
SeungbeomKim
[Java] Stream, Collection
상단으로

티스토리툴바