67일: GoF, Lambda(Consumer,Predicate,Supplier,RuntimeException), 자바에서 표준메소드 작성, 익명 객체를 이용한 스레드, Controller
2022.02.18.Fri.
✍ 복습
GoF(Gang of Four) 디자인 패턴
출처 : https://velog.io/@namezin/GoF-design-pattern
Factory
- 객체를 생성하는 데 복잡한 옵션이나 정보가 필요. 대신 설정해 주는 클래스
- MyBatis의 경우 DataSource를 입력받아 SqlSession을 생성한 다음 SqlSession을 이용해 CRUD 처리
- active시 최대 연결은 몇개? idle시(프로세스가 실행하고 있지 않은 상태) 최대 연결 몇개? 타임아웃시간?.....설정을 잡을 수 있는데 설정을 안잡으면 SqlSession을 안만들건가? 적절하게 초기화해서 객체를 만들어주는 공장
- 마이바티스의 SqlSessionFactory는 DataSource를 입력받아 SqlSession을 편리하게 사용할 수 있는 SqlSessionTemplate을 만들어준다.
Builder
- 객체 생성의 난해함(예를들어 필드가 String 10개)을 덜어준다.
Facade
- 표준 인터페이스 + 인터페이스를 구현한 구상(concrete) 클래스
- 표준을 가지고 작업을 하면 구상 클래스를 필요에 따라 교체하면서 사용
자바에서 표준메소드 작성하기
- 스레드 : 메소드가 병렬 실행
- 스레드가 실행될 때 윈도우로부터 일정 실행시간을 지정받는다(time slice). 시간이 지나면 실행을 양보한다
- 만약 2초 걸리는 A스레드, 3초 걸리는 B 스레드가 있다면. 그리고 타임 슬라이스가 0.1초라면
A B A B
0.1 0.1 0.1(0.2) 0.1(0.2).....
- 자바는 스레드 클래스를 제공하기 때문에 간단하게 병렬 작업을 할 수 있다
- 단 자바가 병렬로 돌릴 작업이 뭔지는 모른다 → 프로그래머가 작성해야 한다 → 이름이 run으로 정해져 있다
- 자바에서 표준메소드를 작성하려면 인터페이스를 implements해야 한다
class MyRunnable implements Runnable {
@Override
public void run() {
for(int i=1; i<=10; i++)
System.out.println("### MyRunnable 실행 중 : " + (i*10) + "% 완료 ###");
}
}
public class Test2 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
// new Thread하는데 왜 객체를 넘긴다? 실제로는 메소드를 넘긴 것
// js에서는 함수만 넘길 수 있다. new Thread(function() { });
new Thread(myRunnable).start();
System.out.println("메인 스레드 종료");
}
}
익명 객체를 이용한 스레드
- boilerplate : 작업 할 때 반복되는 코드
- 자바에서 js처럼 함수를 파라미터로 넘기고 싶다. 근데 자바는 인터페이스를 구현한 객체를 생성해야 한다 → boilerplate를 제거하자
public class Test3 {
public static void main(String[] args) {
// Runnable은 만들어야 하는데...클래스까지 만들 필요는 없잖아...파라미터로 Runnable을 넘기자
// Thread 생성자의 파라미터가 Runnable이라는 사실을 자바가 알고 있다
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("익명 객체를 이용한 스레드");
}
}).start();
// 그렇다면 프로그래머는 run()의 내부만 만들자 -> 객체는 자바가 만들면 되잖아 : 자바 Lambda
// 메소드만 만들면 자바가 객체를 알아서 생성해준다 -> 전제조건 : 인터페이스가 존재해야만 한다
new Thread(
()->{System.out.println("익명 객체를 이용한 스레드");}
);
}
}
람다식 예시
// 람다식을 이용해 간편하게 함수를 작성하려면...많은 작업이 필요하다
// 람다식을 사용하려면 추상 메소드를 하나가진 인터페이스가 바람직
@FunctionalInterface
interface 인사 {
public void hello();
}
class 학생 {
public void 꾸벅(인사 insa) {
insa.hello();
}
}
public class Test4 {
public static void main(String[] args) {
// 인터페이스가 있고 그 인터페이스를 이용하는 클래스가 있어야만 람다식을 사용할 수 있다
// 람다를 사용하려니 배보다 배꼽이 크다 -> 자바는 java.util.function 패키지를 이용해 FunctionInterface를 제공
학생 s = new 학생();
s.꾸벅(()->{ System.out.println("안녕하세요"); });
}
}
Consumer
입력은 있고 리턴은 없다
class ConsumerSample implements Consumer<Integer> {
@Override
public void accept(Integer t) {
System.out.println(t);
}
}
public class Test5 {
public static void main(String[] args) {
// Arrays.asList는 배열을 리스트로 변환하는 함수. 읽기전용이다
List<Integer> list = Arrays.asList(11,22,33,44,55);
// ConsumerSample을 사용한 예 : ?의 구체적 의미가 궁금해서 iilii.eloos.com에서 generic 강좌를 보세요
list.forEach(new ConsumerSample());
// 람다식을 사용한 예
// list.forEach((xx)->{ System.out.println(xx); });
// 처리하는 코드가 한 줄이면 {}를 생략할 수 있다. {}를 생략하면 ;이 오면 안된다
//list.forEach((xx)->System.out.println(xx));
// 파라미터가 하나면 ()를 생략할 수 있다(하나일때만 생략 가능)
//list.forEach(a->System.out.println(a));
// 파라미터에 대해 어떤 처리도 하지 않는다면....윗줄의 경우 xx가 들어와서 그대로 xx를 출력한다...생략하자
// 이렇게 파라미터를 생략하고 함수를 사용하는 것을 "메소드 참조"라고 한다
list.forEach(System.out::println);
}
}
Predicate
입력이 있고 출력은 boolean → 조건 체크
class SamplePredicator implements Predicate<Integer> {
@Override
public boolean test(Integer t) {
return t%2==0;
}
}
public class Test6 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(11,22,33,44,55);
// 람다식을 이용해 작업하도록 만들어진 자바 기술이 Java Stream API
// 리스트를 스트림을 변환하면 자바가 제공하는 함수를 이용해 람다식을 연속으로 사용할 수 있다
// filter는 list를 모든 원소를 차례로 입력받아 조건을 만족하는 것만 걸러낸다
// 스트림에는 메소드에는 중간에서 필터링 또는 변경하는 중간 메소드가 있고 최종 소비를 하는 메소드가 있다
list.stream().filter(a->a%2==0).forEach(System.out::println);
// list로 부터 조건을 만족하는 원소만 뽑아서 리스트를 작성하고 싶다면
List<Integer> result = list.stream().filter(a->a%2==0).collect(Collectors.toList());
System.out.println(list.stream().filter(a->a%2==0).count());
}
}
Supplier
입력은 없고 출력은 있다
import java.util.*;
import java.util.function.*;
class SupplierSample1 implements Supplier<Integer> {
@Override
public Integer get() {
// 입력은 없고 출력은 있다
return 1;
}
}
// 우리가 사용할 서플라이어 형식 :
class SupplierSample2 implements Supplier<RuntimeException> {
@Override
public RuntimeException get() {
return new RuntimeException();
}
}
public class Test7 {
public static void main(String[] args) {
// java.util.Optional : NullPointerException에 대한 자바의 대응
// 리턴값이 반드시 존재할 경우 : public User searchUser(String username) { }
// 리턴값이 존재하지 않을 수 있는 경우 : public Optional<User> searchUser(String username) { }
// dao에서 Optional로 result가 리턴되어 왔다고 하자
Optional<Integer> result = Optional.ofNullable(null);
// result에 들어있을 수 있는 Integer를 꺼내려면 get() -> 단 값이 없으면 NoSuchElementException 예외 발생
// Integer value1 = result.get();
// 예외를 내가 원하는 예외로 바꿔주자
// 스프링에는 예외를 전담하는 컨트롤러가 있다(@ControllerAdvice)
// 검색 실패와 같이 내가 원하지 않는 결과가 나왔을 때 적절한 예외를 발생시켜 ControllerAdvice를 부르자
// 즉 작업을 할 때 바람직한 상황은 Controller에 작성, 원하지않는 상황은 ControllerAdvice에 작성하자
result.orElseThrow(()->new RuntimeException());
result.orElseThrow(RuntimeException::new);
}
}
RuntimeException (예외 처리)
- try ~ catch 사용하지 않으려고 RuntimeException 사용
- 체크하는 예외 : try~catch 필요
- 체크하지 않는 예외 : 가벼운 예외로 RuntimeException의 자식. 예외처리 코드는 작성하지 않아도 상관없다
public class BoardNotFoundException extends RuntimeException {
}
Lambda Test 1
Lambda Test 2
Controller
MVC(Model View Controller) : Model:데이터, View: 화면
백엔드에서 View를 포함하고 있다 → 백엔드와 뷰가 함께 작업한다. 즉 자바 객체를 보내줘도 타임리프나 jsp는 처리할 수 있다
@GetMapping("/test1")
public ModelAndView test1(Integer pno) {
return new ModelAndView("test1").addObject(new Product(pno, pno+"번 상품"));
}
REST
데이터만 있다 → 그러면 데이터를 어떻게 클라이언트쪽으로 출력할까? (자바 객체는 안된다), 스프링 부트의 경우 JSON으로 내보낸다.
- 입력 형식을 지정 : PropertyEditor
- 출력 형식을 지정 : MessageConverter
- 스프링 부트 프로젝트를 만들면 JSON을 처리하는 Jackson 라이브러리가 자동포함되고 JSON에 대한 메시지 컨버터로 잭슨 자신을 등록한다
- Jackson, Gson 등 JSON 라이브러리가 포함되지 않은 경우 메시지 컨버팅에 실패(415. unsupported media type)
@GetMapping(value="/test2", produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Product test2(Integer pno) {
return new Product(pno, pno+"번 상품");
}
// @RequestBody, @ResponseBody
// request, response를 편지에 비유하자면 편지봉투가 있고 편지지가 있다
// (보내는 주소, 요청 주소, 데이터의 길이) 등 편지봉투에 해당하는 것이 헤더, 내용에 해당하는 것이 바디
// urlencoded로 요청, 응답 바디에 여러개의 값을 담아서 보낼 수 있다
// json의 경우는 단일 json이 요청 객체, 또는 응답 객체의 바디를 가득 채운다
// @RequestBody는 요청 객체의 바디 전체를 꺼내서 JSON으로 바꿔라
@GetMapping("/example01")
public void test2View() {
}
SampleController 아래 entity를 공통으로 사용
Author And Source
이 문제에 관하여(67일: GoF, Lambda(Consumer,Predicate,Supplier,RuntimeException), 자바에서 표준메소드 작성, 익명 객체를 이용한 스레드, Controller), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@wontwopunch/67일-GoF-LambdaConsumerPredicateSupplierRuntimeException-자바에서-표준메소드-작성-익명-객체를-이용한-스레드저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)