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

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


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


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

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

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

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



답변

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

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

 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 사용량 측면에서 매우 가볍습니다. 원시 속도와 메모리 절약이 우선 순위 인 경우 스트림 사용이 더 나쁩니다.

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

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

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


답변

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

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


답변

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

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

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

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

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


답변

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

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

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


답변

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

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


답변