일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- raw 타입
- 함수형 인터페이스
- 정렬
- 스파르타코딩클럽
- junit 5
- throwable
- Switch Expressions
- auto.create.topics.enable
- 상속
- System.out
- 자바할래
- 제네릭 와일드 카드
- 제네릭 타입
- 접근지시자
- docker
- 브릿지 메소드
- github api
- Study Halle
- 프리미티브 타입
- 바운디드 타입
- annotation processor
- 익명 클래스
- 합병 정렬
- System.in
- 로컬 클래스
- 람다식
- 항해99
- 자바스터디
- System.err
- yield
- Today
- Total
코딩하는 털보
21.09.18 TIL 본문
항해99 DAY 6
try-catch 문에서 실행부를 제외한 catch 블록이 동일한 코드로 자주 사용됩니다. 중복을 없앨 수 있을까요?
@app.route('/post', methods=['DELETE']) def delete_post(): token_receive = request.cookies.get('mytoken') try: #jwt에서 payload 가져오기 payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256']) #payload를 통해 user 정보 조회 user = db.users.find_one({"user_id": payload["user_id"]}) post_id_receive = request.form['post_id'] post_id_valid_check(post_id_receive) if is_post_owner(post_id_receive, user): db.post.delete_one({'_id': ObjectId(post_id_receive)}) db.comment.delete_many({'post_id': post_id_receive}) db.likes.delete_many({'post_id': post_id_receive}) return jsonify({'msg': '고민이 삭제되었습니다.'}) else: return jsonify({'msg': '해당 글에 대한 권한이 없습니다.'}), 403 # 예외 처리 except jwt.ExpiredSignatureError: abort(401, '로그인 시간이 만료되었습니다.') except jwt.DecodeError: abort(401, '로그인 정보가 존재하지 않습니다.')
해결, 훨씬 깔끔하다.
@app.route('/post', methods=['DELETE']) def delete_post(): token_receive = request.cookies.get('mytoken') user = get_user_from_token(token_receive) post_id_receive = request.form['post_id'] post_id_valid_check(post_id_receive) if is_post_owner(post_id_receive, user): db.post.delete_one({'_id': ObjectId(post_id_receive)}) db.comment.delete_many({'post_id': post_id_receive}) db.likes.delete_many({'post_id': post_id_receive}) return jsonify({'msg': '고민이 삭제되었습니다.'}) else: return jsonify({'msg': '해당 글에 대한 권한이 없습니다.'}), 403 # ExpiredSignatureError 및 DecodeError 가 발생하는 곳이 jwt.decode 이므로 요부문만 추출한다. # get_user_from_token()는 유저 정보가 필요한 다른 메서드들에서 공통적으로 사용하면 된다. def get_user_from_token(token): try: payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256']) return db.users.find_one({"user_id": payload["user_id"]}) except jwt.ExpiredSignatureError: abort(401, '로그인 시간이 만료되었습니다.') except jwt.DecodeError: abort(401, '로그인 정보가 존재하지 않습니다.')
자바 람다식
분명히 난 자바 스터디할때 람다에 대해서 공부를 했다. 근데 왜 어떤게 머리속에 들어가면 GC마냥 다른 안쓰는 것은 삭제되는 것인가.
오늘은 '잊혀진' 람다에 대해서 다시 공부해보고 조금 다른 공부 방법을 써보려고 한다. 사실 방법이랄것도 없다 그냥 겁나 두들겨 보는거다.
일단 자바 8하면 떠오르는 람다식.. 도덕책 언제쓰일까?
람다식은 익히 알듯이 익명 함수이다.
익명 함수라는 말은 부를 이름이 없다는 말이다.
부를 이름이 없다는 것은 다음에 또 불러서 쓰일 수 없다는 말이다.
즉, 람다식은 이번에 한번만 쓸 메서드를 좀 더 간결하게 만들고 싶을때 사용한다.
예를 들어 문자열을 다른 문자열로 변환해주는 Converter라는 인터페이스가 있다.
Converter에는 받은 문자열을 변환하는 하나의 메서드만 존재한다.
interface Converter {
String convert(String str);
}
람다를 써보기 전에 익명 클래스를 사용해서 convert를 구현해보자.
public class Test {
static String str = "abcdefg";
public static void main(String[] args) {
Converter converter = new Converter() {
@Override
public String convert(String str) {
return str.toUpperCase(Locale.ROOT);
}
};
String result = converter.convert(str);
System.out.println(result);
}
}
익명 클래스는 이렇게 클래스 이름 없이 만드는 로컬 클래스(메서드 안에서 생성되는 클래스)이다.
익명 클래스도 느낌은 비슷하다. 한번 쓸거니까 간결하게 만드는것.
람다식은 여기서 한단계 더 나아가 만약 익명 클래스가 구현하는 메서드가 하나라면 메서드 이름까지 생략해버리는 것이다.
이번에는 람다식을 사용해보자.
public class Test {
static String str = "abcdefg";
public static void main(String[] args) {
Converter converter = str -> str.toUpperCase(Locale.ROOT);
String result = converter.convert(str);
System.out.println(result);
}
}
와우. 나는 내가 실행해 보면서도 "이게 된다고? 이러는 중이다.str -> str.toUpperCase(Locale.ROOT);
에 대해서 좀더 생각을 해보자.
좌변의 str
은 구현할 메서드의 매개변수와 같다.
그러면 이렇게 생각할지도 모르겠다.
"Converter 인터페이스에 convert() 메서드의 매개변수는 String 타입인데...그럼 타입은 상관 없는건가?"
사실 좌변은 매개변수에서 타입이 생략되어 있다. 정확히는 괄호까지 생략이 되어있다.(String str) -> str.toUpperCase(Locale.ROOT);
여기에서 람다는 매개변수의 타입을 생략할 수 있게 해줬고, 매개변수가 하나일 때는 괄호까지 생략 가능하기 때문에 위에 예시 처럼 작성될 수 있는 것이다.
우변의 str.toUpperCase(Locale.ROOT);
또한 사실 블록과 return
이 생략된 것이다.
만약 이 람다식의 구현부가 여러 줄의 코드를 요구한다면 블록과 return
을 사용해야 한다.
Converter converter = str -> {
System.out.println(str);
return str.toUpperCase(Locale.ROOT);
};
사실 람다식은 익명 클래스의 간편화 버전이다.
"잉? 람다식은 메서드 아니었음?"
람다식의 사용법이 메서드를 만드는 방법과 아주 유사하기 때문에 혼란이 있을 수도 있지만,
람다식은 함수형 인터페이스(구현할 추상 메서드가 하나밖에 없는 인터페이스)를 구현하는 "익명 클래스"이다.
클래스 임에도 불구하고 가진게 메서드 하나 뿐이기 때문에 그 메서드 자체가 클래스를 전부 설명할 수 있다. 그래서 람다식은 익명 메서드로 불리우기도 하는 것.
람다식이 익명 클래스 임을 알았으니 무엇을 할 수 있는가.
인스턴스화 될 수 있고 그것을 변수에 집어 넣을 수도 있다는 것이다. 사실 위에서 이미 했다.Converter converter = str -> str.toUpperCase(Locale.ROOT);
converter
는 Converter
타입의 람다식 인스턴스가 대입된다.
또는 메서드의 반환으로 사용할수도 있겠다.
public static Converter upperCaseConverter() {
return str -> str.toUpperCase(Locale.ROOT);
}
꽤나 멋진 코딩이 가능하다!
옆에 친구가 람다식과 스트림을 즐겨사용하는데 그걸보며 람다식을 좀치면 회사에서 좋은 평가를 받을 수 있을 것 같다는 생각이 들었다.
람다식은 필연적으로 함수형 인터페이스를 사용할 때 자주 쓰이게 된다.
특히 자바의 표준 함수형 인터페이스는 자바의 표준 라이브러리를 사용할 때 매우 중요하다.
대표적인 예로 배열이나 컬렉션을 이용해서 만드는 Stream의 주요 메서드들 대부분은 인수로 표준 함수형 인터페이스 타입을 받는다.
public static void main(String[] args) {
Collection<Integer> list = Arrays.asList(1,2,3,4,5);
List<Integer> collect = list.stream().map(x -> x + 10).collect(Collectors.toList());
System.out.println(collect);
}
위의 예시에서 Stream의 map() 메서드는 Function 인터페이스 타입을 인수로 받는다.
사용자는 Function 인터페이스를 확인하여 그 메서드를 구현하는 람다식을 인수로 넘겨줄 수 있다.
람다에 대해서 간략하게 알아보았는데, 문제는 람다식을 계속 써보는 습관을 들이는 것.
람다식이나 스트림이 내 머릿속에서 계속 삭제되는 이유는 역시 쓰질 않아서 그렇다고 생각한다.
다음 프로젝트에서 Collection을 조작해야할 기능이 필요할때 잊지말고 꼭 써보자.