우리는 람다가 자바에 클로저 개념을 도입하기를 오랫동안 기다려왔지만 컬렉션에서 사용하지 않는다면 많은 가치를 잃게 될 것입니다. 기존 인터페이스를 람다 스타일로 마이그레이션하는 문제는 기본 메서드를 통해 해결되었습니다. 이 기사에서는 Java 컬렉션의 대량 데이터 작업(대량 작업)을 심층적으로 분석하고 람다의 가장 강력한 역할에 대한 미스터리를 풀어보겠습니다.
1. JSR335에 대하여
JSR은 Java Spec Requests의 약어로 Java 사양 요청을 의미합니다. Java 8 버전의 주요 개선 사항은 Lambda 프로젝트(JSR 335)입니다. Java를 멀티 코어 프로세서용 코드 작성을 더욱 쉽게 만듭니다. JSR 335=람다 표현 + 인터페이스 개선(기본 방법) + 일괄 데이터 작업. 이전 두 기사와 함께 JSR335 관련 내용을 완전히 배웠습니다.
2. 외부 VS 내부 반복
과거 Java 컬렉션에서는 내부 반복을 표현할 수 없고 외부 반복 방식, 즉 for 또는 while 루프만 제공했습니다.
List persons = asList(new Person("Joe"), new Person("Jim"), new Person("John")); for (Person p : persons) { p.setLastName("Doe"); }
위의 예는 소위 외부 반복이라고 불리는 이전 접근 방식입니다. 루프는 고정 시퀀스 루프입니다. 오늘날의 멀티 코어 시대에 병렬 루프를 실행하려면 위의 코드를 수정해야 합니다. 효율성이 얼마나 향상될 수 있는지는 아직 불확실하며 특정 위험(스레드 안전 문제 등)이 발생할 수 있습니다.
내부 반복을 설명하려면 Lambda와 같은 클래스 라이브러리를 사용해야 합니다. 람다와 Collection.forEach를 사용하여 위 루프를 다시 작성해 보겠습니다.
persons.forEach(p->p.setLastName("Doe"));
이제 jdk 라이브러리가 루프를 제어합니다. 각 개인 개체에 성이 어떻게 설정되는지 신경 쓸 필요가 없습니다. 라이브러리는 실행 환경, 병렬, 비순차 또는 지연 로딩에 따라 이를 수행하는 방법을 결정할 수 있습니다. 이는 내부 반복이며 클라이언트는 p.setLastName 동작을 데이터로 API에 전달합니다.
내부 반복은 실제로 컬렉션의 배치 작업과 밀접한 관련이 없습니다. 이를 통해 문법 표현의 변화를 느낄 수 있습니다. 일괄 작업과 관련하여 정말 흥미로운 점은 새로운 스트림 API입니다. 새로운 java.util.stream 패키지가 JDK 8에 추가되었습니다.
3.Stream API
Stream은 데이터 스트림만 표현하고 데이터 구조가 없으므로 한 번 순회한 후에는 더 이상 사용할 수 없습니다. Traversal을 사용합니다(프로그래밍 시 주의해야 할 점은 Collection과 달리 몇 번을 탐색하더라도 여전히 데이터가 포함되어 있음). 소스는 Collection, array, io 등이 될 수 있습니다.
3.1 중간 및 최종 방법
플로우 기능은 빅데이터 운영을 위한 인터페이스를 제공하여 데이터 운영을 보다 쉽고 빠르게 만드는 것입니다. 필터링, 매핑, 순회 횟수 감소 등의 메서드가 있습니다. 이러한 메서드는 중간 메서드와 터미널 메서드의 두 가지 유형으로 구분됩니다. 중간 메서드는 기본적으로 항상 Stream을 반환해야 합니다. 우리는 최종 결과를 얻고 싶습니다. 그렇다면 엔드포인트 작업을 사용하여 스트림에서 생성된 최종 결과를 수집해야 합니다. 이 두 메서드의 차이점은 반환 값을 살펴보는 것입니다. Stream이면 중간 메서드이고, 그렇지 않으면 end 메서드입니다. 자세한 내용은 Stream의 API를 참조하세요.
여러 중간 방법(필터, 맵)과 끝점 방법(수집, 합계)에 대한 간략한 소개
3.1.1Filter
첫 번째 단계는 데이터 스트림의 필터링 기능 우리가 생각할 수 있는 가장 자연스러운 작업입니다. Stream 인터페이스는 필터 조건을 정의하는 람다 식을 사용하는 작업을 나타내는 Predicate 구현을 허용하는 필터 메서드를 노출합니다.
List persons = … Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);//过滤18岁以上的人
3.1.2Map
객체를 변환할 때와 같이 이제 일부 데이터를 필터링한다고 가정해 보겠습니다. Map 연산을 통해 입력 매개변수를 받아들이고 이를 반환하는 함수 구현(Function43ca9160a1fbc6e1e17f36fac17e2094의 일반 T 및 R은 각각 실행 입력 및 실행 결과를 나타냄)을 실행할 수 있습니다. 먼저 이를 익명 내부 클래스로 설명하는 방법을 살펴보겠습니다.
Stream adult= persons .stream() .filter(p -> p.getAge() > 18) .map(new Function() { @Override public Adult apply(Person person) { return new Adult(person);//将大于18岁的人转为成年人 } });
이제 위의 예를 람다 식으로 변환합니다.
Stream map = persons.stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person));
3.1.3Count
count method는 스트림 결과의 최종 통계를 작성하고 int를 반환할 수 있는 스트림의 끝점 방법입니다. 예를 들어 18세 이상의 총 사람 수를 계산해 보겠습니다.
int countOfAdult=persons.stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person)) .count();
3.1. 4Collect
collect 메서드는 최종 결과를 수집할 수 있는 스트림의 끝점 메서드이기도 합니다
List adultList= persons.stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person)) .collect(Collectors.toList());
또는 특정 구현 클래스를 사용하여 결과를 수집하려는 경우:
List adultList = persons .stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person)) .collect(Collectors.toCollection(ArrayList::new));
공간이 제한되어 있으며 기타 중간 메소드와 엔드포인트 메소드는 하나씩 소개하지 않습니다. 위의 예를 읽은 후 이 두 메소드의 차이점을 이해하고 결정하면 됩니다. 나중에 필요에 따라 사용하세요.
3.2 순차 및 병렬 스트림
각 스트림에는 순차 실행과 병렬 실행의 두 가지 모드가 있습니다.
순차 흐름:
List <Person> people = list.getStream.collect(Collectors.toList());
병렬 흐름:
List <Person> people = list.getStream.parallel().collect(Collectors.toList());
이름에서 알 수 있듯이 순차 흐름을 사용하여 순회하는 경우 각 항목을 읽고 다음 항목을 읽습니다. 병렬 순회를 사용하면 배열이 여러 세그먼트로 나누어지고 각 세그먼트는 서로 다른 스레드에서 처리된 다음 결과가 함께 출력됩니다.
3.2.1 병렬 스트림 원리:
List originalList = someData; split1 = originalList(0, mid);//将数据分小部分 split2 = originalList(mid,end); new Runnable(split1.process());//小部分执行操作 new Runnable(split2.process()); List revisedList = split1 + split2;//将结果合并
3.2.2 순차 및 병렬 성능 테스트 비교
멀티 코어 머신이라면 이론적으로 병렬 스트림은 순차 스트림보다 빠릅니다. 이전보다 두 배, 다음은 테스트 코드입니다
long t0 = System.nanoTime(); //初始化一个范围100万整数流,求能被2整除的数字,toArray()是终点方法 int a[]=IntStream.range(0, 1_000_000).filter(p -> p % 2==0).toArray(); long t1 = System.nanoTime(); //和上面功能一样,这里是用并行流来计算 int b[]=IntStream.range(0, 1_000_000).parallel().filter(p -> p % 2==0).toArray(); long t2 = System.nanoTime(); //我本机的结果是serial: 0.06s, parallel 0.02s,证明并行流确实比顺序流快 System.out.printf("serial: %.2fs, parallel %.2fs%n", (t1 - t0) * 1e-9, (t2 - t1) * 1e-9);
3.3 Folk/Join 프레임워크 소개
애플리케이션 하드웨어의 병렬 처리는 Java 7에서 사용할 수 있습니다. 즉, java.util.concurrent 패키지의 새로운 기능 중 하나는 포크 조인 스타일 병렬 분해 프레임워크로, 관심 있는 학생들에게도 매우 강력합니다. 가서 조사해 보세요. 여기서는 Stream.parallel()에 비해 자세히 설명하지 않겠습니다. 저는 후자를 선호합니다.
4. 요약
Stream이 있으면 위의 3.1.2map 예시와 같이 익명의 내부 클래스가 많이 생성됩니다. 기본 메서드가 아니므로 컬렉션 프레임워크가 변경될 수 있으므로 람다+기본 메서드는 jdk 라이브러리를 더욱 강력하고 유연하게 만듭니다. Stream 및 컬렉션 프레임워크의 개선이 가장 좋습니다.
더 많은 Java8의 새로운 기능, 람다 표현식의 용도(사용 예) 및 관련 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!