1. Spring Framework란?



Java 엔터프라이즈 개발을 편하게 해주는 ①오픈소스 ②경량급 ③애플리케이션 프레임워크이다.


① 오픈소스 : Spring은 OpenSource의 장점을 충분히 취하면서 동시에 OpenSource제품의 단점과 한계를 잘 극복했다.


① 엔터프라이즈 개발 용이 : 개발자가 복잡하고 실수하기 쉬운 Low Level에 많이 신경 쓰지 않으면서 Business Logic

개발에 전념할 수 있도록 해준다.


② 경량급 프레임워크 : 단순한 웹컨테이너에서도 엔터프라이즈 개발의 고급기술을 대부분 사용할 수 있다.


③ 애플리케이션 프레임워크 : 특정 계층이나 기술, 업무 분야에 국한되지 않고 애플리케이션의

전 영역을 포괄하는 범용적인 프레임워크를 말한다.




2. Spring Framework 전략





엔터프라이즈 개발의 복잡함을 상대하는 Spring의 전략

-> ①Portable Service Abstraction, ②DI, ③AOP, ④POJO 가 있다.



① Portable Service Abstraction(서비스 추상화)


트랜젝션 추상화, OXM 추상화, 데이터 액세스의 Exception 변환기능 등 

기술적인 복잡함은 추상화를 통해 Low Level의 기술구현부분과 기술을 사용하는

인터페이스로 분리한다.



② 객체 지향과 DI(Dependency Injection)


Spring은 객체지향에 충실한 설계가 가능하도록 단순한 객체형태로 개발할 수 있고,

DI는 유연하게 확장 가능한 객체를 만들어 두고 그 관계는 외부에서 다이내믹하게 설정해준다.



③ AOP(Aspect Oriented Programming)


AOP는 애플리케이션 로직을 담당하는 코드에 남아있는 기술 관련 코드를 분리해서

별도의 모듈로 관리하게 해주는 강력한 기술이다.



④ POJO(Plain Old Java Object)


POJO는 객체지향 원리에 충실하면서, 특정 환경이나 규약에 종속되지 않고 필요에 따라 재활용될수 있는

방식으로 설계된 객체이다.




3. Spring Freamwork 특징



1. 컨테이너 역할

Spring 컨테이너는 Java 객체의 LifeCycle을 관리하며, Spring 컨테이너로부터 필요한 객체를 가져와

사용할 수 있다.


2. DI(Dependency Injection) 지원

Spring은 설정파일이나 어노테이션을 통해서 객체 간의 의존관계를 설정할 수 있도록 하고 있다.


3. AOP(Aspect Oriented Programming) 지원

Spring은 트랜젝션이나 로깅, 보안과 같이 공통적으로 필요로 하는 모듈들을 실제 핵심 모듈에서 분리해서

적용 할 수 있다.


4. POJO(Plain Old Java Object) 지원

Spring 컨테이너에 저장되는 Java객체는 특정한 인터페이스를 구현하거나, 특정클래스를 상속받지 않아도 된다.


5. 트랜젝션 처리를 위한 일관된 방법을 지원

JDBC, JTA 등 어떤 트랜젝션을 사용하던 설정을 통해 정보를 관리하므로 트랜젝션 구현에 상관없이 동일한 코드 사용가능


6. 영속성과 관련된 다양한 API 지원

Spring은 Mybatis, Hibernate 등 데이터베이스 처리를 위한 ORM(Object Relational Mapping)

프레임워크들과의 연동 지원



4. SpringFramework의 기능요소





Core 컨테이너


Core 컨테이너는 Spring프레임워크의 기본기능을 제공한다. 이 모듈에 있는 BeanFactory는 Spring의

기본 컨테이너이면서 스프링 DI의 기반이다.



Context


Context모듈은 BeanFactory의 개념을 확장한 것으로 국제화(I18N) 메시지, 애플리케이션 생명주기 이벤트, 

유효성 검증을 지원한다.



DAO


DAO 패키지는 JDBC에 대한 추상화 계층으로 JDBC 코딩이나 예외처리 하는 부분을 간편화 시켰으며, AOP 모듈을

이용해 트랜젝션 관리 서비스도 제공한다.



ORM


Mybatis, Hibernate, JPA 등 널리 사용되는 ORM 프레임워크과의 연결고리를 제공한다.

ORM 제품들을 Spring의 기능과 조합해서 사용할 수 있도록 해준다.



AOP


AOP 모듈을 통해 Aspect 지향 프로그래밍을 지원한다.

AOP 모듈은 스프링 애플리케이션에서 Aspect를 개발할 수 있는 기반을 지원한다.



Web


일반적인 웹 애플리케이션 개발에 필요한 기본기능을 제공하고, Webwork나 Struts와 같은

다른 웹어플리케이션 프레임워크와의 통합을 지원한다.



WebMVC


MVC(Model/View/Controller) 패러다임은 사용자 인터페이스가 애플리케이션 로직과

분리되는 웹 애플리케이션을 만드는 경우에 일반적으로 사용되는 패러다임이다. 이 패러다임을 바탕으로

웹 계층에서 결합도를 낮추는 Spring MVC 프레임워크가 있다.




1. Spring 프레임워크의 "프레임 워크"란 무엇인가?



프레임워크는 

비기능적 요구사항을 만족하는 구조와 구현된 기능을 안정적으로 실행하도록 제어 해주는 

잘 만들어진 구조의 라이브러리 덩어리이다.


프레임워크는 애플리케이션들의 최소한의 공통점을 찾아 하부 구조를 제공함으로써 개발자로

하여금 시스템의 하부구조를 구현하는데 들어가는 노력을 절감해준다.




2. 프레임워크를 왜 사용할까?



비기능적인 요소들을 초기 개발 단계마다 구현해야 하는 불합리함을 극복해준다.

기능적인 요구사항에 집중 할 수 있도록 해준다.

디자인 패턴과 마찬가지로 반복적으로 발견되는 문제를 해결하기 위한 특화된 solution을 제공한다.




3. 프레임워크는 디자인패턴과 관련이 있나?



프레임워크의 핵심적인 특징이 디자인 패턴이다. 

하지만 프레임워크는 디자인 패턴이 아니다.


디자인패턴은 애플리케이션을 설계할 때 필요한 구조적인 가이드라인이 되어 줄수는 있지만 구체적으로

구현된 기반코드를 제공하지 않는다.


프레임워크는 디자인 패턴과 함께 패턴이 적용된 기반 클래스 라이브러리를 제공해서 

프레임워크를 사용하는 구조적인 틀과 구현코드를 함께 제공한다.




4. 프레임워크의 구성요소와 종류



IoC(Inversion of Control)


IoC란 "제어의 역전" 즉 인스턴스 생성부터 소멸까지의 인스턴스 생명주기 관리를 

개발자가 아닌 컨테이너가 대신 해준다는 뜻이다.

즉 컨테이너 역할을 해주는 프레임워크에게 제어하는 권한을 넘겨서 개발자의 코드가

신경써야 할 것을 줄이는 전략이다.



프레임워크의 동작원리를 제어흐름이 일반적인 프로그램 흐름과 반대로 동작하므로 IoC라고 한다.


Spring 컨테이너는 IoC를 지원하며, 메타데이터(XML설정)을 통해 beans를 관리하고

어플리케이션의 중요부분을 형성한다.


Spring 컨테이너는 관리되는 bean들을 의존성주입(Dependency Injection)을 통해

IoC를 지원한다.




5. 프레임워크와 라이브러리의 차이점


프레임워크는 특정부분의 기술적인 구현을 라이브러리 형태로 제공한다.

Class Library라는 구성요소는 프레임워크의 정의 중 하나인 Semi Complete(반제품)이다.



 특징

 프레임워크

 라이브러리

 유저코드의 작성

 프레임워크 클래스를 서브클래싱해서 작성

 독립적으로 작성

 호출흐름

 프레임워크코드가 유저코드를 호출

 유저코드가 라이브러리를 호출

 실행흐름

 프레임워크가 제어

 유저코드가 제어

 객체의 연동

 구조프레임워크가 정의

 독자적으로 정의



- 프레임워크와 라이브러리를 구분하는 방법은 실행제어가 어디서 일어나는 가에 달려있다.

- 라이브러리는 개발자가 만든 클래스에서 직접 호출하여 사용하므로 실행의 흐름에 대한 제어를 개발자의 코드가 관장하고 있다.

- 프레임워크는 반대로 프레임워크에서 개발자가 만든 클래스를 호출하여 실행의 흐름에 대한 제어를 담당한다.


디자인 패턴 + 라이브러리 = 프레임워크


- 프레임워크는 디자인 패턴과 그것이 적용된 기반 라이브러리의 결합이다.

- 프레임워크를 확장하거나 커스터마이징 할때는 프레임워크에 적용된 패턴에 대한 이해가 필요하다.





module-info.java를 통해 

서로 다른 프로젝트 a, b에 대해 a에서 선언한 클래스를 b에서 불러와 사용할수 있다.


common.widget프로젝트에는 

com.logicbig 패키지에 RendererSupport.java라는 파일이 있고

org.jwidgets 패키지에 SimpleRenderer.java라는 파일이 있다.


common.widget 프로젝트(a)의 module-info.java에 외부에 노출하고 싶은 패키지를 exports해주고



1
2
3
module common.widget {
    exports com.logicbig;    // 외부에 노출하고싶은 패키지
}
cs




패키지를 require시 접근하여 사용할수 있다.




1
2
3
4
module data.widget {
    requires common.widget;    // 사용할 패키지
    requires java.sql;
}
cs




requires로 선언후 Java Build Path로 Module path를 잡아주면된다.






이후 프로젝트(b)에서 다른 프로젝트(a)에 있는 클래스를 호출하여 객체를 생성하거나 메소드를 활용할 수 있다.



프로젝트 a의 RendererSupport.java


1
2
3
4
5
6
7
8
9
package com.logicbig;
 
import org.jwidgets.SimpleRenderer;
 
public class RendererSupport {
  public void render(Object object) {
      new SimpleRenderer().renderAsString(object);
  }
}
cs




프로젝트 a의 SimpleRenderer.java


1
2
3
4
5
6
7
package org.jwidgets;
 
public class SimpleRenderer {
  public void renderAsString(Object object) {
      System.out.println(object);
  }
}
cs




프로젝트 b의 Component.java


1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example;
 
import com.logicbig.RendererSupport;
import java.sql.*;
 
// java.base 그 외 다른 모듈 패키지를 쓰려면 module-info에 require로 넣어줘야함.
 
public class Component {
  public static void main(String[] args) {
      RendererSupport support = new RendererSupport();
      support.render("Test Object");
  }
}
cs




프로젝트 b의 Component.java파일에서 프로젝트 a의 RenderSupport 클래스를 호출하여 객체를 생성하는 것을 확인할 수 있다.



module-info.java에 대해 공부하여 서로 다른 프로젝트 간의 exports, require에 대해 알 수 있었다.



소스코드 첨부 :


common.widget.zip

data.widget.zip




자바8의 Time 및 Date 관련 새로운 API를 공부하게 되어 정리하게 되었다. 



1. LocalDate, LocalTime, LocalDateTime, DateTimeFormatter 사용하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package dateTimeTest;
 
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Locale;
 
public class LocalDateTimeTest {
 
    public static void main(String[] args) {
 
        // 1. LocalDate 사용
        LocalDate today = LocalDate.now();
        System.out.println(today);
        
        System.out.println("년월일"+today.getYear() + "/" + today.getMonth() + " "+today.getMonthValue() 
        +"/"+today.getDayOfMonth() + " 지난일자 " + today.getDayOfYear());
        System.out.println("요일 " + today.getDayOfWeek()+" "+today.getDayOfWeek().getValue());
        
        // 특정 날짜를 지정해서 LocalDate 생성
        LocalDate endDay = LocalDate.of(20191231);
        System.out.println("현재 기준 몇일 남아 있는지 "+ today.until(endDay, ChronoUnit.DAYS));
        
        System.out.println("현재 기준 1개월 후 "+today.plusMonths(1));
        System.out.println(DayOfWeek.TUESDAY.plus(3));
        
        // LocalTime 사용
        LocalTime now = LocalTime.now();
        System.out.println(now);
        System.out.println("시분초나노초" + now.getHour() + " " + now.getMinute()
                                        + " " + now.getSecond() + " " +now.getNano());
        
        // 특정 시간을 지정해서 LocalTime 생성
        LocalTime bedTime = LocalTime.of(2340);
        LocalTime wakeTime = bedTime.plusHours(8);
        System.out.println(wakeTime);
        
        // LocalDateTime 사용
        LocalDateTime dt = LocalDateTime.now();
        System.out.println(dt);
 
        LocalDate date = dt.toLocalDate();
        System.out.println(date);
        
        LocalTime time = dt.toLocalTime();
        System.out.println(time);
        
        // 특정 날짜와 시간을 지정해서 LocalDateTime 생성
        LocalDateTime dt2 = LocalDateTime.of(2019,2,19,13,20,50);
        System.out.println(dt2);
        System.out.println(dt2.getMonth());
        
        dt2.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        
        // 포맷을 직접 설정한 Formatter 생성
        DateTimeFormatter myFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss E a", Locale.KOREAN);
        System.out.println(dt2.format(myFormat));    
    }
}
cs





2. LocalDateTime 응용해 현재로부터 월급날까지 남은 일수 계산하기



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package dateTimeTest;
 
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
 
public class SalaryDate {
    
    // 내 월급날(매월 25일)은 몇일 남았을까?
    public static void main(String[] args) {
         LocalDate today = LocalDate.now();
//        LocalDate today = LocalDate.of(2019, 2, 26);
        
        // 1. 기준이 되는 날짜를 구하기
        LocalDate theDay = LocalDate.from(today);
        System.out.println("오늘날짜 : "+theDay);
        
        // 2. 월급날 구하기 매월 25일 
        int salaryDay = 25;
        int remainDay = 0;
 
        if(theDay.getDayOfMonth() > salaryDay) {
            LocalDate lastDayOfMonth = theDay
                    .with(TemporalAdjusters.lastDayOfMonth());
            remainDay = lastDayOfMonth.getDayOfMonth()-theDay.getDayOfMonth()+salaryDay;
        }else if(theDay.getDayOfMonth() < salaryDay) {
            remainDay = salaryDay-theDay.getDayOfMonth();
        }else {
            remainDay = 0;
        }
        
        System.out.println("월급까지 "+remainDay+"일 남았습니다.");
    }
}
 
cs


1
2
오늘날짜 : 2019-02-20
월급까지 5일 남았습니다.
cs



소스코드 첨부: 


myLamdaTest.zip





1. 스트림이란?


스트림은 자바8부터 추가된 컬렉션의 저장요소를 하나씩 참조해서 람다식으로 처리할수 있도록 해주는 반복자이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package streamTest;
 
import java.util.Arrays;
import java.util.List;
 
public class myStreamTest {
 
    public static void main(String[] args) {
        int count1 = 0;
         List<String> names = Arrays.asList("1""2""3""4""5");
         
         // 기존의 for문
        for (String w : names) {
            if(w.length() > 0) {
                count1++;
            }
        }
        
        // stream 방식
        long count2 = 
                names.stream()
                         .filter(a->a.length()>0)
                         .count();
        
        // 병렬 stream 방식
        long count3 = 
                names.parallelStream()
                         .filter(a->a.length()>0)
                         .count();
        
        System.out.println(count1);
        System.out.println(count2);
        System.out.println(count3);
    }
}
cs


count1, count2, count3의 결과는 같다. 

기존for문,스트림, 병렬스트림 을 사용해서 표현한 것을 확인할 수 있다.



2. 스트림의 특징


- 스트림을 활용하면 복잡한 코드를 간결하게 표현할 수 있다.

- 스트림은 컬렉션, 배열, 파일 등의 대량의 데이터를 가공 축소하여 데이터의 합계, 

평균값, 카운팅, 최대값, 최소값, 집계함수를 모두 표현할 수 있다.


- 오리지날 스트림에서 중간처리(필터, 매핑)를 하고 최종처리(집계 처리 결과물)를 하여 결과를 볼수 있다.

- 스트림은 iterator와 비슷한 역할을 하는 반복자이다.


- 스트림이 제공하는 요소처리 메서드는 함수적 인터페이스 타입이므로 람다식, 

메서드 참조를 이용하여 요소처리 내용을 인자로 전달할 수 있다.



3. 컬렉션과 스트림의 공통점과 차이점



공통점


- 연속된 요소형식의 값을 저장하는 자료구조 인터페이스를 제공한다.

- 둘다 순차적으로 요소에 접근한다.


차이점


컬렉션은


- 각 계산식을 만날 때마다 데이터가 계산된다. 

- 데이터의 접근, 읽기, 변경, 저장이 주요 관심사이다.

- 데이터에 접근하는 방법을 직접 작성해야한다.

- Iterator로 모든요소를 순환해야한다.

- 메모리에 모든 요소가 올라가 있는 상태에서 요소들을 누적시키며 결과를 계산한다.

- 메모리 사용량이 늘어난다.


스트림은


- 최종 연산이 실행 될 때에 데이터가 계산된다. 

- 계산식(람다)을 표현하는 것이 주요 관심사이다.

- 데이터에 접근하는 방법이 추상화되어있다.

- 계산식을 미리 적어두고 계산시에 람다식으로 JVM에 넘긴다.

- 내부에서 요소들을 어떻게 메모리에 올리는 지는 관심사가 아니다.

- 메모리 사용량이 줄어든다.



스트림을 활용해 코드를 개선해보자.





4. 스트림 생성방법 예제



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package streamTest;
 
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.function.IntSupplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
 
public class MakingStreams {
 
    public static void main(String...args) throws Exception{
        
        // Stream.of
        Stream<String> stream = Stream.of("Java8""Lambdas""SangHyun");
        stream.map(String::toUpperCase).forEach(System.out::println);
        // result : UpperCase
        
        // Arrays.stream
        int[] numbers = {12345};
        System.out.println(Arrays.stream(numbers).sum());
        // result : 15
        
        // Stream.iterate
        Stream.iterate(0, n -> n + 2)
              .limit(5)
              .forEach(System.out::println);
        // result : 0 2 4 6 8
        
        // random stream of doubles with Stream.generate
        Stream.generate(Math::random)
              .limit(10)
              .forEach(System.out::println);
        // result : random data
        
        // stream of 1s with Stream.generate
        IntStream.generate(() -> 1)
                 .limit(5)
                 .forEach(System.out::println);
        // result : 1 1 1 1 1 
        
        IntStream.generate(new IntSupplier(){
            public int getAsInt(){
                return 2;
            }
        }).limit(5)
          .forEach(System.out::println);
        // result : 2 2 2 2 2
 
        // 피보나치 수열
        IntSupplier fib = new IntSupplier(){
                  private int previous = 0;
                  private int current = 1;
                  public int getAsInt(){
                      int nextValue = this.previous + this.current;
                      this.previous = this.current;
                      this.current = nextValue;
                      return this.previous;
                  }
              };
         IntStream.generate(fib).limit(10).forEach(System.out::println);
         // result : 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
         
         // 유니크 단어 카운트
         long uniqueWords = Files.lines(Paths.get("data2.txt"), Charset.defaultCharset())
                                 .flatMap(line -> Arrays.stream(line.split(" ")))
                                 .distinct()
                                 .count();
 
         System.out.println("There are " + uniqueWords + " unique words in data2.txt");
    }
}
cs




5. 스트림 활용하여 문제 풀기



5.1 Developer 모델



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package streamTest;
 
public  class Developer{
    
    private String name;
    private String title;
 
    public Developer(String n, String c){
        this.name = n;
        this.title = c;
    }
 
    public String getName(){
        return this.name;
    }
 
    public String getTitle(){
        return this.title;
    }
 
    public void setTitle(String newTitle){
        this.title = newTitle;
    }
 
    public String toString(){
        return "Developer:"+this.name + " , " + this.title;
    }
}
cs




5.2 BiddingCompany 모델



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package streamTest;
 
public class BiddingCompany{
 
    private Developer developer;
    private String companyName;
    private int year;
    private int salary;
 
    public BiddingCompany(Developer developer, String companyName, int year, int salary)
    {
        this.developer = developer;
        this.companyName = companyName;
        this.year = year;
        this.salary = salary;
    }
 
    public Developer getDeveloper(){ 
        return this.developer;
    }
    
    public String getCompanyName() {
        return companyName;
    }
 
    public int getYear(){
        return this.year;
    }
 
    public int getSalary(){
        return this.salary;
    }
    
    public String toString(){
        return "{" + this.developer + ", " +
               "companyName: "+this.companyName+", " +
               "year: "+this.year+", " +
               "salary:" + this.salary +"}";
    }
}
cs



5.3 StreamTestCode Main 코드



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package streamTest;
 
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
 
public class StreamTestCode {
    public static void main(String ...args){    
        // 개발자의 성명과 직급
        Developer sanghyun = new Developer("SangHyun""대리");
        Developer hyunYoung = new Developer("HyunYoung","사원");
        Developer jiSook = new Developer("JiSook","주임");
        Developer choa = new Developer("Choa","대리");
        
        // 입찰회사에서 개발자 채용을 위해 연봉제시 
        // 입찰한 개발자 이름, 참여한 회사이름, 설립연도 , 제시한연봉 
        List<BiddingCompany> company = Arrays.asList(
            new BiddingCompany(sanghyun, "쿠팡",20104000), 
            new BiddingCompany(sanghyun, "위메프",20115000), 
            new BiddingCompany(sanghyun, "sk플래닛",20127000), 
            new BiddingCompany(hyunYoung, "위메프",20102000),  
            new BiddingCompany(hyunYoung, "sk플래닛",20123000), 
            new BiddingCompany(jiSook, "쿠팡",20103500),
            new BiddingCompany(choa, "위메프",20113800
        );    
        
        // 쿼리 1 : 설립일이 2012년인 입찰회사를 모두 찾아서 연봉이 작은값부터 큰값으로 출력해라
        // 2012년이라는 특정한 조건이 있으므로 filter사용, 작은값부터 큰값 정렬 sorted 사용
        
        List<BiddingCompany> t1 = 
                company.stream()
                             .filter(a->a.getYear()==2012)
                             .sorted(Comparator.comparing(b->b.getSalary()))
                             .collect(Collectors.toList());
        
        t1.forEach(System.out::println);
        /* result : {Developer:HyunYoung , 사원, companyName: sk플래닛, year: 2012, salary:3000}
                        {Developer:SangHyun , 대리, companyName: sk플래닛, year: 2012, salary:7000} */
        
        // 쿼리 2 : 입찰회사 개발자 목록에서 개발자의 중복되지 않는 직급만 출력해라.
        // 특정한 조건이 딱 주어지지 않았으므로 map사용, 중복제거 distinct사용
        
        List<String>  t2_1 =     
                company.stream()
                             .map(BiddingCompany::getDeveloper)
                             .map(Developer::getTitle)
                             .distinct()
                             .collect(Collectors.toList());
 
        System.out.println("map 2번 사용");
        t2_1.forEach(System.out::println);
        /* result : 대리 사원 주임 */
        
        List<String>  t2_2 =         
                company.stream()
                             .map(tx -> tx.getDeveloper().getTitle()) 
                             .distinct()
                             .collect(Collectors.toList());
        
        System.out.println("map 1번 사용");
        t2_2.forEach(System.out::println);
        /* result : 대리 사원 주임 */
        
        // 쿼리 3: 개발자 중에서 대리직급을 찾아 이름순으로 정렬해라.
        
        company.stream()
                     .map(a->a.getDeveloper())
                     .filter(b->b.getTitle().equals("대리"))
                     .distinct()
                     .sorted(Comparator.comparing(c->c.getName()))
                     .forEach(System.out::println);
        /* result : Developer:Choa , 대리 
                        Developer:SangHyun , 대리 */
        
        // 쿼리 4: 알파벳 순서대로 정렬하여 개발자 이름만 출력해라
        
        String names = 
                company.stream()
                             .map(a->a.getDeveloper().getName())
                             .distinct()
                             .sorted()
                             .reduce("", (a1,a2) -> a1+a2+" ");
        
        System.out.println(names);
        /* result : Choa HyunYoung JiSook SangHyun */
        
        // 쿼리 5 : 사원 직급의 개발자가 있는가?
        
        boolean 사원 = 
                company.stream()
                             .anyMatch(tx -> tx.getDeveloper().getTitle().equals("사원"));
                                    
        System.out.println(사원);
        /* result : true */
        
        // 쿼리 6 : 대리직급의 개발자를 과장직급으로 업데이트 해라
        
        System.out.println("업데이트 전: "+company);
        company.stream()
                     .map(a->a.getDeveloper())
                     .filter(a->a.getTitle().equals("대리"))
                     .forEach(a->a.setTitle("과장"));
        System.out.println("업데이트 후: "+company);
        
        // 쿼리 7: 입찰한 모든회사 중에 가장 높은 연봉을 제시한 값은 얼마인가?
        
        int highSalary = 
                company.stream()
                             .mapToInt(a->a.getSalary())
                             .max()
                             .getAsInt();
        
        System.out.println(highSalary);
        /* result : 7000 */
    }
}
cs


소스 코드 첨부 :


myLamdaTest.zip




1. 람다식


람다는 하나의 abstract 메서드 만 가진 인터페이스를 함수형 인터페이스라고 한다.

람다식을 지원하는 java.util.functon 패키지가 추가되었다.



1.1 람다 표현과 특성


1
Runnable r = () -> System.out.println("Hello World");
cs


1
2
3
4
5
public interface Comparator<T> {
    public int compare(T o1, T o2);
}
 
Comparator<Integer> comparator = (o1, o2) -> o2 - o1;
cs


 - 이름이 없는 익명이다.

 - 메서드처럼 특정클래스에 종속되지 않는다. 

 - 람다식을 메서드의 인자로 전달하거나 변수값으로 저장할 수 있다.

 - 간결하다.

 



2. 스트림

 

자바8은 스트림과 람다를 활용하여 이전보다 간결하고 향상된 방법으로 collection을 처리한다.

 

stream은 순차(sequential), 병렬(parallel) 두 종류가 존재한다.

순차 stream은 싱글 쓰레드가 순차적으로 처리되며 병렬 stream은 fork/join 프레임워크로 구현된 

메서드에 의해 병렬로 처리된다.

 


2.1 stream의 장단점


장점은 Laziness, Collection의 interation처리를 자바에게 맡겨 둠으로써 jvm이 최적화할수 있는 기회를 제공한다.

단점은 재사용 불가하다. 한번 사용된 stream은 재사용이 불가능하여 필요에 따라 새롭게 만들어야 한다.

 


3. 함수형 인터페이스 활용하기


3.1 java.util.function 패키지의 함수형 인터페이스

 

함수형 인터페이스

 Descriptor

 Method명

 Predicate<T>

 T -> boolean

 test()

 Consumer<T>

 T -> void

 accept()

 Supplier<T>

 () -> T

 accept()

 Function<T,R>

 T -> R

 apply()

 UnaryOperator<T>

 T -> T

 identity()



위에 함수형 인터페이스를 활용해서 예제를 작성해보겠다.



3.2 predicate와 consumer 예제



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package lamdaTest;
 
public class Grape {
    private int weight = 0;
    private String color = "";
 
    public Grape(int weight, String color){
        this.weight = weight;
        this.color = color;
    }
 
    public Integer getWeight() {
        return weight;
    }
 
    public void setWeight(Integer weight) {
        this.weight = weight;
    }
 
    public String getColor() {
        return color;
    }
 
    public void setColor(String color) {
        this.color = color;
    }
 
    public String toString() {
        return "Grape{" +
               "color='" + color + '\'' +
               ", weight=" + weight +
               '}';
    }
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package lamdaTest;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
 
public class PredicateAndConsumer {
 
    public static void main(String... args) {
 
        // 청포도, 보라포도, 적포도
        List<Grape> inventory = 
                Arrays.asList(new Grape(70"green"), 
                              new Grape(90"purple"), 
                              new Grape(120"red"));
 
        // 1. Predicate 인터페이스 사용
        System.out.println("----- 1. Predicate 인터페이스 사용 -----");
        filter(inventory, grape -> grape.getWeight() >=100)
        .forEach(System.out::println);
        // result : Grape{color='red', weight=120}
        
        // 2. Consumer 인터페이스 사용
        System.out.println("----- 2. Consumer 인터페이스 사용 -----");
        printGrapeInfo(inventory, grape -> System.out.println(grape));
        // result : All List print
        
    }
 
    public static void printGrapeInfo(List<Grape> inventory, Consumer<Grape> consumer) {
        for (Grape grape : inventory) {
            consumer.accept(grape);
        }
    }
    
    public static List<Grape> filter(List<Grape> inventory, Predicate<Grape> p) {
        List<Grape> result = new ArrayList<>();
        for (Grape grape : inventory) {
            if (p.test(grape)) {
                result.add(grape);
            }
        }
        return result;
    }
}
cs



3.3 supplier 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package lamdaTest;
 
import java.util.function.Supplier;
 
class Animal {
    public void eat() {
        System.out.println("Eating something");
    }
}
 
class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("Eating fish");
    }
}
 
public class SupplierTest {
    static void eatSomething(Supplier<extends Animal> supplier) {
        Animal animal = supplier.get();
        animal.eat();
    }
 
    public static void main(String[] args) {
        // Using Lambda expression
        eatSomething(() -> new Animal());
        eatSomething(() -> new Cat());
        
        // Using Method Reference
        eatSomething(Animal::new);
        eatSomething(Cat::new);
    }
}
cs



3.4 function 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package lamdaTest;
 
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
 
public class FunctionTest {
 
    // Function 인터페이스
    public static List<String> getColorList(List<Grape> inventory, Function<Grape, String> function) {
        List<String> colorList = new ArrayList<String>();
        for (Grape grape : inventory) {
            colorList.add(function.apply(grape));
        }
        return colorList;
    }
 
    public static void main(String[] args) {
        List<Grape> grapeList = new ArrayList<>();
        grapeList.add(new Grape(150"green"));
        grapeList.add(new Grape(200"purple"));
        grapeList.add(new Grape(200"red"));
        grapeList.add(new Grape(150"red"));
 
        // 1. 익명 클래스 사용
        System.out.println("----- 1. 익명 클래스 사용 -----");
        getColorList(grapeList, new Function<Grape, String>() {
            @Override
            public String apply(Grape grape) {
                // TODO Auto-generated method stub
                return grape.getColor();
            }
        }).forEach(System.out::println);
        
 
        // 2. 람다식 사용
        System.out.println("----- 2. 람다식 사용 -----");
        getColorList(grapeList, grape -> grape.getColor()).forEach(System.out::println);
 
        // 3. 메소드 레퍼런스 사용
        System.out.println("----- 3. 메소드 레퍼런스 사용 -----");
        getColorList(grapeList, Grape::getColor).forEach(System.out::println);
 
    }
 
    public static class Grape {
        private Integer weight = 0;
        private String color = "";
 
        public Grape(Integer weight, String color) {
            this.weight = weight;
            this.color = color;
        }
 
        public Integer getWeight() {
            return weight;
        }
 
        public void setWeight(Integer weight) {
            this.weight = weight;
        }
 
        public String getColor() {
            return color;
        }
 
        public void setColor(String color) {
            this.color = color;
        }
 
        public String toString() {
            return "Grape{" + "color='" + color + '\'' + ", weight=" + weight + '}';
        }
    }
}
 
cs



3.5 operator 예제


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package lamdaTest;
 
import java.util.function.IntBinaryOperator;
 
public class OperatorTest {
    private static int[] valueList = { 102030 };
 
    // IntBinaryOperator 사용
    public static int maxOrMin(IntBinaryOperator operator) {
        int result = valueList[0];
        for (int value : valueList) {
            result = operator.applyAsInt(result, value);
        }
        return result; }
 
    public static void main(String[] args) {
        // 최대값 얻기
        int maxValue = maxOrMin((n1,n2) ->{
            if(n1>=n2) return n1;
            else return n2;
        });
        System.out.println(maxValue);
        
        // 최소값 얻기
        int minValue = maxOrMin((n1,n2) ->{
            if(n1<=n2) return n1;
            else return n2;
        });
        System.out.println(minValue);
    }
}
cs



정리


1. 람다식은 익명클래스를 간결하게 표현할수 있다.

2. 함수형 인터페이스는 추상 메서드 하나만 정의된 인터페이스이다.

3. 메서드 레퍼런스를 이용하면 기존의 메서드 구현을 재사용 가능하다.

4. Comparator, Predicate, Function 같은 함수형 인터페이스는 람다식을 조합할수 이는 다양한 디폴트 메소드를 제공한다.



소스코드 첨부 :


myLamdaTest.zip







서블릿 라이프사이클에 대해 궁금증을 갖게 되어 정리해보았다.



■  서블릿은 init () 메소드를 호출하여 초기화된다.


■  서블릿은 service () 메소드를 호출 하여 클라이언트의 요청을 처리한다.


■  서블릿은 destroy () 메소드를 호출하여 종료된다.


■  마지막으로, 서블릿은 JVM의 가비지 컬렉터에 의해 가비지 수집된다.



그림으로 표현하면 다음과 같다.




init 메소드는 처음 한번만 실행되고 그 이후에 service()가 다 처리를 하는 것이다.

service () 메소드는 HTTP 요청 유형 (GET, POST, PUT, DELETE 등)을 확인하고

적절하게 doGet, doPost, doPut, doDelete 등의 메소드를 호출한다.



그럼 정말로 이렇게 도는지 확인하기 위해 테스트 소스를 작성해보았다.




1. jsp 파일


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
    $(document).on("click""#button"function() {
        // get method 호출
        $.get("myServlet"function(content) {             
            $( "#list" ).append( "<li>"+content+"</li>" );
            myMethod();
        });
    
    myMethod = function(){
        // ajax post method 호출
        var myData = $("#button").val();
        $.ajax({
            type : "POST",
            data : myData,
            url : "myServlet",
            success : function(content) {
                $( "#list" ).append( "<li>"+content+"</li>" );
            }
        });
    }
});
</script>
</head>
<body>
    <button id="button" value="1">servlet 메소드 호출하기</button>
    <ul id="list">
    </ul>
</body>
</html>
 
cs



2. 서블릿 파일


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package myServletTest;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@WebServlet("/myServlet/*")
public class MyServlet extends HttpServlet{
    
    private static final long serialVersionUID = 1L;
    String msg = "default";
    
    // The servlet is initialized by calling the init() method.
    public void init() throws ServletException {
        msg = "init 메소드 Call";
    }
    
    
    // The servlet calls service() method to process a client's request.
    // service () 메소드는 HTTP 요청 유형 (GET, POST, PUT, DELETE 등)을 확인하고 
    // 적절하게 doGet, doPost, doPut, doDelete 등의 메소드를 호출
    @Override
    public void service(ServletRequest request, ServletResponse response) 
            throws ServletException, IOException {
        String text = "Service 메소드 Call";
        if(!"default".equals(msg)){
            text = msg +"<br>"+text;
            msg = "default";
        }
        response.setContentType("text/plain");  
        response.setCharacterEncoding("UTF-8"); 
        response.getWriter().write(text);       
    }
    
    
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String text = "doGet 메소드 Call";
        commonMethod(text, response);
    }
    
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String text = "doPost 메소드 Call";
        commonMethod(text, response);
    }
 
    // The servlet is terminated by calling the destroy() method.
    @Override
    public void destroy() {
        // Finalization code...
        System.out.println("destroy method call");
    }
    
 
    private void commonMethod(String text, HttpServletResponse response) 
            throws ServletException, IOException{
        if(!"default".equals(msg)){
            text = msg +"<br>"+text;
            msg = "default";
        }
        response.setContentType("text/plain");  
        response.setCharacterEncoding("UTF-8"); 
        response.getWriter().write(text);   
    }
}
 
cs


버튼을 누를시 get 요청 1번,  post 요청 1번이 이루어지고

response 시 공통되는 부분은 메소드로 빼서 작성했다.


이후 실행을 하면 


서블릿 java 파일에 service() 가 없을 경우 init() 한번 호출 이후 doGet(), doPost()를 호출한다.





서블릿 java 파일에 service() 가 있을 경우 init() 한번 호출 이후 service()를 호출한다.

service () 메소드가 HTTP 요청 유형 (GET, POST, PUT, DELETE 등)에 따라

적절하게 doGet, doPost, doPut, doDelete 등의 메소드를 호출하여 처리해줌을 알수 있었다.






이후 서블릿이 종료되면 destroy() 메소드가 발생하며 종료된다.



마지막으로 작성한 소스코드를 첨부한다.


myServletTest.zip






1. git저장소와 local git 연결(clone),  add,commit push 방법



1. github( https://github.com/ )으로 이동해 로그인 후 git저장소를 만들자. 



 





2. git저장소를 만들면 github에서 git저장소로 원격접속 가능한 주소를 제공한다.(https, ssh)



 





3. https://git-scm.com 에서 git을 다운받고 기본설정으로 설치한다.

원격 git저장소에  접속하려면 자신의 로컬컴퓨터에 git프로그램이 있어야한다.








4. 설치가 완료되면 cmd창을 열고 명령어를 입력한다. 


   git

   git --version

   (git관련 명령어와 git버전이 잘 뜬다면 설치 성공)




5. git 환경설정으로 name과 email을 지정해준다.


   git config --global user.name shlee0882

   git config --global user.email shlee0882@gmail.com




6. github에서 만든 원격 git저장소를 자신의 로컬 컴퓨터로 다운받기 위해서는

clone 명령어를 사용한다.

로컬 컴퓨터의 clone(다운로드)할 위치로 이동 후 다음 명령어로 복사(다운로드)한다.


   git clone https://github.com/shlee0882/Git-Study.git




7. 다운로드된 위치로 이동 후 text.txt파일을 하나 만든다.




8. working directory 에서 현재 상태를 확인한다. 

상태 명령어는 status이다.


   git status




9. 만든 파일을 올리기 위해서는 working directory -> staging area(index)

로 옮겨야 한다. 스태이징의 명령어는 add이다.


   git add text.txt




10. add명령이 성공적으로 되었다면 local repository(로컬 저장소)로 올려야한다.

로컬 저장소는 commit명령어를 사용하여 커밋메세지로 -m을 커밋내용을 입력한다.

   

   git commit -m "add Text File"




11. commit 명령이 성공적으로 되었다면 remote repository(원격저장소)로 올려야한다.

원격 저장소는 push명령어를 사용한다.


   git push




12. push가 완료되면 자신의 github으로 이동해서 커밋한 파일이 잘 올라갔는지 확인한다.





2. git work flow (동작원리)



앞에 명령어를 그림으로 나타내면 git은 다음과 같이 동작하는 것을 확인할 수 있다.

index는 staging하는 영역이다.


add와 commit으로 로컬 저장소까지 올릴수 있고

commit -a를 통해 add와 commit을 동시에 진행 할 수 있다.


push로 원격 저장소로 올리고

fetch로 로컬 저장소로 받을 수 있다.


fetch와 checkout으로 merge를 할수 있고

pull을 통해 fetch와 merge를 동시에 진행 할 수 있다.




 






3. git 명령어 add, reset, checkout, amend, log




sampleCode.html 을 스테이징으로 올린다.


   git add sampleCode.html




스태이징에 올라간 sampleCode.html 파일을 내려오게 한다.


   git reset sampleCode.html




sampleCode.html 파일을 원격레파지토리에 올라간것으로 바꾼다.


   git checkout -- sampleCode.html 




올라가야 할 파일을 전부 스태이징으로 올린다.


   git add . 




git 로그 확인 하기 (커밋 메세지, 해쉬 값)


   git log 




과거의 커밋한 특정 시점으로 돌아감 


   git reset --hard [hash value]

   git reset --hard adf0f596fbe1e8033e76ac2680546480fb2b0ed9





강제로 푸시 진행


   git push -f




커밋 메세지 변경


   git commit --amend




4. git branch 사용해 master에 merge해 올리기




1. 현재 브랜치 확인

   git branch





2. develop 브랜치 생성

   git brach develop





3. develop 브랜치 이동

   git checkout develop





4. 현재 브랜치 확인

   git branch





5. 파일 수정, 추가 후 push, git log 확인






현재 push한 곳은 develop 브랜치

github은 master 브랜치를 바라보고 있음

master 브랜치에도 push를 해줘야함.




6. 마스터 브랜치로 이동

   git checkout master





7. develop 브랜치와 머지

   git merge develop





8. git log 확인






HEAD -> master, develop으로

master와 develop 모두 올라간 것을 확인





9. develop 브랜치 삭제

  git branch -d develop




10. local 레파지토리에서 작업한 파일을 원격 레파지토리로 바로 올리는 방법


1
2
3
4
5
6
7
git init
git status
git add .
git commit -m "test commit"
git remote add origin https://github.com/shlee0882/git-test.git
git remote -v
git push origin master
cs


+ Recent posts