Java에서 루프보다 스트림의 장점은 무엇입니까? [닫은]


133

나는 인터뷰에서 이것을 물었고 나는 내가 가질 수있는 최선의 대답을했다고 확신하지 못한다. 병렬 검색을 수행 할 수 있고 기억할 수없는 수단으로 null 값을 처리했다고 언급했습니다. 이제 나는 옵션을 생각하고 있음을 알고 있습니다. 내가 여기서 무엇을 놓치고 있습니까? 그들은 그것이 더 좋거나 간결한 코드라고 주장하지만 동의하지는 않습니다.


간결하게 대답 된 것을 고려할 때, 이것은 결국 너무 광범위한 질문이 아닌 것 같습니다.


만약 그들이 인터뷰에서이 질문을하고 있고, 분명하게 대답한다면, 답을 찾기 어렵게 만드는 것 이외의 다른 목적으로 그것을 무너 뜨릴 수 있습니까? 당신은 무엇을 찾고 있습니까? 나는 질문을 세분화하고 모든 하위 질문에 대답 할 수는 있지만 모든 하위 질문에 대한 링크가있는 부모 질문을 만들 수는 있지만 꽤 어리석은 것처럼 보입니다. 우리가 그 동안, 덜 광범위한 질문의 예를 들어주세요. 나는이 질문의 일부만을 물어볼 방법이 없으며 여전히 의미있는 대답을 얻습니다. 다른 방법으로 정확히 같은 질문을 할 수 있습니다. 예를 들어, "스트림은 어떤 용도로 사용됩니까?" 또는 "for 루프 대신 스트림을 언제 사용합니까?" 또는 "for 루프 대신 스트림을 사용하는 이유는 무엇입니까?" 이것들은 모두 정확히 같은 질문입니다.

... 또는 누군가가 정말 긴 다 지점 답변을했기 때문에 너무 광범위하게 간주됩니까? 솔직히 아는 사람은 거의 모든 질문으로 그렇게 할 수 있습니다. 예를 들어 JVM 작성자 중 한 사람이라면 하루 종일 for 루프에 대해 이야기 할 수 있습니다.

"적절한 답변을 식별 할 수있을 정도로 상세하게 특정 문제로 제한하도록 질문을 편집하십시오. 한 번에 여러 개의 다른 질문을하지 마십시오.이 질문을 명확하게하는 방법은 질문하는 방법 페이지를 참조하십시오."

아래에 언급 된 바와 같이, 하나가 있고 제공하기가 쉽다는 것을 입증하는 적절한 답변이 제공되었습니다.


7
이건 의견에 근거한 것입니다. 개인적으로, 나는 코드를 더 읽기 쉽도록 스트림을 선호합니다. 방법 대신 원하는 것을 쓸 수 있습니다 . 또한, 한 줄짜리로 놀라운 일을하는 것은 완전히 나쁜 일입니다.
— Arnaud Denoyelle

19
30 줄이더라도 라이너 하나? 나는 긴 사슬을 좋아하지 않습니다.
— user447607

1
게다가, 내가 찾고있는 것은 인터뷰에 대한 적절한 대응입니다. 이것이 중요한 "의견"입니다.
— user447607

1
교육적으로 말하면,이 질문은 미래의 인터뷰에서 나에게 약간의 성능 저하를 줄였습니다. 람다 식에서 떨어져 상대방에서 스트림 , 미래에 Structs와 Unions에 대해 Java가 무엇을하는지
— 보자

5
스트림은 함수형 프로그래밍에서 힘의 일부만 탭한다는 점에 유의하십시오.-/
— Thorbjørn Ravn Andersen

답변:


251

인터뷰 질문은 단점에 대해 묻지 않고 장점에 대해 묻는 것이 흥미 롭습니다. 둘 다 있기 때문입니다.

스트림은보다 선언적인 스타일 입니다. 또는보다 표현적인 스타일. 수행 방식 을 설명 하는 것 보다 코드에서 의도를 선언하는 것이 좋습니다 .

 return people
     .filter( p -> p.age() < 19)
     .collect(toList());

... 목록에서 일치하는 요소를 필터링한다고 분명히 밝힙니다.

 List<Person> filtered = new ArrayList<>();
 for(Person p : people) {
     if(p.age() < 19) {
         filtered.add(p);
     }
 }
 return filtered;

"루프를하고 있어요"라고 말합니다. 루프의 목적은 논리에 더 깊이 묻혀 있습니다.

스트림은 종종 더 간결 합니다. 같은 예가 이것을 보여줍니다. Terser가 항상 더 좋은 것은 아니지만 동시에 간결하고 표현력이 있으면 훨씬 좋습니다.

스트림은 함수와 강한 친 화성을 가지고 있습니다 . Java 8에는 람다와 기능적 인터페이스가 도입되어 강력한 기술의 전체 장난감 상자가 열립니다. 스트림은 일련의 객체에 함수를 적용하는 가장 편리하고 자연스러운 방법을 제공합니다.

스트림은 덜 가변성을 장려 합니다. 이것은 함수형 프로그래밍 측면과 관련이 있습니다. 스트림을 사용하여 작성하는 프로그램의 종류는 객체를 수정하지 않는 종류의 프로그램 인 경향이 있습니다.

스트림은 더 느슨한 결합을 권장 합니다. 스트림 처리 코드는 스트림의 소스 또는 최종 종료 방법을 알 필요가 없습니다.

스트림은 매우 정교한 동작을 간결하게 표현할 수 있습니다 . 예를 들면 다음과 같습니다.

 stream.filter(myfilter).findFirst();

마치 전체 스트림을 필터링하는 것처럼 첫눈에 본 다음 첫 번째 요소를 반환 할 수 있습니다. 그러나 실제로 findFirst()전체 작업을 수행하므로 하나의 항목을 찾은 후 효율적으로 중지됩니다.

스트림은 미래의 효율성 향상을위한 범위를 제공합니다 . 일부 사람들은 벤치마킹하여 인 메모리 List또는 어레이의 단일 스레드 스트림 이 동등한 루프보다 느릴 수 있음을 발견했습니다 . 게임에 더 많은 객체와 오버 헤드가 있기 때문에 이는 타당합니다.

그러나 시내 규모. 병렬 스트림 조작에 대한 Java의 내장 지원뿐만 아니라 모델에 적합하기 때문에 Streams를 API로 사용하여 분산 맵 감소를위한 라이브러리가 몇 가지 있습니다.

단점?

성능 : for어레이를 통한 루프는 힙 및 CPU 사용량 측면에서 매우 가볍습니다. 원시 속도와 메모리 절약이 우선 순위 인 경우 스트림 사용이 더 나쁩니다.

친숙 함 : 세계에는 많은 언어 배경의 경험이 풍부한 절차 적 프로그래머가있어 루프가 친숙하고 스트림이 참신합니다. 어떤 환경에서는 그러한 종류의 사람에게 친숙한 코드를 작성하려고합니다.

인지 적 오버 헤드 . 선언적인 특성과 그 아래에서 발생하는 추상화로부터의 증가로 인해 코드가 실행과 어떻게 관련되는지에 대한 새로운 정신 모델을 구축해야 할 수도 있습니다. 실제로 상황이 잘못되거나 성능을 심층 분석하거나 미묘한 버그를 분석해야하는 경우에만이 작업을 수행하면됩니다. "그냥 작동"하면 작동합니다.

디버거 는 개선되고 있지만 지금도 디버거에서 스트림 코드를 단계별로 실행하는 경우 간단한 루프는 기존 디버거가 사용하는 변수 및 코드 위치에 매우 가깝기 때문에 동등한 루프보다 작업이 어려울 수 있습니다.


4
스트림과 같은 것들이 점점 더 일반화되고 있으며 특히 FP 지향적이지 않은 일반적으로 사용되는 많은 언어로 나타납니다.
— Casey

5
여기에 나열된 장단점을 감안할 때 스트림이 중요하지 않은 성능 부분에서 매우 간단한 용도 (작은 논리 if / then / else, 많은 중첩 된 호출 또는 람다 등) 이외의 용도로는 가치가 없다고 생각합니다.
— Henrik Kjus Alstad

1
@HenrikKjusAlstad 그것은 내가 의사 소통하려는 테이크 아웃이 아닙니다. 스트림은 성숙하고 강력하며 표현력이 풍부하며 프로덕션 등급 코드에 완벽하게 적합합니다.
— 슬림

아, 나는 그것을 생산에 사용하지 않을 것을 의미하지 않았다. 그러나 오히려 결과 스트림이 복잡하게 보일 경우 스트림보다 오래된 루프 / if 등을 기본값으로 사용합니다. 나는 스트림이 루프를 이길 수있는 용도가있을 것이라고 확신하지만 명확하지 않은 경우 더 자주 묶여 있거나 때로는 다른 방법으로 생각합니다. 따라서, 나는 옛 방식을 고수하기 위해인지 적 오버 헤드 주장에 중점을 두었습니다.
— Henrik Kjus Alstad

1
@lijepdam- "목록을 반복"하는 것이 코드의 핵심 의도가 아닌 경우에도 "이 목록을 반복하고 있습니다 (루프 내부를 참조하여 이유 확인)"라는 코드가 계속 표시됩니다.
— 슬림

16

구문상의 재미를 제외하고 Streams는 잠재적으로 매우 큰 데이터 세트와 함께 작동하도록 설계되었지만, Iterable을 구현하는 배열, 컬렉션 및 거의 모든 Java SE 클래스는 완전히 메모리에 있습니다.

Stream의 단점은 필터, 매핑 등이 확인 된 예외를 throw 할 수 없다는 것입니다. 따라서 스트림은 중간 I / O 작업에 적합하지 않습니다.


7
물론 무한한 소스를 반복 할 수도 있습니다.
— 날씬한

그러나 처리 할 요소가 DB에 유지되면 스트림을 어떻게 사용합니까? 주니어 개발자는 스트림을 사용하기 위해 컬렉션의 모든 항목을 읽으려고 할 수 있습니다. 그리고 그것은 재앙이 될 것입니다.
— Lluis Martinez

2
@LluisMartinez 좋은 DB 클라이언트 라이브러리는 다음과 같은 것을 반환 Stream<Row>하거나 StreamDB 결과 커서 연산을 래핑하는 자체 구현 을 작성할 수 있습니다 .
— 슬림

Streams가 예외를 자동으로 무시한다는 것은 최근에 물린 버그입니다. 직관적이지 않습니다.
— xxfelixxx

@xxfelixxx 스트림은 예외를 자동으로 무시하지 않습니다. 이것을 실행 해보십시오 :Arrays.asList("test", null).stream().forEach(s -> System.out.println(s.length()));
— VGR

8
  1. 잘못 알고 : 병렬 작업은 Streams가 아닌 Optionals를 사용합니다.

  2. 스트림으로 작업하는 메소드를 정의 할 수 있습니다 : 스트림을 매개 변수로 사용, 반환 등. 루프를 매개 변수로 사용하는 메소드를 정의 할 수 없습니다. 이를 통해 복잡한 스트림 작업을 한 번 수행하고 여러 번 사용할 수 있습니다. Java는 여기에 단점이 있습니다. 메서드는 someMethod(stream)스트림 자체가 아닌 호출되어야 stream.someMethod()하므로 혼합하면 읽기가 복잡합니다.

    myMethod2(myMethod(stream.transform(...)).filter(...))

    다른 많은 언어들 (C #, Kotlin, Scala 등)은 어떤 형태의 "확장 방법"을 허용합니다.

  3. 순차적 작업 만 필요하고 재사용하지 않으려는 경우에도 스트림이나 루프를 사용할 수 있으므로 스트림에 대한 간단한 작업은 루프의 복잡한 변경에 해당 할 수 있습니다.


설명 1. 옵션 인터페이스가 체인에서 널을 처리하는 수단이 아닙니까? 3에 관해서는, 단락 필터로 인해 지정된 발생에 대해서만 메소드가 호출되기 때문에 의미가 있습니다. 실력 있는. 이 코드를 사용하면 테스트해야 할 추가 코드를 작성해야 할 필요성이 줄어든다는 것을 알 수 있습니다. 검토 결과, 2의 순차적 인 사례가 무엇을 의미하는지 잘 모르겠습니다.
— user447607

1. Optional은의 대안 null이지만 병렬 작업과는 관련이 없습니다. 귀하의 질문에 "지금은 선택 사항을 생각하고 있음을 알지 못한다"는 것만으로 null취급에 대해서만 이야기하고 있습니까?
— Alexey Romanov

나는 2와 3의 순서를 변경하고 둘 다 조금 확장했습니다.
— Alexey Romanov

6

시퀀스의 요소에 일부 함수를 적용하려고하므로 시퀀스 (배열, 수집, 입력 등)를 반복합니다.

스트림은 시퀀스 요소에 함수 를 구성 할 수있는 기능을 제공 하며 구체적인 경우에 관계없이 가장 일반적인 함수 (예 : 매핑, 필터링, 찾기, 정렬, 수집 등) 를 구현할 수 있습니다.

따라서 대부분의 경우 반복 작업이 주어지면 Streams를 사용하여 적은 코드로 표현할 수 있습니다 . 즉, 가독성 을 얻습니다 .


4
글쎄, 그것은 단지 가독성이 아닙니다. 작성할 필요가없는 코드는 테스트 할 필요가없는 코드입니다.
— user447607

3
인터뷰에 대한 좋은 답변도 나오고있는 것 같습니다
— wero

6

병렬화 가 너무 사용하기 쉽다고 말하고 싶습니다 . for 루프와 병렬로 수백만 개의 항목을 반복 시도하십시오. 우리는 많은 CPU에 더 빨리 가지 않습니다. 따라서 병렬로 실행하는 것이 더 쉬울수록 좋으며 Streams를 사용하면 산들 바람입니다.

내가 많이 좋아하는 것은 그들이 제공 하는 자세한 설명 입니다. 그것은의 반대로 실제로 수행 및 생산을 이해하기 위해 약간의 시간이 소요 어떻게 그들이 그것을 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.