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.