우리 흐름 얘기 좀 하자!!
여보게, 저기!
본고에서 나는 자바의 흐름과 간결한 생산 코드를 작성하는 데 어떻게 도움이 되는지 토론할 것이다.
그러나 흐름을 깊이 연구하기 전에 함수 프로그래밍에 대해 이야기합시다
자바 개발자로서 우리는 자바의 지루한 본질과 단어를 어떻게 인쇄하는지 자주 질문을 받는다. 우리는 대략 5-8행 코드를 작성해야 한다.😭
이것은 JAVA 8이 등장하기 전의 장면이다.
함수식 프로그래밍을 포함하여 JAVA 코드의 상세도를 70% 정도 낮출 수 있습니다.😮
내 관점으로 돌아가서 함수 프로그래밍이 무엇인지 봅시다.
🎯 함수식 프로그래밍❓
함수식 프로그래밍 (FP) 은 순수 함수를 만들어서 소프트웨어 구조를 생각하는 방법이다.그것은 공유 상태와 대상 프로그래밍에서 관찰된 가변 데이터의 개념을 피했다.
함수식 언어는 문장의 집행이 아니라 표현식과 성명을 강조한다.따라서 국부 또는 전역 상태에 의존하는 다른 과정과 달리 FP의 값 출력은 함수에 전달되는 매개 변수에 달려 있다.
🎯 함수식 프로그래밍의 특징:
함수 프로그래밍 방법은 과정이 아니라 결과를 중시한다
중점은 계산할 내용이다
🎯 함수식 프로그래밍의 장점:
이게 어떻게 JAVA 흐름에서 이루어졌는지 보여드릴게요.
간단하게 말하면 흐름은 데이터 원본 주위의 포장으로 우리가 이 데이터 원본을 사용하여 조작할 수 있고 대량 처리를 편리하고 신속하게 할 수 있다.
흐름은 데이터를 저장하지 않는다. 이런 의미에서 말하자면, 그것은 데이터 구조가 아니다.그것도 하부 데이터 원본을 수정한 적이 없다.
이 기능 – java.util.stream - 요소 흐름의 함수식 조작을 지원합니다. 예를 들어 집합의map-reduce 변환입니다.
✅ Streams를 배우기 전에 다음과 같은 중요한 개념을 적어 둡니다.
1. Stream은 집합에서 파생된 데이터 흐름
2. Stream은 평가 가능한 기능 파이핑을 생성합니다.
3. 흐름 중의 데이터가 평가 지연됨
흐름은 데이터를 변환할 수 있지만 변이할 수 없다.
🎯 [주의] - 흐름은 데이터 구조가 아니다.그 밖에 그 위에 흐름을 만드는 데이터 구조는 전혀 바뀌지 않았다.흐름은 단지 그것을 복제하고 자신의 복사본에서 약간의 조작을 실행할 뿐이다.
이것은 매우 좋은데, 어떻게 흐름을 만듭니까?😕
🎯 흐름 생성:
✔️ 먼저 기존 스토리지에서 스트림을 가져옵니다.
private static Dev[] arrayOfDevs = {
new Dev(1, "Steve Rogers", 100000.0),
new Dev(2, "Anthony Stark", 200000.0),
new Dev(3, "Bruce Wayne", 300000.0)
};
Stream.of(arrayOfDevs);
✔️ 기존 목록에서 스트림을 가져올 수도 있습니다.private static List<Dev> devList = Arrays.asList(arrayOfDevs);
devList.stream();
Stream.of(arrayOfDevs[0], arrayOfDevs[1], arrayOfDevs[2]);
✔️ 흐름을 간단하게 사용하거나.생성기():Stream.Builder<Dev> devStreamBuilder = Stream.builder();
devStreamBuilder.accept(arrayOfDev[0]);
devStreamBuilder.accept(arrayOfDev[1]);
devStreamBuilder.accept(arrayOfDev[2]);
Stream<Dev> devStream = devStreamBuilder.build();
이제 우리는 흐름을 만드는 방법을 알게 되었다.😎하지만 우리가 개울가에서 놀지 못하면 무슨 소용이 있겠는가.
🎯 흐름 작업:
이제 우리는 이 언어의 흐름 지원의 도움으로 실행할 수 있는 흔한 용법과 조작을 살펴보자.
✔️ forEach 회사:
forEach()는 가장 간단하고 흔히 볼 수 있는 조작이다.그것은 흐르는 원소에서 순환하고, 모든 원소에서 제공하는 함수를 호출한다.
이 방법은 매우 흔한 방법으로 Iterable, Map 등에서 직접 소개되었습니다.
@Test
public void whenIncrementSalaryForEachDev_thenApplyNewSalary() {
devList.stream().forEach(d -> d.salaryIncrement(10.0));
assertThat(devList, contains(
hasProperty("salary", equalTo(110000.0)),
hasProperty("salary", equalTo(220000.0)),
hasProperty("salary", equalTo(330000.0))
));
}
이것은 devList의 모든 요소에 salaryIncrement()를 효과적으로 호출합니다.forEach () 는 터미널 작업입니다. 이것은 이 작업을 실행한 후에 파이프가 소모된 것으로 간주되고 다시 사용할 수 없다는 것을 의미합니다.
✔️ 지도.
map () 은 함수를 원시 흐름의 모든 요소에 적용한 후 새로운 흐름을 생성합니다.새로운 흐름은 서로 다른 유형일 수 있다.
다음 예제에서는 정수 흐름을 개발자 흐름으로 변환합니다.
@Test
public void whenMapIdToDevs_thenGetDevStream() {
Integer[] devIds = { 1, 2, 3 };
List<Dev> devs = Stream.of(devIds)
.map(devRepository::findById)
.collect(Collectors.toList());
assertEquals(devs.size(), devIds.length);
}
여기서, 우리는 한 그룹에서 정수 dev id 흐름을 얻습니다.모든 정수는 함수 devRepository::findById() – 이 함수는 해당하는 Dev 대상을 되돌려줍니다.이것은 효과적으로 개발 흐름을 형성했다.✔️ 모으다
우리는 앞의 예시에서collect()의 작업 원리를 보았다.일단 우리가 모든 처리를 끝낸다면, 이것은 흐름에서 정보를 얻는 흔한 방법 중의 하나이다.
@Test
public void whenCollectStreamToList_thenGetList() {
List<Dev> devs = devList.stream().collect(Collectors.toList());
assertEquals(devList, devs);
}
collect () 는 흐르는 실례에 저장된 데이터 요소에 대해 가변 접기 작업을 실행합니다. (요소를 일부 데이터 구조로 다시 포장하고 추가 논리를 적용하여 연결합니다.이 동작의 정책은 수집기 인터페이스를 통해 제공됩니다.위의 예에서, 우리는 toList 수집기를 사용하여 모든 흐름 요소를 목록의 실례에 수집합니다.
✔️ 필터
다음은 Filter () 를 봅시다.이것은 주어진 테스트 (술어로 지정) 를 통과한 원시 흐름의 요소를 포함하는 새로운 흐름을 생성할 것이다.
어떻게 작동하는지 살펴보겠습니다.
@Test
public void whenFilterDevs_thenGetFilteredStream() {
Integer[] devIds = { 1, 2, 3, 4 };
List<Dev> devs = Stream.of(devIds)
.map(devRepository::findById)
.filter(e -> e != null)
.filter(e -> e.getSalary() > 200000)
.collect(Collectors.toList());
assertEquals(Arrays.asList(arrayOfDevs[2]), devs);
}
위의 예에서 우리는 먼저 잘못된 개발 ID의 빈 인용을 필터한 다음에 필터를 다시 적용하여 개발자의 임금이 한도값을 초과하도록 합니다.✔️ 회사 명
collect () 를 사용하여 흐름에서 데이터를 가져오는 방법을 보았습니다.흐름에서 그룹을 가져오려면 toArray () 를 사용하십시오.
@Test
public void whenStreamToArray_thenGetArray() {
Dev[] devs = devList.stream().toArray(Dev[]::new);
assertThat(devList.toArray(), equalTo(devs));
}
문법 Dev[]: new는 Dev의 빈 그룹을 만들고 흐르는 요소로 이 그룹을 채웁니다.🎯 [주]
지연 평가
흐름의 가장 중요한 특징 중 하나는 지연 평가를 통해 중대한 최적화를 할 수 있다는 것이다.
터미널 작업이 시작될 때만 원본 데이터에 대한 계산을 실행하고 필요할 때만 원본 요소를 소모합니다.
모든 중간 조작은 타성이기 때문에 실제 처리 결과가 필요하기 전에는 실행하지 않는다.
예를 들어, 앞에서 본 findFirst () 예제를 고려하십시오.여기에서 맵 () 동작을 몇 번 실행했습니까?네 번, 입력 그룹에 네 개의 요소가 포함되어 있기 때문에?
@Test
public void whenFindFirst_thenGetFirstDevInStream() {
Integer[] devIds = { 1, 2, 3, 4 };
Dev devs= Stream.of(devIds)
.map(devRepository::findById)
.filter(e -> e != null)
.filter(e -> e.getSalary() > 100000)
.findFirst()
.orElse(null);
assertEquals(devs.getSalary(), new Double(200000));
}
Stream은 매핑과 두 개의 필터 작업을 한 번에 하나씩 수행합니다.이것은 우선 id1에 대해 모든 조작을 실행합니다.id1의 임금이 100000을 넘지 않기 때문에 처리는 다음 요소로 넘어갑니다.
Id2는 이 두 필터 술어를 만족시키기 때문에 터미널 작업findFirst () 를 흐름하여 결과를 되돌려줍니다.
id 3과 4에 대한 작업이 실행되지 않았습니다.
지연 처리 흐름은 불필요할 때 모든 데이터를 검사하는 것을 피할 수 있다.입력 흐름이 매우 큰 것이 아니라 무한할 때 이런 행위는 더욱 중요해진다.
Java Streams Api는 매우 큰 주제입니다. 저는 이 글에 적응하기 위해 최선을 다했습니다.
자세한 내용은 다음 링크를 참조하십시오.
👇
Link for reference-1
Oracle docs
Baeldung link
내 기타 게시물:
개념
링크
Java 액세스 수정자
Java 범용
Java 정규 표현식
Java Streams Api
하나 남겨주세요.❤️ 만약 네가 이 문장을 좋아한다면.
A.🦄 다행이네요.
만약 당신이 나에게 어떤 건의가 있다면, 토론 그룹에서 나에게 알려주세요.
다른 사람들에게 도움을 줄 수 있는 Java Streams Api의 모든 자원을 가리키는 링크를 남겨 주십시오. 댓글에 추가할 것입니다.
오늘 하루 즐겁게 보내세요!😃
Reference
이 문제에 관하여(우리 흐름 얘기 좀 하자!!), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/the_unconventional_coder/lets-talk-about-streams-2bdf텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)