나는 Java8 스트림을 이해하려면 어떻게

(나의 이해는 상대적으로 낮은) 도입 Java8 스트림 기사를 많이 읽을 수 있지만 초기 접촉이 이해하기 정말 어렵 전에, 방법 할 수있는 전용 "기계적"하지만 어제는 내가 국, 소를 이겼다 (영광의 왕을 공격하지 마법 관객 MVP) 영감의 갑작스런 버스트가 갑자기 철저한 이해가 철저한 느낌 전에 이해하지 못했다. 그래서 결정이 간단한 방식으로 java8 스트림에서 불러올 수 있다고 생각합니다.

람다 표현식

문법

당신이 고찰을 수행하려면 먼저 여기, 람다 람다 표현식을 이해해야합니다 스트림 API를 사용하는 방법을 학습 할 수 있도록 람다 표현식 초석 스트림 API입니다.

우리는 종종 코드를 볼 수

Arrays.sort(new Integer[]{1, 8, 7, 4}, new Comparator<Integer>() {
   @Override
   public int compare(Integer first, Integer second) {
       return first.compareTo(second);
   }
});
复制代码

문구는 위의 우리가 한 번만 실행되기 때문에 우리는 종종 항상 존재하지 않는, 익명 클래스를 사용, 익명 클래스의 사용이다. , 함수형 프로그래밍이라고뿐만 아니라 지역 사회에서 모두가 오랜 후에 나올 무엇에 대한하지만 내 생각에 람다 식 파티에 있지만 그것을 (게으른) (도용).

위의 코드는 문제라고하지만, 이런 일이 다음으로 변환?

Arrays.sort(new Integer[]{1, 8, 7, 4},
	(first,second) -> first.compareTo(second));
复制代码

이 편안 이상을 보였지만, 불필요한 세부 사항은 숨겨져 있습니다. 이 방법은 추상적 인 인터페이스를 포함 들어, 기능적인 인터페이스라고 람다 인터페이스를 통해 인터페이스의 객체를 생성 할 수 있습니다.

람다 식 새로운 오퍼레이터 도입 -> 람다 식의 두 부분으로 분할되어있는

(n) -> n*n
复制代码

어떤 매개 변수가 null이 될 수 없다 경우 필요한 매개 변수는 식의 왼쪽을 지정합니다. 람다 람다 식의 동작을 지정하는 오른쪽 블록이다.

하나는 문없이 반환하는 방법 경우, 기본 반환 않습니다. 당신이 지점을 반환 할 시간이 있다면 문을 수행하기 위해 필요합니다.

(n) -> {
	if( n <= 10) 
		return n*n;
	return n * 10;
}
复制代码

그리고 생성자 메서드 참조 인용

방법 참조

어떤 경우에는, 우선 상기 방법으로 구현 된 다른 코드의 동작에 전달. 예를 들어, 버튼을 클릭하면 첫 번째 이벤트 객체를 인쇄해야하는 GUI, 당신은 호출 할 수 있습니다

button.setOnAction(event -> System.out.println(event));
复制代码

내가 게으른 할이 시간, 나는 하나 개의 매개 변수 때문에, JVM은 저를 도울 수, 이벤트 매개 변수를 쓰고 싶지 않아? 다음은 수정 된 코드가 좋다


button.setOnAction(System.out::println);
复制代码

System.out::println람다 식에있어서 당량 기준이다 x -> System.out.println(x). , 세 가지 주요 사용 따르고 있습니다 ** ** : 운영자 방법 이름과 객체 클래스의 이름이나 분리 :

  1. :: 개체 인스턴스 메소드
  2. :: 클래스 정적 메서드
  3. :: 클래스 인스턴스 메소드

처음 두 경우, 상기 방법은 람다 식의 기준 파라미터에 동등한 방법을 제공한다. 예를 들어 Math::pow ==== (x,y) -> Math.pow(x,y).

세 번째 경우, 착신 객체 실행 방법의 첫번째 인수. 예를 들어 String::compareToIgnoreCase ==== (x,y) -> x.compareToIgnoreCase(y).

this::equals ==== x -> this.equals(x), super::equals ==== super.equals(x).

생성자 참조

List<String> strList = Arrays.asList("1","2","3");
Stream<Integer> stream =  strList.stream().map(Integer::new);
复制代码

상기 코드는 Integer::new생성자 메소드 이름 참조가 새로운 것 이외에는, 생성자 기준이다. 여러 생성자가있는 경우, 컴파일러는 추론과 컨텍스트의 권리를 찾을 수 있습니다.

StreamAPI

단어 스트림은 스트림의 흐름, 스트림 흐름과 물의 흐름을 의미하는 변환합니다.

흐름

위의 표와 같이 데이터가 작은 물방울의 시작이며, 스트림처럼 나에게 보이는 다양한 치료, 물방울의 "요격"일부는 폐기, 후 몇 가지, 몇 가지 큰 색상, 일부는 삼각형이된다. 마지막으로, 그들은 색상으로 라운드 돌았 다. 우리는 마침내 결과 집합을 넣어. 수집 및 또는 변환 세트의 요소의 판정을 통해, 새로운 컬렉션은, 상기 방법이 방법도 동일되는 조건을 만족시키기 위해 추가된다 : 대부분의 시간 우리는 다음과 같은 코드가 물품. 코드 조각에서 첫보기

Map<String,Map<String,Integer>> resultMap = new HashMap<>();
Map<String,Integer> maleMap = new HashMap<>();
Map<String,Integer> femaleMap = new HashMap<>();

resultMap.put("male", maleMap);
resultMap.put("female",femaleMap);

for(int i = 0; i < list.size(); i++) {
    Person person = list.get(i);
    String gender = person.getGender();
    String level = person.getLevel();
    switch (gender) {
        case "male":
            Integer maleCount;
            if("gold".equals(level)) {
                maleCount = maleMap.get("gold");
                maleMap.put("gold", null != maleCount ? maleCount + 1 : 1);
            } else if("soliver".equals(level)){
                maleCount = maleMap.get("soliver");
                maleMap.put("soliver", null != maleCount ? maleCount + 1 : 1);
            }
            break;

        case "female":
            Integer femaleCount;
            if("gold".equals(level)) {
                femaleCount = femaleMap.get("gold");
                femaleMap.put("gold", null != femaleCount ? femaleCount + 1 : 1);
            } else if("soliver".equals(level)){
                femaleCount = femaleMap.get("soliver");
                femaleMap.put("soliver", null != femaleCount ? femaleCount + 1 : 1);
            }
            break;

    }
}

复制代码

효과 위의 코드는 엔지니어의 수는 자바 StreamAPI 아웃, 시스템에서 매우 유사한 비즈니스 코드가 모든 곳에서해야하기 전에, 다른 성별의 통계 순위이다가, 손 코드 위에 나는 스트림으로 약 2 분 후했다 나는 게으른를 훔쳐

Map<String,Map<String,Integer>> result = list.stream().collect(
    Collectors.toMap(
	    person -> person.getGender(),
	    person -> Collections.singletonMap(person.getLevel(), 1),
	    (existValue,newValue) -> {
	        HashMap<String,Integer> newMap = new HashMap<>(existValue);
	        newValue.forEach((key,value) ->{
	            if(newMap.containsKey(key)) {
	                newMap.put(key, newMap.get(key) + 1);
	            } else {
	                newMap.put(key, value);
	            }
	        });
	        return newMap;
	    })
);

复制代码

또는 그런 코드로

Map<String,Map<String,Integer>> result =  stream.collect(
    Collectors.groupingBy(
        Person::getGender, 
        Collectors.toMap(
            person->person.getLevel(), 
            person -> 1,
            (existValue,newValue) -> existValue + newValue
        )
    )
);

复制代码

단지 코드 블록, 논리도 명확의 수를 줄일 수 없습니다. 흐름과 함께 정말 멋진 순간, Shuangya을 사용하고있다.

물론 우리가 제한 (루프 흐름 제한에 대해)도가는 전술 한 바와 같이, 우리는 각각의 대류의 다양한 구성 요소들을 만들 수있는 가장 사용하거나 흐름 유한 또는 무한 수있다 흐름으로서, 치료의 일반적인 종류. 예를 들어, 요약, 필터링, 그룹화, 최대, 최소 및 기타 일반적인 과정, 그래서 것이 스트림 사용하기 시작

스트림 특성

  1. 스트림은 자신의 요소를 저장하지 않는 요소가 바닥에 설정 될 수 있으며, 생산 또는 저장된다.
  2. 스트림 연산자는 반대로, 소스 객체를 변경하지 않습니다, 그들은 새로운 스트림 객체를 잡고 돌아갑니다
  3. 스트림 연산자는 실행을 지연하기 위해, 당신은 실행하기 전에 결과 때까지 기다려야 할 수도 있습니다.

스트림 API

기능 인터페이스 매개 변수 유형 반환 유형 추상 메소드 이름 기술 다른 방법
실행 가능한 아니오 운영 동작 파라미터 및 반환 값을 행하지 않고, 아니오
공급 업체 <T> 아니오 도망 타입 T의 값을 제공
Counsumer <T> 동의 처리 값의 T 형 체인
BiConsumer <T, U> T, U 동의 T 형 및 U 형의 처리 값 체인
기능 <T, R> 아르 자형 대다 T 형 함수의 파라미터 구성, andThen, 정체성
BiFunction <T, U, R> T, U 아르 자형 대다 파라미터 타입은 U 및 T의 함수 인 그리고
UnaryOperator <T> 대다 형 T의 단항 연산자입니다 구성, andThen, 정체성
BinaryOperator <T> T, T 대다 T 형 이진 연산자이며 그리고
술어 <T> 부울 테스트 부울 함수 값을 계산 AND, OR, ISEQUAL를 부정
BiPredicate <T, U> T, U 부울 테스트 부울 연산을 두 매개 변수 함수 AND, OR, 부정

차이지도 ()와 flatMap ()의

지도 상에있어서, 각각의 요소에 적용 동등한 기능, 및 새로운 스트림을 사용하는 경우 수집 된 값이 리턴.

Stream<String[]>	-> flatMap ->	Stream<String>
Stream<Set<String>>	-> flatMap ->	Stream<String>
Stream<List<String>>	-> flatMap ->	Stream<String>
Stream<List<Object>>	-> flatMap ->	Stream<Object>

{{1,2}, {3,4}, {5,6} } -> flatMap -> {1,2,3,4,5,6}
复制代码

엔드 및 중간 작업

두 가지 범주로 스트림에 모든 작업 : 작업의 운영 및 중간 끝은 작업이 작업의 끝 부분 만 만 중간 마크 (. 이러한 방법으로 호출, 정말 스트림을 통과하기 시작되지 않음), 실제 계산을 실행할 것입니다. 간단히 그렇지 않으면 작업의 끝, 반환 값은 여전히 ​​API는 작업의 중간입니다 스트림 것을 의미한다.

어떻게 디버깅하는 방법

  1. 같은 코드 세그먼트를 사용하십시오 IntStream.of(1,2,3,4,5).fiter(i -> {return i%2 == 0;})코드 세그먼트에 공격 중단 점.
  2. 참조 방법은 isDouble 이러한 중단 점으로 표시된, 디버깅 할 수IntStream.of(1,2,3,4,5).fiter(MyMath::isDouble)

이 API의 그 이해 부족

  1. 가 완료되기 전에 우리는 방법을 (를 축적 함) 줄일?

int sum = 0;
for(int value in values) {
	sum = sum + value;
}

复制代码

이제 달성 할 수있는 방법으로 스트리밍

values.stream().reduce(Integer::sum);
复制代码

줄이기 () 메소드는 이진 함수이다 : 처음 두 기본 스트림의 시작부터,이 스트림 내의 다른 요소들에 적용되고 있습니다.

코드 스트림을 작성하는 방법

이 API는, 편의를 위해 설계되지 편리한 레벨 SQL 데이터 처리 동작을 합산 정렬 패킷 스트림 중합, 최대 값, 최소값, 등으로 구현 될 수있다 스트림. 그래서 너무 복잡, 충분한 쓰기하지 않습니다. 당신이 숙련 된 코드가 너무 단순 쓸 수 있습니다 어느 날 항상있다. 지금부터, 또는 스트림 모드로 변환 순환 많은 수의 프로젝트를 넣어.

샘플 코드

나는 스트림 API를 변환하는 큰 세그먼트 패턴에 코드를 작성하는 것을 의미하지만, 예를의 전환을 완료하기 위해 코드 hutool의 GitHub의 도구의 일부를 찾을 필요가 없다 생각했다. (당신은 API를 이런 식으로 스트리밍 할 수있는 능력을 향상시킬 수 있습니다)

  1. 각 요소가 나타나는 횟수를 계산 (달성하는 방법 jdk7에서 상상하십시오)
代码效果:[a,b,c,c,c]  -> a:1,b:1,c:3

Arrays.asList("a","b","c","c","c").stream().collect(Collectors.groupingBy(str->str, Collectors.counting()));
复制代码
  1. 분리기의 특정 세트에서 문자열로 변환합니다 (jdk7을 달성하는 방법을 상상하십시오) 접두사와 접미사를 추가한다
List<String> myList = Arrays.asList("a","b","c","c","c");
myList.stream().collect(Collectors.joining(",","{","}"));

复制代码
  1. 판단 불완전한 목록 (달성하는 방법 jdk7에서 상상하십시오) 비어
myList.stream().anyMatch(s -> !s.isEmpty());
复制代码

추천

출처juejin.im/post/5d536870e51d4561c6784066