Develope Story

2019-07-30 [Spring-study] DB없이 회원가입 및 목록 기능 구현

|

DB없이 회원가입 및 목록 기능 구현

공부한 내용

###template engine

  • html = 정적 <-> tepmplate engine = 동적

###Mustache

Ex)

Hello  You have just won  dollars!  Well,  dollars, after
taxes. 
{
  "name": "Chris",
  "value": 10000,
  "taxed_value": 10000 - (10000 * 0.4),
  "in_ca": true
}

Model

  • ModelAttribute(" ") => view 로 문자열을 전달해줌

###html 중복 제거

  • base.html

<h1>Title</h1>
   
<span>Powered by Handlebars.java</span>

  • Content.html

<p>Home page</p>
content 자리에 들어갈 내용~!~!~~ 
 

###WebMvcConfigurer

@Configuration
public class MvcConfig implements WebMvcConfigurer {

  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
    registry.setOrder(Ordered.HIGHEST_PRECEDENCE);

    registry.addViewController("/user/form").setViewName("user/form");
    registry.addViewController("/user/login").setViewName("user/login");
    registry.addViewController("/").setViewName("main/index");
  }
}
  • url 를 함수로 일일히 구현 x 자동으로 연결시켜줌
  • templates에있는 이름.html 실행

###Service 참고 자료

image-20190730224651019

   
Controller Request를 어떻게 처리
Service Request를 어떤 처리
Dao Data access object
VO 값을 표현하는 객체

Client — Request —> Controller —> Service

Service —> Controller —> client

  • service
    • Interface 만들어서 class 구현

Restful Api 참고자료

REST 구성

  • 자원(Resource) - URI
  • 행위(Verb) - HTTP METHOD
  • 표현(Representations)

**Rest API 규칙 **

  1. URI는 정보의 자원을 표현해야함 ( 리소스명은 동사보다는 형용사 )

    GET /members/delete/1 => x delete와 같은 행위에 대한 표현이 들어가면 안됨.

  2. 자원에 대한 행위는 HTTP Method(Get, Post, Put, Delete 등)로 표현

  • 회원 정보를 가져오는 URI

    GET /members/show/1     (x)
    GET /members/1          (o)
    
  • 회원 정보를 추가할 때

     GET /members/insert/2 (x)  - GET 메서드는 리소스 생성에 맞지 않습니다.
     POST /members/2       (o)
    
Method 역할
POST 해당 URI를 요청하면 리소스를 생성합니다
GET 리소스를 조회합니다
PUT 리소스를 수정합니다
DELETE 리소스를 삭제합니다.

URI 설계 주의 사항

  1. / 는 계층 관계를 나타내는 데 사용
  2. 마지막에 / 를 포함하지 않는다.
  3. - (하이픈)을 통해 가독성 UP
  4. _(언더바)는 사용하지 않는다.
  5. URI 경로에는 소문자가 적합하다
  6. 파일 확장자 불포함

리소스 간의 관계 표현

  /리소스명/리소스 ID/관계가 있는 다른 리소스명
  ex)GET : /users/{userid}/devices (일반적으로 소유 ‘has’의 관계를 표현할 때)
  	 GET : /users/{userid}/likes/devices (관계명이 애매하거나 구체적 표현이 필요할 때)

자원을 표현하는 Colllection과 Document

http:// restapi.example.com/sports/soccer/players/13 
  • ports, players 컬렉션과 soccer, 13(13번인 선수)를 의미하는 도큐먼트로 URI가 이루어지게 됩니다. 여기서 중요한 점은 컬렉션은 복수로 사용하고 있다는 점

궁금 궁금

Spring Framework 구조

image-20190730211448228

singletone을 권장하는 이유

  • 일반적인 구조는 스레드 수만큼 객체 생성 but 스프링은 xml에 bean으로 미리 정의해 놓고 각 스레드가 자원을 공유 하면서 실행.

왜 Dao, Service에서 Interface를 사용하는가?

  • 유지보수가 편한 코드를 작성하도록 유도
  • 굳이 안 써도 된다는 의견이 많음 : 안써도 잘돌아감, 프로젝트에 따라 다름…토의 내용

리뷰

  • 종근이형

    • 다형성에 대해 알아보고 다시 반영해봤으면 좋겠습니다.
      • 다형성 : 상속을 통해 기능을 확장하거나 변경 하는 것을 가능하게 해주고, 같은 클래스 내에 코드의 길이를 줄여줌.
      • 깜박함…
    • users를 전역변수로 선언한 특별한 이유가 있을까요?
      • 전역변수(?) 멤버변수 아닌가요? 멤버변수로 선언한 이유는 1. 자바지기가 시켜서 2. db가 없기 때문에 userController에 모두 접근 할 수 있는 곳
    • @RequestMapping에 대해 알아보고 중복을 줄여보세요
      • @RequestMapping(/url) -> /url + …
    • service 레이어에 대해 알아보고 controller에서 비즈니스 로직을 분리해보세요
      • controller, service, Dao, vo 로 분리해보겠습니다
  • 혁진이형

    • Restful 관련 공부 https://meetup.toast.com/posts/92
    • url 에서 create 동사 이용 x
      • get /users -> 유저 정보를 다 가져온다
      • get /users/1 -> 1번 유저정보를 가져온다
      • post /users -> 유저 정보를 브라우저에서 서버로 날린다.
      • put /users/1 -> 1번 유저 정보를 수정한다
    • @Repository 어노테이션 공부
      • @Repository = 해당 클래스가 데이터베이스에 접근하는 클래스임을 명시
    • static -> templates 로 옮기기
    • 자바 진영에서 패키지는 소문자로

후기

웹 프로젝트 때문에 js 만하다가 오랜만에 자바로 돌아왔다. 그래서 그런가 접근제한자나 다형성 부분에서 실수가 발생하였다. 스프링를 처음 접해보았는 데 코드 구현 보다는 이노테이션 같은 부분에서 공부가 많이 필요했다. 코드를 작성하다보니 왜 이걸 이렇게 작성하지.. 왜 사용 하는 지 의문이 들었고 그 것에 대해 구글링은 해보면 공부해야 할 것들이 산더미 같이 많았다. 음.. 첫 스프링은 만족했다. 하지만 아직까지 nodejs 보다는 불편 함이 많았고 더 어렵게 느껴졌다. 최근 kotlin 에 꽂혀서 빨리 스프링을 공부하고 kotlin 으로 스프링을 구현 해보고 싶다는 생각이 들었다.

2019-06-01 [java-study] 로또2단계 스터디

|

로또 2단계

기능 요구사항

  • 2등을 위해 추가 번호를 하나 더 추첨한다.
  • 당첨 통계에 2등도 추가해야 한다.
  • 사용자가 수동으로 추첨 번호를 입력할 수 있도록 해야 한다.
구입금액을 입력해 주세요.
14000

수동으로 구매할 로또 수를 입력해 주세요.
3

수동으로 구매할 번호를 입력해 주세요.
8, 21, 23, 41, 42, 43
3, 5, 11, 16, 32, 38
7, 11, 16, 35, 36, 44

수동으로 3장, 자동으로 11개를 구매했습니다.
[8, 21, 23, 41, 42, 43]
[3, 5, 11, 16, 32, 38]
[7, 11, 16, 35, 36, 44]
[1, 8, 11, 31, 41, 42]
[13, 14, 16, 38, 42, 45]
[7, 11, 30, 40, 42, 43]
[2, 13, 22, 32, 38, 45]
[23, 25, 33, 36, 39, 41]
[1, 3, 5, 14, 22, 45]
[5, 9, 38, 41, 43, 44]
[2, 8, 9, 18, 19, 21]
[13, 14, 18, 21, 23, 35]
[17, 21, 29, 37, 42, 45]
[3, 8, 27, 30, 35, 44]

지난 주 당첨 번호를 입력해 주세요.
1, 2, 3, 4, 5, 6
보너스 볼을 입력해 주세요.
7

당첨 통계
---------
3개 일치 (5000원)- 1개
4개 일치 (50000원)- 0개
5개 일치 (1500000원)- 0개
5개 일치, 보너스 볼 일치(30000000원) - 0개
6개 일치 (2000000000원)- 0개
총 수익률은 35.7%입니다.

프로그래밍 요구사항

  • 모든 기능을 TDD로 구현해 단위 테스트가 존재해야 한다. 단, UI(System.out, System.in) 로직은 제외
  • 예외 처리를 통해 에러가 발생하지 않도록 한다.
  • 규칙 3: 모든 원시값과 문자열을 포장한다.
  • 규칙 5: 줄여쓰지 않는다(축약 금지).
  • 규칙 8: 일급 콜렉션을 쓴다.

힌트

  • 규칙 3: 모든 원시값과 문자열을 포장한다.

    • 로또 숫자 하나는 int 타입이다. 이 숫자 하나를 추상화한 LottoNo 객체를 추가해 구현한다.
  • 규칙 8: 일급 콜렉션을 쓴다.

    • 사용자가 구매한 로또 한장을 Lotto 객체, 당첨 번호에 해당하는 로또를 WinningLotto 객체로 추상화한다.
  • 하드 코딩을 하지 않기 위해 상수 값을 사용하면 많은 상수 값이 발생한다. 자바의 enum을 활용해 상수 값을 제거한다. 즉, enum을 활용해 일치하는 수를 로또 등수로 변경해 본다.

    public enum Rank {
      FIRST(6, 2000000000),
      SECOND(5, 30000000),
      THIRD(5, 1500000),
      FOURTH(4, 50000),
      FIFTH(3, 5000),
      MISS(0, 0);
      
      private int countOfMatch;
      private int winningMoney;
      
      private Rank(int countOfMatch, int winningMoney) {
          this.countOfMatch = countOfMatch;
          this.winningMoney = winningMoney;
      }
      
      public int getCountOfMatch() {
          return countOfMatch;
      }
      
      public int getWinningMoney() {
          return winningMoney;
      }
      
      public static Rank valueOf(int countOfMatch, boolean matchBonus) {
          // TODO 일치하는 수를 로또 등수로 변경한다. enum 값 목록은 "Rank[] ranks = values();"와 같이 가져올 수 있다.
          return null;
      }
    }
    

할일

  • test코드를 먼저짠다

    => test코드를 먼저짜는 이유 https://www.youtube.com/watch?v=cVxqrGHxutU&t=2111s

  • enum 공부하고 적용하자

  • 로또 숫자 하나는 int 타입이다. 이 숫자 하나를 추상화한 LottoNo 객체를 추가해 구현한다.

    => 숫자 범위 밖 에러 발생

공부한 내용

  • Enum

http://woowabros.github.io/tools/2017/07/10/java-enum-uses.html참고

  • comparable 과 comparator 차이

    • comparable : 객체 간의 일반적인 정렬이 필요할 때, Comparable 인터페이스를 확장해서 정렬의 기준을 정의

      int compareTo(T o)
      
    • comparator : 객체 간의 특정한 정렬이 필요할 때, Comparator 인터페이스를 확장해서 특정 기준을 정의

      int compare(T o1, T o2)
      

리뷰 받은 내용

  • Set 과 List 의 차이

    • 가장 큰 차이는 set은 중복된 수를 허용하지 않는다는 점
  • 한줄이더라도 괄호를 붙여주자!

  • 생성자에서 일을 많이함

  • 상속 사용

    public class Lottos extends ArrayList<Lotto> {
      
        public LottoResults match(Lotto winningLotto) {
            LottoResults lottoResults = new LottoResults();
            this.stream()
                    .map(lotto -> new LottoResult(lotto.getCorrectCount(winningLotto.getNumbers())))
                    .forEach(lottoResults::add);
            return lottoResults;
        }
    }
    

후기

로또를 구현하면서 최대한 객체가 무슨일을 하는지 이해하려고 노력했다. test를 먼저 작성하려다보니 어려워 객체를 먼저 그림을 그려보고 무슨일을 하는지 정의해보았다. 마침 구현해보고 수업시간에 디자인패턴에 대해 언급을 해주었다. 자세히 배우지는 못하였지만 디자인 패턴에 대하여 호기심이 생겼다. 처음 부터 디자인 패턴을 알고 접근 하였으면 좀 더 체계적으로 구현을 할 수 있었을 거라 생각했다.

무엇보다 학교과제 프로젝트가 복합적으로 겹쳐서 힘들었고 집중하지 못한 점이 아쉽다.

소스 코드

https://github.com/jbj616/spring-study-lotto/tree/step2/src/main/java

2019-05-09 [java-study] 문자열 덧셈 계산기 스터디

|

문자열 덧셈 계산기

요구사항

  • 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환 (예: “” => 0, “1,2” => 3, “1,2,3” => 6, “1,2:3” => 6)

  • 앞의 기본 구분자(쉼표, 콜론)외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 “//”와 “\n” 사이에 위치하는 문자를 커스텀 구분자로 사용한다. 예를 들어 “//;\n1;2;3”과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.

  • 문자열 계산기에 숫자 이외의 값 또는 음수를 전달하는 경우 RuntimeException 예외를 throw한다

프로그래밍 요구사항

  • indent(들여쓰기) depth를 2단계에서 1단계로 줄여라.
    • depth의 경우 if문을 사용하는 경우 1단계의 depth가 증가한다. if문 안에 while문을 사용한다면 depth가 2단계가 된다.
  • 메소드의 크기가 최대 10라인을 넘지 않도록 구현한다.
    • method가 한 가지 일만 하도록 최대한 작게 만들어라.
  • else를 사용하지 마라.

요구사항 힌트

  • 빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다.(예 : “” => 0, null => 0)

  • 숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.(예 : “1”)

  • 숫자 두개를 컴마(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.(예 : “1,2”)

  • 구분자를 컴마(,) 이외에 콜론(:)을 사용할 수 있다. (예 : “1,2:3” => 6)

  • “//”와 “\n” 문자 사이에 커스텀 구분자를 지정할 수 있다. (예 : “//;\n1;2;3” => 6)

  • 음수를 전달할 경우 RuntimeException 예외가 발생해야 한다. (예 : “-1,2,3”)

목표

  • 리팩토링 시간을 줄이자! (정해진 시간안에 구현)
  • Test -> 구현 순서
  • stream or 람다식 사용

공부한 내용

Pattern, Matcher 클래스

Pattern p = Pattern.compile('정규식');
Matcher matcher = p.matcher("문자열");
  • find()
    • Pattern에 일치하는 텍스트가 발견 되면 true
  • group()
    • 패턴과 일치하는 텍스트를 반환

정규식

표현식 설명
^ 문자열의 시작
$ 문자열의 종료
. 임의의 한 문자 (줄바꿈 제외)
[…] [] 사이에 있는 문자 혹은 문자집합 (ex A-Z)
[^…] [] 사이에 있는 문자 혹은 문자집합 제외
* 앞문자가 문자열일 많을수도 없을수도
+ 앞 문자가 하나 이상
? 앞 문자가 없거나 하나
{} 횟수 또는 범위
\d [0-9]

더 많은 표현 : https://jamesdreaming.tistory.com/179

자주 사용하는 거

  1. 숫자만 : ^[0-9]*$

  2. 영문자만 : ^[a-zA-Z]*$

  3. 한글만 : ^[가-힣]*$

  4. 영어 & 숫자만 : ^[a-zA-Z0-9]*$

  5. E-Mail : ^[a-zA-Z0-9]+@[a-zA-Z0-9]+$

  6. 휴대폰 : ^01(?:0|1|[6-9]) - (?:\d{3}|\d{4}) - \d{4}$

  7. 일반전화 : ^\d{2.3} - \d{3,4} - \d{4}$

  8. 주민등록번호 : \d{6} \- [1-4]\d{6}

  9. IP 주소 : ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3})

"//;\n1;2;3"

Matcher matcher = Pattern.compile("//(.)\n(.*)").matcher(string);

=> //\n 사이의 문자가 식의 구분자

matcher.group(2), matcher.group(1) //group(2)는 1;2;3 group(1)은 ;

Stream

  • mapToInt() : 객체 스트림을 기본 타입 스트림으로 변환 (Stream -> IntStream)

  • allMatch() : 모든 파라미터가 조건에 중촉되는지

String[] str = {"1", "2", "3"};
Arrays.stream(str).mapToInt(num -> Integer.parseInt(num)).allMatch(num -> num > 0);

assertThat

=> 가독성 UP

  • isEqualTo = 동등

assertThat(stringAddCalculator.calculate(null)).isEqualTo(0);

  • contains

  • startWith

  • 더 많은 정보 : https://joel-costigliola.github.io/assertj/

##리뷰 받은 내용

  • 변수를 줄여쓰지 않는다.

StringAddCalculator cal;

  • assertThat() 사용하기 (참고 https://joel-costigliola.github.io/assertj/ )

  • java Stream stream = Arrays.stream(str); stream.mapToInt(num -> Integer.parseInt(num)).allMatch(num -> num > 0);

    stream을 선언하지 않고 한줄에 끝낼수있다.

  • 무조건 stream을 사용하지말고 장점이 있는 경우에만 사용 => 이번엔 stream을 사용해 보고싶었음 다음부턴 효율적으로 적용

  • Test 작성 -> Test Fail -> Test 통과할만큼의 간단한 구현 -> 중복제거 리팩토링 -> 다른 요구사항 test 작성 -> … 무한반복

  • Scanner 생성 비용이 높아 메소드에서 생성하는 것보단 매개변수로 받는게 좋음 => threadSafe문제

  • 변수명에 자료형 이름이 오지 않는다.

힘든점

  • 정규식 표현을 읽기 힘들었다.
    • 정규식 사용 이유 : 코딩 시간절약, 특정 문자나 문자열 검색등등
    • 단점 : 가독성 떨어짐.
  • 저번보다 리팩토링 시간을 줄였음.
  • test 작성 -> 구현 -> 리팩토링 순서
  • 추가 요구 사항 (선택)
    • 1번 (positive 객체 사용) => stream 사용할 아이디어가 생각이안남
    • 2번 (Inteface를 사용하여 Splitter 구현) => interface 사용시 오버라이딩 때문에 static 메소드 사용할 수 없어서 더 복잡해졌음.
    • 3번 (람다식 사용) => 이번 과제는 람다식 (Stream) 중심으로 구현

소스 코드 : https://github.com/sproutt/spring-study-lotto/pull/11/files

2019-04-04 [java-study] java8 람다식

|

자바 람다식

람다식이란?

: 함수를 변수처럼 사용

  • 함수가 필요한 이유

    이급시민(구조체가 값의 구조를 자유롭게 전달 할 수 없음) -> 일급시민

장점

  • 불필요한 코드를 줄여줌

  • 가독성을 높여줌

    => 부정적인 입장도 있음.

  • 병렬 프로그래밍

  • 메소드로 행동방식을 전달

  • 성능

    => 부정적인 입장도 있음.

가독성 및 성능에 대한 부정적 입장 + 주의사항 - https://okky.kr/article/329818

단점

  • 람다식의 호출을 위해 직접 메소드를 불러야 함

  • 재귀 람다식 호출이 까다로움

  • 클로저가 지원되지 않음

    • 클로저 : 자신을 둘러싼 context 내의 변수에 접근함. 즉, 외부 범위의 변수를 함수 내부로 바인딩하는 기술

      • 자신을 둘러싼 외부 함수가 종료되더라도 이 값이 유지
        private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
          //a = 10 값 변경 X
          return stream.map(t -> t * a + b);
        }
      

      => calculate 메소드에서 map메소드 호출

      => a,b는 final로 간주

  • 함수 외부의 값을 변경함

메소드

int min(int x, inty){
  return x < y ? x : y;
}

=> 람다 표현식

(x,y) -> x < y ? x : y;
  • 클래스를 작성하고 객체를 생성하지 않아도 메소드를 사용할 수 있음.

  • 익명 클래스와 같음

    • 익명 클래스 : 클래스의 선언과 동시에 객체를 생성하기 때문에 하나의 객체만을 생성할 수 있는 클래스
    new Object(){
      int min(int x, int y){
        return x < y ? x : y;
      }
    }
    

기본 문법

(매개변수목록) -> {함수 몸체}

  • 매개변수의 타임을 추론할 수 있을 경우 타입 생략가능

    (x, y) -> {return x + y}; // (int x, int y) -> {return x + y;}
    
  • 매개변수가 하나인 경우 ()를 생각할 수 있음.

    a -> a*4

  • 함수의 몸체가 하나의 명령문만으로 이루어졌을 때 중괄호 {}를 생략 할 수 있음. ( 세미콜론 ; 은 붙이지 않는다 )

    (String name, int i) -> System.out.println(name + "="+i)
    
  • 함수의 몸체가 하나의 return 문으로 이루어진 경우 중괄호 {} 생략 불가

    (int a, int b) -> {
      return a > b ? a : b;
    }
    
  • return 문 대신 표현식을 사용할 수 있으며, 이때 반환값은 표현식의 결괏값이 됨. ( 세미콜론(;)은 붙이지 않는다 )

  • (int a, int b) -> a > b ? a: b
    
  • 인자가 없으면 빈 괄호로 표시

    () -> System.out.println("hihi");
    

예제

스레드 생성과 람다 표현식 비교

  • 기존 스레드 생성

    new Thread(new Runnable(){
      public void run(){
        System.out.println("스레드 생성");
      }
    }).start();
    
  • 람다식

    new Thread(()->{
      System.out.println("람다식으로 스레드 생성");
    }).start();
    

함수형 인터페이스

@FunctionalInterface
interface Calc{
  public int min(int x, int y);
}

public calss Lambda{
  public static void main(String[] args){
    Calc minNum = (x, y) -> x < y ? x : y; //추상 메소드 구현
    System.out.println(minNum.min(3,4));
  }
}

메소드 참조

: 람다 표현식이 단 하나의 메소드만을 호출할 때 해당 람다 표현식에서 불필요한 매개변수를 제거하고 사용

문법

클래스이름::메소드이름
또는
참조변수이름::메소드이름
DoubleUnaryOperator oper; //인터페이스

oper = (n) -> Math.abs(n); //람다
System.out.println(oper.applyAsDouble(-5));

oper = Math::abs; //메소드 참조
System.out.println(oper.applyAsDouble(-5))

참고자료

https://coding-factory.tistory.com/

https://m.blog.naver.com/2feelus/220695347170

http://tcpschool.com/java/java_lambda_concept

https://ryan-han.com/post/java/java-lambda/

https://futurecreator.github.io

https://github.com/11STNEWBIE/java-8-study/blob/master/Java8Action/chapter1/1장.md#자바-8에-추가된-새로운-개념

2019-04-30 [java-study] java8 스트림

|

스트림 API

스트림이란?

: 데이터를 추상화하여 다루어 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 방법

  • List, 배열의 iterator나 반복문 사용의 코드 길이가 매우 길고 재사용 힘듦 => 해결책

특징

  1. 외부 반복을 통해 작업하는 컬렉션과는 달리 내부 반복을 통해 작업을 수행함
    • 내부 반복이라는 것은 반복문을 메서드의 내부에 숨길 수 있다는 것을 의미
  2. 재사용이 가능한 컬렉션과는 달리 단 한 번만 사용할 수 있음.

  3. 원본 데이터를 변경하지 않음.

  4. 스트림의 연산은 필터-맵 기반의 API를 사용하여 지연연산을 통해 성능을 최적화함.

  5. parallelStream() 메소드를 통한 손쉬운 병렬 처리를 지원함.

    • 여러쓰레드가 처리해주니 병렬스트림이 항상 성능면에서 유리해보일 수 있지만 애플리케이션에서 사용하는 쓰레드가 많거나 스트림의 요소 수가 많지 않다면 오히려 쓰레드를 사용하는데 드는 오버헤드가 더 클 수도 있다

부정적인 입장 : https://homoefficio.github.io/2016/06/26/for-loop-%EB%A5%BC-Stream-forEach-%EB%A1%9C-%EB%B0%94%EA%BE%B8%EC%A7%80-%EB%A7%90%EC%95%84%EC%95%BC-%ED%95%A0-3%EA%B0%80%EC%A7%80-%EC%9D%B4%EC%9C%A0/

동작 흐름

데이터 소스 => 중개연산(필터) - 스트림의 변환 => 중개 연산(맵) - 스트림의 사용=> 최종 연산


스트림 생성

  1. 컬렉션
ArrayList<Integer> list = new ArrayList<>();
list.add(4);
list.add(3);
list.add(2);
list.add(1);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println); 

forEach() => 스트림의 요소를 하나씩 소모하면서 순차적 접근 (원본 데이터는 그대로 유지)

  1. 배열
String[] arr = new String[]{"하나", "둘", "셋", "넷"};
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(e->System.out.print(e+" ")); //하나 둘 셋 넷

Stream<String> stream2 = Arrays.stream(arr, 1, 3); //subString
stream2.forEach(e -> System.out.print(e+" ")); //둘 셋

-> 컬렉션과 차이 배열의 특정 부분만 이용할 수 있음.

Int, long 타입이 있는 Stream은 Stream 앞에 타입을 적어준다 ex) IntStream, LongStream…

  1. 가변 매개변수
Stream<Double> stream = Stream.of(4.2, 2.5, 3.1, 1.9);
stream.forEach(System.out::println);

of() 메소드를 사용하여 가변 매개변수를 전달받아 스트림 생성 가능

  1. 지정된 범위의 연속된 정수

range(), rangeClosed()

  • range() : 시작 정수를 포함하지만, 명시된 마지막 정수는 포함하지 않는 스트림
  • rangeClosed() : 작 정수뿐만 아니라 명시된 마지막 정수까지도 포함하는 스트림을 생성
IntStream stream1 = IntStream.range(1, 4);
stream1.forEach(e -> System.out.print(e + " ")); //1부터 4이전까지 1 2 3

IntStream stream2 = IntStream.rangeClosed(1, 4);
stream2.forEach(e -> System.out.print(e + " ")); //1부터 4까지 1 2 3 4
  1. 람다 표현식
  • iterate() : 시드로 명시된 값을 람다 표현식에 사용하여 반환된 값을 다시 시드로 사용하는 방식으로 무한 스트림을 생성
    • 이해하기 어렵 -> 예제
IntStream stream = Stream.iterate(2, n -> n+2);//2,4,6,...
Stream.iterate(0, n -> n + 1)
                .limit(10) //조건
                .forEach(x -> System.out.println(x)); //0,1,2,...,9
  • generate()
Stream<String> stream = Stream.generate(() -> "Echo").limit(5);
stream.forEach(System.out::println); //echo 5번 
  1. 빈 스트림
Stream<Object> stream = Stream.empty();
System.out.println(stream.count()); // 스트림의 요소의 총 개수를 출력함.

-> 말그대로 빈 스트림


스트림의 중개 연산

  1. 스트림 필터링
  • distinct() : 스트림에서 중복 요소 제거 (equal() 기준)
  • filter() : 말 그대로 필터링
IntStream stream1 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
IntStream stream2 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
// 스트림에서 중복된 요소를 제거함.
stream1.distinct().forEach(e -> System.out.print(e + " "));
stream2.filter(n -> n % 2 != 0).forEach(e -> System.out.print(e + " "));
//홀수만
  1. 스트림 변환
  • map() : 반환값들로 이루워진 스트림
Stream<String> stream =Stream.of("Hello", "HI", "Bye", "good");
stream.map(s->s.length()).forEach(system.out::println);
  • flatMap() : 스트림들을 하나의 스트림으로 합쳐서 하나의 새로운 스트림
String[] arr = {"I study hard", "You study JAVA", "I am hungry"};
        
        Stream<String> stream = Arrays.stream(arr);
        stream.flatMap(s -> Stream.of(s.split(" "))).forEach(System.out::println); 

=> 단어별 출력

  1. 스트림 제한
  • skip() : 해당 변수를 첫번째 요소로 지정함.
  • limit(개수) : 개수만큼 출력
IntStream stream1 = IntStream.range(0,10);
IntStream stream2 = IntStream.range(0,10);
IntStream stream3 = IntStream.range(0,10);

stream1.skip(4).forEach(n -> System.out.print(n + " "));//4 5 6 7 8 9 
stream2.limit(5).forEach(n -> System.out.print(n + " "));//0 1 2 3 4
stream3.skip(3).limit(5).forEach(n -> System.out.print(n + " "));// 3 4 5 6 7
  1. 스트림 정렬

정렬은 배열과 동일 sorted();

  • 역 정렬시

    stream.sorted(Camparator.reverseOrder())
    
  1. 스트림 연산 결과 확인

peek()

  • foreach 는 스트림을 소비해서 다음 연산이 불가능하고 peek 는 스트림을 소비하지 않아서 다음 연산이 가능함
Stream.of("one", "two", "three", "four")
                .filter(e -> e.length() > 3)
                .peek(e -> System.out.println("Filtered value: " + e))
                .map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped value: " + e))
                .collect(Collectors.toList());

Filtered value: three Mapped value: THREE Filtered value: four Mapped value: FOUR


스트림 최종 연산

  1. 요소의 출력 : forEach()

  2. 요소의 소모 : reduce()

List<Integer> ages = new ArrayList<Integer>();
ages.add(1);ages.add(2);ages.add(3);//1,2,3
System.out.println(ages.stream().reduce((b,c) -> b+c).get());//1+2+3=6
  1. 요소의 검색 : findFirst(), findAny()

  2. 요소의 검사 : anyMatch(), allMatch(), noneMatch()

    • anyMatch() : 해당 스트림의 일부 요소가 특정 조건을 만족할 경우에 true를 반환함.

    • allMatch() : 해당 스트림의 모든 요소가 특정 조건을 만족할 경우에 true를 반환함.

    • noneMatch() : 해당 스트림의 모든 요소가 특정 조건을 만족하지 않을 경우에 true를 반환함.

  3. 요소의 통계 : count(), min(), max()

IntStream stream = IntStream.of(30,90,70,10);
System.out.pritnln(stream.count());
  1. 요소의 연산 : sum(), average()

  2. 요소의 수집 : collect()

    자세한 내용 : http://tcpschool.com/java/java_stream_terminal


참고자료

예제

https://www.baeldung.com/java-streams-peek-api

https://jeong-pro.tistory.com/165

개념 http://tcpschool.com/

추가설명

http://iloveulhj.github.io/posts/java/java-stream-api.html