프로젝트/잡스캐너

Optional 활용하기, 람다식에서 지역변수 변경하기

성장에 몰입중인 개발자 2022. 9. 8. 23:55

로그인하는데 회원가입이 되어 있지 않으면 예외가 발생한다. 하지만 처음 소셜 로그인할 때는 회원가입이 되어 있지 않아서 NotFoundMemberException 예외가 발생하는 문제가 있었다. 우선 간단하게 try-catch문으로 NotFoundMemberException 예외를 잡아서 회원가입을 진행하고 로그인을 진행하게 코드를 짰다.

 

Controller에 비즈니스 로직과 예외 처리 로직이 함께 있어서 좀 더 개선할 방법을 고민했다. Optional을 활용해서 회원가입이 되어 있지 않는다면 Optional.orElseGet()을 사용해서 Controller에 try-catch문을 없애고 좀 더 간결하게 만들 수 있었다.

 

Optional 활용하기

	@PostMapping("signin/{socialType}")
	public ResponseEntity<AuthLoginResponse> socialSignin(
		@PathVariable("socialType") String type,
		HttpServletRequest request
	) {
		AtomicReference<HttpStatus> httpStatus = new AtomicReference<>(HttpStatus.OK);
		SocialType socialType = SocialType.getEnum(type);
		socialTokenValidator = socialTokenValidatorFactory.find(socialType);

		String code = JwtHeaderUtil.getCode(request);
		Member member = socialTokenValidator.generateMemberFromCode(code);

		SocialMember findSocialMember = socialMemberService.findByEmailAndSocialType(member.getEmail(), socialType)
			.orElseGet(() -> {
				httpStatus.set(HttpStatus.CREATED);
				return socialSignup(member, socialType);
			});

		return ResponseEntity.status(httpStatus.get()).body(authService.signin(findSocialMember));
	}

 

orElse()와 orElseGet()의 차이

    /**
     * If a value is present, returns the value, otherwise returns
     * {@code other}.
     *
     * @param other the value to be returned, if no value is present.
     *        May be {@code null}.
     * @return the value, if present, otherwise {@code other}
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * If a value is present, returns the value, otherwise returns the result
     * produced by the supplying function.
     *
     * @param supplier the supplying function that produces a value to be returned
     * @return the value, if present, otherwise the result produced by the
     *         supplying function
     * @throws NullPointerException if no value is present and the supplying
     *         function is {@code null}
     */
    public T orElseGet(Supplier<? extends T> supplier) {
        return value != null ? value : supplier.get();
    }

orElse()와 orElseGet()의 경우 차이가 없어 보일 수 있다. 하지만 자바 언어의 특성상 메소드가 사용되기 전에 먼저 파라미터에 있는 연산을 수행한다. 즉 orElse()는 수행되지 않더라도 파라미터로 들어가는 값의 연산이 수행되는 것이다. 만약 orElse()가 실행되지 않는다면 CPU와 메모리 연산이 낭비된다. 따라서 메소드가 수행되는 시점에 파라미터의 연산을 수행하는 orElseGet()을 사용했다.

ps.로깅
마찬가지로 logging.level = info인데 log.trace("this year=" + "2022")일 경우, log가 찍히지 않는데 불필요한 연산이 발생하기 때문에 log.trace("this year={}", "2022")로 쓰는 것이 더 좋다.


람다식에서 지역 변수 변경하기
로그인이 진행되면 HTTP OK 200 상태 코드를 반환한다. 하지만 프로젝트 프론트엔드 팀원이 처음 소셜 로그인시에 자동으로 회원가입이 진행되고나서 로그인해서 JWT를 반환할 경우, 온보딩으로 redirect하기 위해서 HTTP CREATED 201 상태 코드를 반환해달라는 요구사항이 있었다.

지역변수는 스레드 스택에서 관리되고, 람다식는 다른 스레드에서 실행됨으로 람다식내에서 변경할 수 없다. 따라서 멀티스레드 환경에서 동시성을 보장하는 AtomicRefrerence<>를 사용해서 httpStatus의 상태를 변경함으로 요구사항을 구현했다.

참고
https://leekm0912.tistory.com/26