[{"data":1,"prerenderedAt":816},["ShallowReactive",2],{"post-document:\u002Fjava\u002Fbasics\u002F2026\u002F08\u002F11\u002Fjava-stream-api\u002F":3},{"id":4,"title":5,"body":6,"categories":794,"date":796,"description":797,"extension":798,"image":799,"key_concepts":799,"last_modified_at":799,"legacyPath":800,"meta":801,"navigation":236,"part":803,"path":804,"published":236,"robots":799,"seo":805,"series":806,"stem":807,"strengths":799,"summary":799,"tags":808,"tradeoffs":799,"__hash__":815},"posts\u002Fposts\u002FBackend\u002FJAVA\u002Fbasics\u002F2026-08-11-java-stream-api.md","Java 기초 Part 5: Stream API",{"type":7,"value":8,"toc":777},"minimark",[9,13,18,130,137,144,148,151,192,195,203,207,210,219,222,265,268,287,290,296,300,401,408,437,440,446,451,458,485,491,496,506,537,540,546,549,555,559,574,604,610,626,629,633,638,663,669,672,676,700,706,710,768,773],[10,11,5],"h2",{"id":12},"java-기초-part-5-stream-api",[14,15,17],"h3",{"id":16},"_1-먼저-알아둘-단어","1. 먼저 알아둘 단어",[19,20,21,37],"table",{},[22,23,24],"thead",{},[25,26,27,31,34],"tr",{},[28,29,30],"th",{},"단어",[28,32,33],{},"정의",[28,35,36],{},"예시",[38,39,40,55,68,88,104,117],"tbody",{},[25,41,42,46,49],{},[43,44,45],"td",{},"Stream",[43,47,48],{},"컬렉션의 원본 데이터를 바꾸지 않고 요소를 순서대로 처리하는 흐름",[43,50,51],{},[52,53,54],"code",{},"numbers.stream()",[25,56,57,60,63],{},[43,58,59],{},"파이프라인(Pipeline)",[43,61,62],{},"여러 연산을 연결한 데이터 처리 과정",[43,64,65],{},[52,66,67],{},"stream().filter().map().toList()",[25,69,70,73,76],{},[43,71,72],{},"중간 연산",[43,74,75],{},"Stream을 받아 새로운 Stream을 반환하는 연산",[43,77,78,81,82,81,85],{},[52,79,80],{},"filter()",", ",[52,83,84],{},"map()",[52,86,87],{},"sorted()",[25,89,90,93,96],{},[43,91,92],{},"최종 연산",[43,94,95],{},"Stream 처리를 실행하고 결과를 만드는 연산",[43,97,98,81,101],{},[52,99,100],{},"toList()",[52,102,103],{},"forEach()",[25,105,106,109,112],{},[43,107,108],{},"람다식(Lambda)",[43,110,111],{},"짧게 표현한 익명 함수",[43,113,114],{},[52,115,116],{},"n -> n * 2",[25,118,119,122,125],{},[43,120,121],{},"메서드 참조",[43,123,124],{},"이미 존재하는 메서드를 간결하게 전달하는 문법",[43,126,127],{},[52,128,129],{},"System.out::println",[131,132,133],"blockquote",{},[134,135,136],"p",{},"Stream API는 리스트 같은 데이터 묶음을 하나씩 꺼내서 조건을 걸고, 바꾸고, 다시 모으는 데이터 처리 기능이다.",[134,138,139,140,143],{},"Java 8에서 도입됐으며, 반복문이나 ",[52,141,142],{},"Iterator","로 작성하던 코드를 선언적이고 함수형인 스타일로 표현할 수 있게 해준다.",[14,145,147],{"id":146},"_2-stream-api의-핵심","2. Stream API의 핵심",[134,149,150],{},"Stream API의 핵심은 데이터 처리 과정을 위에서 아래로 읽을 수 있다는 점이다.",[152,153,158],"pre",{"className":154,"code":155,"language":156,"meta":157,"style":157},"language-java shiki shiki-themes github-light github-dark","List\u003CString> names = users.stream()\n        .filter(user -> user.getAge() >= 20)\n        .map(User::getName)\n        .sorted()\n        .toList();\n","java","",[52,159,160,168,174,180,186],{"__ignoreMap":157},[161,162,165],"span",{"class":163,"line":164},"line",1,[161,166,167],{},"List\u003CString> names = users.stream()\n",[161,169,171],{"class":163,"line":170},2,[161,172,173],{},"        .filter(user -> user.getAge() >= 20)\n",[161,175,177],{"class":163,"line":176},3,[161,178,179],{},"        .map(User::getName)\n",[161,181,183],{"class":163,"line":182},4,[161,184,185],{},"        .sorted()\n",[161,187,189],{"class":163,"line":188},5,[161,190,191],{},"        .toList();\n",[134,193,194],{},"위 코드는 다음 순서로 읽을 수 있다.",[152,196,201],{"className":197,"code":199,"language":200,"meta":157},[198],"language-text","users를 Stream으로 만든다\n    ↓\n20세 이상인 사용자만 남긴다\n    ↓\nUser 객체를 이름으로 바꾼다\n    ↓\n이름을 정렬한다\n    ↓\nList로 모은다\n","text",[52,202,199],{"__ignoreMap":157},[14,204,206],{"id":205},"_3-반복문과-stream-비교","3. 반복문과 Stream 비교",[134,208,209],{},"예를 들어 숫자 리스트에서 짝수만 뽑는다고 하자.",[152,211,213],{"className":154,"code":212,"language":156,"meta":157,"style":157},"List\u003CInteger> numbers = List.of(1, 2, 3, 4, 5);\n",[52,214,215],{"__ignoreMap":157},[161,216,217],{"class":163,"line":164},[161,218,212],{},[134,220,221],{},"반복문을 사용하면 결과 리스트를 직접 만들고 값을 추가해야 한다.",[152,223,225],{"className":154,"code":224,"language":156,"meta":157,"style":157},"List\u003CInteger> result = new ArrayList\u003C>();\n\nfor (int number : numbers) {\n    if (number % 2 == 0) {\n        result.add(number);\n    }\n}\n",[52,226,227,232,238,243,248,253,259],{"__ignoreMap":157},[161,228,229],{"class":163,"line":164},[161,230,231],{},"List\u003CInteger> result = new ArrayList\u003C>();\n",[161,233,234],{"class":163,"line":170},[161,235,237],{"emptyLinePlaceholder":236},true,"\n",[161,239,240],{"class":163,"line":176},[161,241,242],{},"for (int number : numbers) {\n",[161,244,245],{"class":163,"line":182},[161,246,247],{},"    if (number % 2 == 0) {\n",[161,249,250],{"class":163,"line":188},[161,251,252],{},"        result.add(number);\n",[161,254,256],{"class":163,"line":255},6,[161,257,258],{},"    }\n",[161,260,262],{"class":163,"line":261},7,[161,263,264],{},"}\n",[134,266,267],{},"Stream을 사용하면 데이터 처리 과정에 집중해서 작성할 수 있다.",[152,269,271],{"className":154,"code":270,"language":156,"meta":157,"style":157},"List\u003CInteger> result = numbers.stream()\n        .filter(number -> number % 2 == 0)\n        .toList();\n",[52,272,273,278,283],{"__ignoreMap":157},[161,274,275],{"class":163,"line":164},[161,276,277],{},"List\u003CInteger> result = numbers.stream()\n",[161,279,280],{"class":163,"line":170},[161,281,282],{},"        .filter(number -> number % 2 == 0)\n",[161,284,285],{"class":163,"line":176},[161,286,191],{},[134,288,289],{},"다음과 같이 읽으면 된다.",[152,291,294],{"className":292,"code":293,"language":200,"meta":157},[198],"numbers를 Stream으로 만든다\n    ↓\n짝수만 남긴다\n    ↓\nList로 모은다\n",[52,295,293],{"__ignoreMap":157},[14,297,299],{"id":298},"_4-자주-사용하는-메서드","4. 자주 사용하는 메서드",[19,301,302,315],{},[22,303,304],{},[25,305,306,309,312],{},[28,307,308],{},"메서드",[28,310,311],{},"구분",[28,313,314],{},"역할",[38,316,317,330,341,352,363,375,390],{},[25,318,319,324,327],{},[43,320,321],{},[52,322,323],{},"stream()",[43,325,326],{},"Stream 생성",[43,328,329],{},"컬렉션에서 데이터 처리 흐름을 시작한다.",[25,331,332,336,338],{},[43,333,334],{},[52,335,80],{},[43,337,72],{},[43,339,340],{},"조건에 맞는 요소만 남긴다.",[25,342,343,347,349],{},[43,344,345],{},[52,346,84],{},[43,348,72],{},[43,350,351],{},"요소를 다른 값이나 형태로 바꾼다.",[25,353,354,358,360],{},[43,355,356],{},[52,357,87],{},[43,359,72],{},[43,361,362],{},"요소를 정렬한다.",[25,364,365,370,372],{},[43,366,367],{},[52,368,369],{},"distinct()",[43,371,72],{},[43,373,374],{},"중복 요소를 제거한다.",[25,376,377,381,383],{},[43,378,379],{},[52,380,100],{},[43,382,92],{},[43,384,385,386,389],{},"처리 결과를 ",[52,387,388],{},"List","로 모은다.",[25,391,392,396,398],{},[43,393,394],{},[52,395,103],{},[43,397,92],{},[43,399,400],{},"각 요소에 지정한 동작을 실행한다.",[14,402,404,405,407],{"id":403},"_5-filter-조건에-맞는-값만-남기기","5. ",[52,406,80],{},": 조건에 맞는 값만 남기기",[152,409,411],{"className":154,"code":410,"language":156,"meta":157,"style":157},"List\u003CString> names = List.of(\"민형\", \"철수\", \"영희\", \"김민형\");\n\nnames.stream()\n        .filter(name -> name.length() > 2)\n        .forEach(System.out::println);\n",[52,412,413,418,422,427,432],{"__ignoreMap":157},[161,414,415],{"class":163,"line":164},[161,416,417],{},"List\u003CString> names = List.of(\"민형\", \"철수\", \"영희\", \"김민형\");\n",[161,419,420],{"class":163,"line":170},[161,421,237],{"emptyLinePlaceholder":236},[161,423,424],{"class":163,"line":176},[161,425,426],{},"names.stream()\n",[161,428,429],{"class":163,"line":182},[161,430,431],{},"        .filter(name -> name.length() > 2)\n",[161,433,434],{"class":163,"line":188},[161,435,436],{},"        .forEach(System.out::println);\n",[134,438,439],{},"결과는 다음과 같다.",[152,441,444],{"className":442,"code":443,"language":200,"meta":157},[198],"김민형\n",[52,445,443],{"__ignoreMap":157},[134,447,448,450],{},[52,449,80],{},"는 조건을 만족하는 요소만 통과시킨다. 요소의 값 자체를 다른 값으로 바꾸지는 않는다.",[14,452,454,455,457],{"id":453},"_6-map-값을-다른-형태로-바꾸기","6. ",[52,456,84],{},": 값을 다른 형태로 바꾸기",[152,459,461],{"className":154,"code":460,"language":156,"meta":157,"style":157},"List\u003CInteger> numbers = List.of(1, 2, 3);\n\nList\u003CInteger> result = numbers.stream()\n        .map(number -> number * 2)\n        .toList();\n",[52,462,463,468,472,476,481],{"__ignoreMap":157},[161,464,465],{"class":163,"line":164},[161,466,467],{},"List\u003CInteger> numbers = List.of(1, 2, 3);\n",[161,469,470],{"class":163,"line":170},[161,471,237],{"emptyLinePlaceholder":236},[161,473,474],{"class":163,"line":176},[161,475,277],{},[161,477,478],{"class":163,"line":182},[161,479,480],{},"        .map(number -> number * 2)\n",[161,482,483],{"class":163,"line":188},[161,484,191],{},[152,486,489],{"className":487,"code":488,"language":200,"meta":157},[198],"결과: [2, 4, 6]\n",[52,490,488],{"__ignoreMap":157},[134,492,493,495],{},[52,494,84],{},"은 각 요소를 전달받아 새로운 값으로 바꾼다.",[14,497,499,500,502,503,505],{"id":498},"_7-filter와-map-함께-사용하기","7. ",[52,501,80],{},"와 ",[52,504,84],{}," 함께 사용하기",[152,507,509],{"className":154,"code":508,"language":156,"meta":157,"style":157},"List\u003CInteger> numbers = List.of(1, 2, 3, 4, 5);\n\nList\u003CInteger> result = numbers.stream()\n        .filter(number -> number > 2)\n        .map(number -> number * 10)\n        .toList();\n",[52,510,511,515,519,523,528,533],{"__ignoreMap":157},[161,512,513],{"class":163,"line":164},[161,514,212],{},[161,516,517],{"class":163,"line":170},[161,518,237],{"emptyLinePlaceholder":236},[161,520,521],{"class":163,"line":176},[161,522,277],{},[161,524,525],{"class":163,"line":182},[161,526,527],{},"        .filter(number -> number > 2)\n",[161,529,530],{"class":163,"line":188},[161,531,532],{},"        .map(number -> number * 10)\n",[161,534,535],{"class":163,"line":255},[161,536,191],{},[134,538,539],{},"처리 흐름은 다음과 같다.",[152,541,544],{"className":542,"code":543,"language":200,"meta":157},[198],"[1, 2, 3, 4, 5]\n    ↓ filter(number -> number > 2)\n[3, 4, 5]\n    ↓ map(number -> number * 10)\n[30, 40, 50]\n",[52,545,543],{"__ignoreMap":157},[134,547,548],{},"기억할 내용은 간단하다.",[152,550,553],{"className":551,"code":552,"language":200,"meta":157},[198],"filter → 골라낸다\nmap    → 바꾼다\n",[52,554,552],{"__ignoreMap":157},[14,556,558],{"id":557},"_8-중간-연산과-최종-연산","8. 중간 연산과 최종 연산",[134,560,561,81,563,81,565,567,568,570,571,573],{},[52,562,80],{},[52,564,84],{},[52,566,87],{}," 같은 중간 연산만 작성하면 실제 데이터 처리가 시작되지 않는다. ",[52,569,100],{},"나 ",[52,572,103],{}," 같은 최종 연산이 호출되어야 전체 파이프라인이 실행된다.",[152,575,577],{"className":154,"code":576,"language":156,"meta":157,"style":157},"numbers.stream()\n        .filter(number -> {\n            System.out.println(\"확인: \" + number);\n            return number % 2 == 0;\n        });\n",[52,578,579,584,589,594,599],{"__ignoreMap":157},[161,580,581],{"class":163,"line":164},[161,582,583],{},"numbers.stream()\n",[161,585,586],{"class":163,"line":170},[161,587,588],{},"        .filter(number -> {\n",[161,590,591],{"class":163,"line":176},[161,592,593],{},"            System.out.println(\"확인: \" + number);\n",[161,595,596],{"class":163,"line":182},[161,597,598],{},"            return number % 2 == 0;\n",[161,600,601],{"class":163,"line":188},[161,602,603],{},"        });\n",[134,605,606,607,609],{},"위 코드는 최종 연산이 없기 때문에 ",[52,608,80],{}," 내부의 출력도 실행되지 않는다.",[152,611,612],{"className":154,"code":270,"language":156,"meta":157,"style":157},[52,613,614,618,622],{"__ignoreMap":157},[161,615,616],{"class":163,"line":164},[161,617,277],{},[161,619,620],{"class":163,"line":170},[161,621,282],{},[161,623,624],{"class":163,"line":176},[161,625,191],{},[134,627,628],{},"이처럼 필요한 시점까지 실행을 미루는 방식을 지연 연산(Lazy Evaluation)이라고 한다.",[14,630,632],{"id":631},"_9-사용할-때-주의할-점","9. 사용할 때 주의할 점",[634,635,637],"h4",{"id":636},"원본-컬렉션은-바뀌지-않는다","원본 컬렉션은 바뀌지 않는다",[152,639,641],{"className":154,"code":640,"language":156,"meta":157,"style":157},"List\u003CInteger> numbers = List.of(1, 2, 3);\n\nList\u003CInteger> result = numbers.stream()\n        .map(number -> number * 10)\n        .toList();\n",[52,642,643,647,651,655,659],{"__ignoreMap":157},[161,644,645],{"class":163,"line":164},[161,646,467],{},[161,648,649],{"class":163,"line":170},[161,650,237],{"emptyLinePlaceholder":236},[161,652,653],{"class":163,"line":176},[161,654,277],{},[161,656,657],{"class":163,"line":182},[161,658,532],{},[161,660,661],{"class":163,"line":188},[161,662,191],{},[152,664,667],{"className":665,"code":666,"language":200,"meta":157},[198],"numbers → [1, 2, 3]\nresult  → [10, 20, 30]\n",[52,668,666],{"__ignoreMap":157},[134,670,671],{},"Stream은 원본 컬렉션을 직접 변경하는 기능이 아니다. 처리 결과가 필요하면 새로운 리스트 등으로 받아야 한다.",[634,673,675],{"id":674},"stream은-한-번만-사용할-수-있다","Stream은 한 번만 사용할 수 있다",[152,677,679],{"className":154,"code":678,"language":156,"meta":157,"style":157},"Stream\u003CInteger> stream = numbers.stream();\n\nstream.toList();\nstream.toList(); \u002F\u002F IllegalStateException\n",[52,680,681,686,690,695],{"__ignoreMap":157},[161,682,683],{"class":163,"line":164},[161,684,685],{},"Stream\u003CInteger> stream = numbers.stream();\n",[161,687,688],{"class":163,"line":170},[161,689,237],{"emptyLinePlaceholder":236},[161,691,692],{"class":163,"line":176},[161,693,694],{},"stream.toList();\n",[161,696,697],{"class":163,"line":182},[161,698,699],{},"stream.toList(); \u002F\u002F IllegalStateException\n",[134,701,702,703,705],{},"최종 연산이 끝난 Stream은 다시 사용할 수 없다. 다시 처리하려면 ",[52,704,54],{},"으로 새로운 Stream을 만들어야 한다.",[14,707,709],{"id":708},"_10-최종-정리","10. 최종 정리",[19,711,712,721],{},[22,713,714],{},[25,715,716,718],{},[28,717,311],{},[28,719,720],{},"핵심 내용",[38,722,723,730,738,746,753,760],{},[25,724,725,727],{},[43,726,45],{},[43,728,729],{},"데이터 자체가 아니라 데이터 처리 흐름이다.",[25,731,732,736],{},[43,733,734],{},[52,735,80],{},[43,737,340],{},[25,739,740,744],{},[43,741,742],{},[52,743,84],{},[43,745,351],{},[25,747,748,750],{},[43,749,72],{},[43,751,752],{},"Stream을 반환하며, 최종 연산 전까지 실행을 미룬다.",[25,754,755,757],{},[43,756,92],{},[43,758,759],{},"파이프라인을 실행하고 결과를 만든다.",[25,761,762,765],{},[43,763,764],{},"원본 데이터",[43,766,767],{},"Stream으로 처리해도 원본 컬렉션은 그대로 유지된다.",[131,769,770],{},[134,771,772],{},"Stream API는 데이터를 어떻게 반복할지보다 어떤 조건으로 골라내고, 어떻게 바꾸고, 어떤 결과로 모을지에 집중하게 해주는 기능이다.",[774,775,776],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":157,"searchDepth":170,"depth":170,"links":778},[779],{"id":12,"depth":170,"text":5,"children":780},[781,782,783,784,785,787,789,791,792,793],{"id":16,"depth":176,"text":17},{"id":146,"depth":176,"text":147},{"id":205,"depth":176,"text":206},{"id":298,"depth":176,"text":299},{"id":403,"depth":176,"text":786},"5. filter(): 조건에 맞는 값만 남기기",{"id":453,"depth":176,"text":788},"6. map(): 값을 다른 형태로 바꾸기",{"id":498,"depth":176,"text":790},"7. filter()와 map() 함께 사용하기",{"id":557,"depth":176,"text":558},{"id":631,"depth":176,"text":632},{"id":708,"depth":176,"text":709},[156,795],"basics","2026-08-11 10:20:00 +0900","Java Stream API의 파이프라인, 중간 연산과 최종 연산을 filter, map, sorted 예제로 정리한다.","md",null,"\u002Fjava\u002Fbasics\u002F2026\u002F08\u002F11\u002Fjava-stream-api\u002F",{"layout":802},"post","5","\u002Fposts\u002Fbackend\u002Fjava\u002Fbasics\u002F2026-08-11-java-stream-api",{"title":5,"description":797},"Java 기초","posts\u002FBackend\u002FJAVA\u002Fbasics\u002F2026-08-11-java-stream-api",[809,810,811,812,813,814],"Java","Stream API","Collection","Lambda","Filter","Map","EyU1YzOdpjb-RGtksEhv3rjsgUFYA9Wl9hs_kgsUtWM",1788744784644]