# 스트림 API 최고의 가이드 멋진

제 JavaStorm 공공 우려가 더 흥미로운 학습

자바 8은 아주 간단하고 가스가 유동 및 람다, 상 코드와 함께 사용 멋진 새로운 기능 람다 표현식 스트림 (스트림)를 제공합니다.

슈퍼 움직임은, 코드를 해제

수요가있을 경우 송장 정보 데이터베이스 쿼리를 처리 할 필요가있다 :

  1. 송장 금액을 제거하여 10,000 미만이다.
  2. 필터링 된 데이터를 정렬한다.
  3. 획득 주문 후 송장 측 핀 이름.

송장 모델

@Builder
@Data
public class Invoice implements Serializable {
    /**
     * 销方名称
     */
    private String saleName;
    /**
     * 是否作废
     */
    private Boolean cancelFlag;
    /**
     * 开票金额
     */
    private BigDecimal amount;
    /**
     * 发票类型
     */
    private Integer type;
    /**
     * 明细条数
     */
    private Integer detailSize;
}

复制代码

우리는 우리가 테스트 데이터 이전을 초기화, 전통적인 방법을 사용

public class StreamTest {

    private List<Invoice> invoiceList;

    @Before
    public void initData() {
        Invoice invoice = Invoice.builder().amount(BigDecimal.valueOf(100.02)).cancelFlag(false).detailSize(10)
                .saleName("广西制药").type(1).build();
        Invoice invoice2 = Invoice.builder().amount(BigDecimal.valueOf(89032478.9)).cancelFlag(false).detailSize(2)
                .saleName("深圳电子科技").type(1).build();
        Invoice invoice3 = Invoice.builder().amount(BigDecimal.valueOf(2077777889)).cancelFlag(true).detailSize(6)
                .saleName("宇宙心空").type(1).build();
        Invoice invoice4 = Invoice.builder().amount(BigDecimal.valueOf(356.8)).cancelFlag(false).detailSize(10)
                .saleName("孟达餐厅").type(2).build();
        Invoice invoice5 = Invoice.builder().amount(BigDecimal.valueOf(998.88)).cancelFlag(false).detailSize(0)
                .saleName("网红餐厅").type(2).build();
        Invoice invoice6 = Invoice.builder().amount(BigDecimal.valueOf(9009884.09)).cancelFlag(false).detailSize(1)
                .saleName("机动车").type(3).build();
        invoiceList = Stream.of(invoice, invoice2, invoice3, invoice4, invoice5, invoice6).collect(Collectors.toList());
        System.out.println("原始数据:" + invoiceList.toString());
    }
复制代码

Java8 구현하기 전에

/**
     * 筛选出金额小于 10000 的发票,根据金额排序,获取排序后的销方名称列表
     */
    @Test
    public void testJava7() {
        ArrayList<Invoice> lowInvoiceList = new ArrayList<>();
        //筛选出 金额小于 10000 的发票
        for (Invoice invoice: invoiceList) {
            if (invoice.getAmount().compareTo(BigDecimal.valueOf(10000)) < 0) {
                lowInvoiceList.add(invoice);
            }
        }
        // 对筛选出的发票排序
        lowInvoiceList.sort(new Comparator<Invoice>() {
            @Override
            public int compare(Invoice o1, Invoice o2) {
                return o1.getAmount().compareTo(o2.getAmount());
            }
        });
        // 获取排序后的销方名字
        ArrayList<String> nameList = new ArrayList<>();
        for (Invoice invoice : lowInvoiceList) {
            nameList.add(invoice.getSaleName());
        }

    }
复制代码

Java8 후 상 가스 동작은, 하나는 이동합니다. 더 이상 긴 코드의 악취 여분의 시간을 일해야하지

@Test
public void testJava8() {
  List<String> nameList = invoiceList.stream()
    .filter(item -> item.getAmount().compareTo(BigDecimal.valueOf(10000)) < 0)// 过滤数据
    .sorted(Comparator.comparing(Invoice::getAmount))// 对金额升序排序
    .map(Invoice::getSaleName)//提取名称
    .collect(Collectors.toList());//转换成list

}
复制代码

용 서비스를 느낌, 하나 모두는 하늘에 당신을 데려 갈. 크게 코드의 양을 줄일 수있다.

Niubi

그리고 지금 다시 요구

송장 데이터 분류를 확인하려면, 그것은지도 <정수, 목록> 데이터를 반환합니다.

Java7 아래의 문구를 불러, 내가 문질러 무언가가,이 너무 많은 문제가있다. 나는 여자 친구를 개최 최대한 빨리 다시 일하러 갈 수 없다.

@Test
public void testGroupByTypeJava7() {
  HashMap<Integer, List<Invoice>> groupMap = new HashMap<>();
  for (Invoice invoice : invoiceList) {
    //存在则追加
    if (groupMap.containsKey(invoice.getType())) {
      groupMap.get(invoice.getType()).add(invoice);
    } else {
      // 不存在则初始化添加
      ArrayList<Invoice> invoices = new ArrayList<>();
      invoices.add(invoice);
      groupMap.put(invoice.getType(), invoices);
    }
  }
  System.out.println(groupMap.toString());
}
复制代码

그런 다음 우리는 위의 요구 사항을 달성하기 위해 상 작동 코드의 스트림을 사용

groupingBy 그룹화

@Test
public void testGroupByTypeJava8() {
  Map<Integer, List<Invoice>> groupByTypeMap = invoiceList.stream().collect(Collectors.groupingBy(Invoice::getType));
}
复制代码

그것은 간단하고 원유, 코드의 황룡 라인을 파괴하는 것입니다.

로드 힘

스트림은 무엇인가?

스트림 (스트림)은 상기 데이터의 데이터 구조가 저장되어 있지 아니 주요 목적은 계산이다 데이터 소스 지원 중합 조작에서 큐 요소이다.

요소는 특정 타입의 객체이며, 큐를 형성한다. 자바 스트림에서와 요소를 저장하지만, 온 디맨드 컴퓨팅하지 않습니다. 데이터 소스의 유래. 세트, 배열, I / O 채널, 발전기 발전기 등을 할 수 있습니다. 이러한 필터,지도, 감소 발견, 일치, 분류 등의 SQL 문의 운영 등의 유사 중합 작업. 컬렉션 다른 이전 작업, 두 가지 기본 특성이있다 스트림 작업 :

  • 파이프 라이닝 : 중간 작업 스트림 객체 자체를 반환합니다. 이러한 동작은 유동 양식 (유창한 스타일)로서, 복수 개의 파이프로서, 직렬로 접속 될 수있다. 이는 지연 실행 (게으름)와 쇼트 (단락)와 같은 동작을 최적화한다.
  • 내부 반복은 : 컬렉션에 의해 또는를 들어-각 반복자 방법 통과하기 전에 명시 적으로 외부의 반복이라고 반복, 외부 설정합니다. 스트림은 반복 모드가 방문자 (방문자)에 의해 달성 내부 수있는 방법을 제공합니다.

어떻게 스트림을 생성하는 방법

다섯 개 가지 방법이 있습니다

1 세트 생성

Collection<String> collection = Arrays.asList("a", "b", "c");
Stream<String> streamOfCollection = collection.stream();
复制代码

어레이를 생성함으로써 2

int[] intArr = new int[]{1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(intArr);
复制代码

플로우 법에 의해 생성 Arrays.stream, 처리 흐름은 대신에 [즉 IntStream 수치 실시 생성된다 Stream<Integer>. 성능을 향상시키기 위해, 포장을 풀고의 수치 흐름 계산 프로세스를 사용하지 않는 것을 추가합니다.

스트림 API는 mapToInt, mapToDouble, mapToLong 제공 세 가지 방법, 즉 스트림 오브젝트의 스트림 [스트림] 대응하는 수치로 변환되고, 상기 방법은 또한 개체 스트림으로 박스형 값 흐름을 제공한다

값 생성 3.

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
复制代码

방법의 흐름에 의해 스트림을 생성 빈 빈 방법 스트림 흐름에 의해 생성 될 수있다

4. 파일에 의해 생성 된

Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
复制代码

Files.line 방법에 의해 얻어진 스트림, 생성 된 스트림 파일의 각 라인에 대해 주어진다

생성 된 함수는 대하여 반복하고, 두 정적 메소드는 함수로부터 생성 류를 생성

반복자 반복 처리 방법은 무한히 절단 제한 대류 방식에 의해 수행되는 생성 반복자 흐름 스트림으로서, 제 2 동작의 함수로서, 두 개의 매개 변수, 제 초기화 값을 얻어 상기도 5를 생성

Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
复制代码

발전기 : 이로부터 값 스트림 파라미터 유형 공급하여 매개 변수를 수용한다. 생성 된 생성 흐름 스트림은 무한대이므로 절단 대류 한도 수행

Stream<Double> stream = Stream.generate(Math::random).limit(5);
复制代码

조작 형 흐름

두 가지 주요 유형

1. 중간 작동

스트림은 0 또는 그 이상의 중간 조작 하였다 될 수있다. 주요 목적은 데이터 매핑 / 필터링 어느 정도하고, 흐름을 열 수하고 다음 작업을 사용하기 위해, 새로운 스트림을 반환합니다.

이러한 동작은 단지 이러한 방법을 호출하고, 스트림의 실제 시작 부분을 통과하지 않는 불활성으로하고, 실제 필요 단말 이송 동작까지 기다려야 중간 동작 바로 아래 제시된 일반적인 필터,지도 등을 갖는다

2. 단말기 작동

스트림은 오직 하나 개의 단말기 동작, 동작이 수행 될 때, 스트림이 더 이상 작동 될 스트림이 때문에 한번 생성 된 원본 데이터 스트림을 통과 할 필요가 통과 할 수없는 수 닫혀있다. 터미널 작업 스트림의 진정한 시작을 통과합니다 수행. 바로 후술하는 바와 같이, 수집 등등 카운트.

중간 동작 API

필터 스크리닝

Stream<Invoice> invoiceStream = invoiceList.stream().filter(invoice -> invoice.getDetailSize() < 10);
复制代码

별개의 제거 중복 요소

List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().distinct();
复制代码

스트림 지정된 제한의 수를 돌려줍니다

Stream<Invoice> invoiceStream = invoiceList.stream().limit(3);
复制代码

그렇지 않은 경우 예외가 발생 방법의 번호로 지정 복귀 유동 제한 제한해야 파라미터 값> = 0,

스킵 스트림 요소를 건너

 List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
 Stream<Integer> stream = integerList.stream().skip(2);
复制代码

상기 예 전에 두 요소 스킵, 기본 스트림에서 스킵 방법에 의해 스킵 인쇄 결과는 그렇지 않은 경우 예외가 발생> = 0이어야 파라미터 값을 스킵 2,3,4,5이다.

지도 흐름 매핑

소위 흐름 매핑은 다른 사람의 수신 요소 요소를 매핑하는 것이다

List<String> stringList = Arrays.asList("Java 8", "Lambdas",  "In", "Action");
Stream<Integer> stream = stringList.stream().map(String::length);
复制代码

이 예에서,지도 방법을 매핑하여 수행 할 수 있습니다, 전체 문자열 -> 정수 매핑,지도 방법 송장에 의해 위의 예를 완료하기 전에 -> 문자열 매핑

flatMap 스트림 변환

스트림의 각 값은 다른 스트림으로 변환

List<String> wordList = Arrays.asList("Hello", "World");
        List<String> strList = wordList.stream()
                .map(w -> w.split(""))// 将元素根据 空格分隔字符的Stream<String[]>
                .flatMap(Arrays::stream)// 将Stream<String[]> 转换成 Stream<String>
                .distinct() //去重
                .collect(Collectors.toList());
        System.out.println(strList.toString());
复制代码

지도 (w은 -> w.split ( " ")) 반환 값은 Stream<String[]>, 우리가 가져올 Stream<String>> 스트림 변환 - flatMap 방법 스트림하여 수행 할 수 있습니다. 그래서 최종 결과가 인쇄됩니다[H, e, l, o, W, r, d]

요소와 일치

  1. 모든 일치를 allMatch
if (invoiceList.stream().allMatch(Invoice::getCancelFlag)) {
  System.out.println("发票全是作废");
}
复制代码
  1. anyMatch 하나 개의 일치

무효 송장 인쇄가

if (invoiceList.stream().anyMatch(Invoice::getCancelFlag)) {
  System.out.println("存在作废发票");
}
复制代码

상당

for (Invoice invoice : invoiceList) {
  if (invoice.getCancelFlag()) {
    System.out.println("存在作废发票");
    break;
  }
}
复制代码
  1. noneMatch 모든 불일치
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().noneMatch(i -> i > 3)) {
    System.out.println("值都小于3");
}
复制代码

터미널 운영

통계적 유동 요소의 개수

  1. 사용 횟수
long count = invoiceList.stream()
  .filter(item -> item.getAmount().compareTo(BigDecimal.valueOf(10000)) < 0)
  .count();
复制代码
  1. 사용 계산
long count = invoiceList.stream()
  .filter(item -> item.getAmount().compareTo(BigDecimal.valueOf(10000)) < 0)
  .collect(Collectors.counting());
复制代码

콜렉트와 함께 사용되는 경우 최종적으로, 통계적 방법은 소자의 수에 특히 유용

탐색

  1. 먼저 찾기를 FindFirst
Optional<Invoice> first = invoiceList.stream()
  .filter(item -> item.getAmount().compareTo(BigDecimal.valueOf(10000)) < 0)
  .findFirst();
复制代码

로 findFirst으로 10,000 미만의 양의 첫 번째 요소를 찾을 수

  1. 임의의 findAny 찾기
Optional<Invoice> any = invoiceList.stream()
  .filter(item -> item.getAmount().compareTo(BigDecimal.valueOf(10000)) < 0)
  .findAny();
复制代码

요소가 10,000 미만인 인쇄물을 특징으로하는 방법에 의해 findAny을 검색하고 있기 때문에 내부의 최적화, 그것의 첫 번째 요소를 발견 할 때보다 세 방법의 결과로 끝나고로 findFirst 방법 결과 충족. FindAny 방법 더 병렬 스트림 이용 FindFirst에 더 엄격한 방법 [병렬 병렬 스트림을 도입하지 않을 것이다 나란히]를 수행하기 위하여 제공된다

조합 된 스트림 요소를 줄일

우리는 값 세트를 요약했다 가정

jdk8 전

int sum = 0;
for (int i : integerList) {
	sum += i;
}
复制代码

후 처리 jdk8 줄이기

int sum = integerList.stream().reduce(0, (a, b) -> (a + b));
//还可以用方法引用写
int sum = integerList.stream().reduce(0, Integer::sum);
复制代码

통계적 합산 송장 금액 등

BigDecimal reduce = invoiceList.stream().map(Invoice::getAmount).reduce(BigDecimal.ZERO, (a, b) -> (a.add(b)));
复制代码

단순화 된 방법 참조를 계속 사용

BigDecimal reduce = invoiceList.stream().map(Invoice::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
复制代码

감소는 초기 값이 0 인 두 개의 매개 변수를 받아 BinaryOperator<T> accumulator, 두 요소가 새로운 값을 생성하기 위해 결합

이 방법은 더 값 초기화 메소드를 오버라이드 (override)하지 않는 감소

취득 최소 및 최대 유량

최소의 최소 / 최대의 최대 값을 획득함으로써

Optional<BigDecimal> min = invoiceList.stream().map(Invoice::getAmount).min(BigDecimal::compareTo);
Optional<BigDecimal> max = invoiceList.stream().map(Invoice::getAmount).max(BigDecimal::compareTo);
复制代码

또한 같이 쓸 수있다

OptionalInt min1 = invoiceList.stream().mapToInt(Invoice::getDetailSize).min();
OptionalInt max1 = invoiceList.stream().mapToInt(Invoice::getDetailSize).max();
复制代码

유동 분의 최소값, 최대 값, 최대 획득 플로우 처리 파라미터를 구하는Comparator<? super T> comparator

최소 minBy / maxBy의 최대 값을 획득함으로써

invoiceList.stream().map(Invoice::getAmount).collect(Collectors.minBy(BigDecimal::compareTo)).get();
复制代码

획득함으로써 최소 및 최대 감소

Optional<BigDecimal> max = invoiceList.stream().map(Invoice::getAmount).reduce(BigDecimal::max);
复制代码

합산

summingInt으로

Integer sum = invoiceList.stream().collect(Collectors.summingInt(Invoice::getDetailSize));
复制代码

데이터 유형은 두 경우, 긴 summingDouble, summingLong 방법을 합산하여 수행

에 의해 감소

Integer sum = invoiceList.stream().map(Invoice::getDetailSize).reduce(0, Integer::sum);
复制代码

합함으로써, 최적의 표현

//推荐写成
Integer sum = invoiceList.stream().mapToInt(Invoice::getDetailSize).sum();
复制代码

위의 요약에서, 최대 값을 선택하고, 동일한 동작을위한 최소 시간은 다른 실행 방법이 선택 될 수 있습니다. 감소 수집합니다 선택할 수 있습니다, 최소 / 최대 / 합계 방법은 최소, 최대, 합계 방법을 권장합니다. 이 값 mapToInt 스트림 오브젝트의 스트림을 판독하는 것이 가장 단순하기 때문에, 권투 언 박싱의 조작하지

averagingInt을 평균하여

Double avg = invoiceList.stream().collect(Collectors.averagingInt(Invoice::getDetailSize));
复制代码

데이터 유형은 이중, 긴 평균화 averagingDouble 통해 수행된다 averagingLong 방법이면

BigDecimal를 위해 당신은 조각의 총 개수로 나눈 첫 합 필요

List<BigDecimal> sumList = invoiceList.stream().map(Invoice::getAmount).collect(Collectors.toList());
        BigDecimal average = average(sumList, RoundingMode.HALF_UP);
// 求平均值
public BigDecimal average(List<BigDecimal> bigDecimals, RoundingMode roundingMode) {
  BigDecimal sum = bigDecimals.stream()
    .map(Objects::requireNonNull)
    .reduce(BigDecimal.ZERO, BigDecimal::add);
  return sum.divide(new BigDecimal(bigDecimals.size()), roundingMode);
}
复制代码

summarizingInt 동시에함으로써 합계, 평균, 최대 값, 최소값을 얻는

IntSummaryStatistics statistics = invoiceList.stream().collect(Collectors.summarizingInt(Invoice::getDetailSize));
double average1 = statistics.getAverage();
int max1 = statistics.getMax();
int min1 = statistics.getMin();
long sum = statistics.getSum();
复制代码

원소 foreach 문에 의해 통과

invoiceList.forEach(item -> {
  System.out.println(item.getAmount());
});
复制代码

요소를 결합함으로써 스트림을 스 플라이 싱

String result = invoiceList.stream().map(Invoice::getSaleName).collect(Collectors.joining(", "));
复制代码

groupingBy에 의해 그룹화

 Map<Integer, List<Invoice>> groupByTypeMap = invoiceList.stream().collect(Collectors.groupingBy(Invoice::getType));
复制代码

수신 그룹핑 방법 GroupingBy를 수집하는 방법 groupingBy 분류 함수의 파라미터. 또한 다단계 중첩 groupingBy에 의해 분류 될 수있다

Map<String, Map<String, List<RzInvoice>>> = invoiceList.stream().collect(Collectors.groupingBy(Invoice::getType, Collectors.groupingBy(invoice -> {
    if (invoice.getAmount().compareTo(BigDecimal.valueOf(10000)) <= 0) {
        return "low";
    } else if (invoice.getAmount().compareTo(BigDecimal.valueOf(80000)) <= 0) {
        return "mi";
    } else {
        return "high";
    }
})));
复制代码

우선, 송장 형 패킷에 기초하여, 그 패킷의 크기에 기초하여 상기 과금 액은, 리턴 된 데이터 유형이 맵은 <문자열지도 <문자열 일람 >>

partitioningBy하여 고급 파티션

특별 진실과 거짓을 기반으로 분류 패킷, 이렇게 두 그룹으로 반환되는 결과

Map<Boolean, List<Dish>> = invoiceList.stream().collect(Collectors.partitioningBy(RzInvoice::getCancelFlag));
复制代码

상당

Map<Boolean, List<Dish>> = invoiceList.stream().collect(Collectors.groupingBy(RzInvoice::getCancelFlag));
复制代码

이 예는, 분할 조금 명백한 예를 변경할 필요가 없습니다 않았더라도 구역 및 분류와의 차이를 볼 수 없습니다 :

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Map<Boolean, List<Integer>> result = integerList.stream().collect(partitioningBy(i -> i < 3));
复制代码

처리 조닝 분류가 적합 범위에 따른 범위에 따라 리턴 값은 결합 부울 타입은 유지되지만, 그 분류는 분류

샘플에 그는 직장에서 발생

// 过滤T-1至T-12 近12月数据,根据省份分组求和开票金额,使用金额进行倒序,产生LinkedHashMap
        LinkedHashMap<String, BigDecimal> areaSortByAmountMaps =
                invoiceStatisticsList.stream().filter(FilterSaleInvoiceUtil.filterSaleInvoiceWithRange(1, 12, analysisDate)) //根据时间过滤数据
                        .collect(Collectors.groupingBy(FkSalesInvoiceStatisticsDO::getBuyerAdministrativeAreaCode
                                , Collectors.reducing(BigDecimal.ZERO, FkSalesInvoiceStatisticsDO::getInvoiceAmount, BigDecimal::add)))// 根据开票地区分组,并同时将每个分组数据的开票金额求和
                        .entrySet().stream().sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed()) // 根据金额大小倒序
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); //收集数据生成LinkedHashMap
复制代码

개요

스트림 API는 코드를 사용하여 단순화 및 코드 가독성을 향상하고, 신속하게 프로젝트에서 사용할 수 있습니다. 스트림 API를 학습하지 않은 이유에 앞서, 응용 프로그램 내에서 나에게 람다를 많이 쓴 사람이, 스트림 API는, 그의 발을 비행하고 싶었다.

나는 그에게 [헤 헤]을 사랑하는 것 같아요. 동시에주의 시간 선언적 및 명령형 프로그래밍 믹스를 사용하지.

추천

출처juejin.im/post/5d906754e51d4578014332df