Arrays

  • 배열을 다루기 편리한 메서드(static) 제공
  • 배열의 출력 toString()
  • 배열의 복사 copyOf(), copyOfRange()
  • 배열 채우기 -fill(), setAll()
  • 배열의 정력과 검색 - sort(), binarySearch()
    • binarySearch하기 전에는 반드시 배열 정렬 .sort() 먼저
  • 다차원 배열의 출력 deepToString()
  • 다차원 배열의 비교 - deepEquals()
  • 배열을 List로 변환 asList(Object ... a)
  • 람다와 스프림 관련 - parallel(), spliterator(), stream()

arrays

 

Comparator 와 Comparable

  • 객체 정렬에 필요한 메서드(정렬기준 제공)를 정의한 인터페이스
  • Comparable - 기본 정렬기준을 구현
  • Comparator - 기본 정렬기준 외에 다른 기준으로 정렬하고자할 때 사용
public interface Comparator {
	int compare(Object o1, Object o2); //o1, o2 두 객체 비교
    boolean equals(Object obj); //equals를 오버라이딩하라는 뜻
  }
  
public interface Comparable {
	int compareTo (Object o); // 주어진 객체 o 를 자신과 비교
 }

 

public final class Integer extends Number implements Comparable {
	...
    public in t compareTo(Integer anotherInteger) {
    	int v1 = this.value;
        int v2 = anotherInteger.value;
        //같으면 0, 오른쪽값이 크면 -1, 작으면 1을 반환
        return (v1 < v2 ? -1: (v1==v2? 0 :1));
    }
    ...
}

 

예제 Ex11_7

import java.util.*;

class Ex11_7 {
    public static void main(String[] args) {
        String[] strArr = {"cat", "Dog", "lion", "tiger"};

        Arrays.sort(strArr); // String의 Comparable 구현에 의한 정렬
        System.out.println("strArr=" + Arrays.toString(strArr));

        Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); // 대소문자 상관 없이 정렬
        System.out.println("strArr=" + Arrays.toString(strArr));

        Arrays.sort(strArr, new Descending()); //역순으로 정렬
        System.out.println("strArr=" + Arrays.toString(strArr));
    }
}

class Descending implements Comparator {
    public int compare(Object o1, Object o2){
        if( o1 instanceof Comparable && o2 instanceof Comparable) {
            Comparable c1 = (Comparable)o1;
            Comparable c2 = (Comparable)o2;
            return c1.compareTo(c2) * -1 ; //-1을 곱해서 기본 정렬방식의 역으로 변경
            // 또는 c2.compareTo(c1)와 같이 순서를 바꿔도 됨
        }
        return -1;
    }
}

 

Integer와 Comparable

  • 삼항연산자가 기본사칙연산보다 상대적으로 빠르다 (2~3% 정도)

 

버블정렬 bubble sort 코드

  • 서로 인접한 두 원소의 대소를 비교하고, 조건에 맞지 않다면 자리를 교환하며 정렬하는 알고리즘
static void sort(int[] intArr) {
	for(int i=0; i<intArr.length-1;i++) {
    	for(int j=0; j<intArr.length-1-i; j++) {
        int tmp =0;
        
        if(intArr[j] > intArr[j+1]) {
        	tmp = intArr[j];
            intArr[j] = intArr[j+1];
            intArr[j+1] =tmp;
            }
     }
}
  • 버블 정렬은 첫 번째 자료와 두 번째 자료를, 두 번째 자료와 세 번째 자료를, 세 번째와 네 번째를, … 이런 식으로 (마지막-1)번째 자료와 마지막 자료를 비교하여 교환하면서 자료를 정렬함
  • 1회전을 수행하고 나면 가장 큰 자료가 맨 뒤로 이동하므로 2회전에서는 맨 끝에 있는 자료는 정렬에서 제외되고, 2회전을 수행하고 나면 끝에서 두 번째 자료까지는 정렬에서 제외된다. 이렇게 정렬을 1회전 수행할 때마다 정렬에서 제외되는 데이터가 하나씩 늘어난다.

https://gyoogle.dev/blog/algorithm/Bubble%20Sort.html

 

거품 정렬(Bubble Sort) | 👨🏻‍💻 Tech Interview

거품 정렬(Bubble Sort) Goal Bubble Sort에 대해 설명할 수 있다. Bubble Sort 과정에 대해 설명할 수 있다. Bubble Sort을 구현할 수 있다. Bubble Sort의 시간복잡도와 공간복잡도를 계산할 수 있다. Abstract Bubble S

gyoogle.dev

 

 

 

 

 

 

 

 

 

 

Iterator

Iterator, ListIterator, Enumeration

  • 컬렉션에 저장된 데이터를 접근하는데 사용되는 인터페이스
  • iterator만 쓰면됨 (Enumeration은 Iterator의 옛날 버전)
  • ListIterator는 Iterator의 접근성을 향상 시킨것

  • 컬렉션에 저장된 요소들을 읽어오는 방법을 표준화한 것
  • 컬렉션에 iterator()를 호출해서 Iterator를 구현한 객체를 얻어서 사용
List list = new ArrayLsit(); //다른 컬렉션으로 변경할 때는 이 부분만 고치면 된다.
Iterator it = list.interator();

while(it.hasNext()) { //boolean has Next()
	System.out.println(it.next()); 
  }
  • iterator는 1회용이라 다쓰고나면 다시 얻어와야 한다

 

Map과 Iterator

  • Map에는 iterator()가 없음
  • Keyset(), entrySet(), values()를 호출해야함
Map map = new HashMap();
.
.
.
Iterator it = map.entrySet().iterator();

 

 

 

  • stack: LIFO 구조, 마지막에 저장된 것을 제일 먼저 꺼냄
  • Queue: FIFO 구조, 제일 먼저 저장한 것을 제일 먼저 꺼냄

stack and queue

 

Stack 메서드

stack 메서드

 

Queue 메서드

 

  • Queue는 인터페이스
  • stack은 클래스

 

인터페이스를 구현한 클래스 찾기

  • Queue를 구현한 클래스를 사용

Java API문서

  • 스택 활용 예 - 수식계산, undo/redo, 웹브라우저 뒤로/앞으로
  • 큐 활용 예 - 최근사용문서(recent files), 인쇄작업 대기목록, buffer
  • 배열의 장점: 구조가 간단하고 데이터를 읽는데 걸리는 시간(access time)이 짧다
  • 배열의 단점:
    • 크기를 변경할 수 없다 -> 새로운 배열을 생성 후 데이터를 복사해야함
    • 크기 변경을 피하기 위해 충분히 큰 배열을 생성하면 메모리 낭비
    • 비순차적인 데이터의 추가, 삭제에 시간이 많이 걸림
    • 데이터를 추가하거나 삭제하기 위해, 다른 데이터를 옮겨야 함
    • 순차적인 데이터 추가(끝에 추가)와 삭제(끝부터 삭제)는 빠름

LinkedList

LinkedList는 배열의 단점(1. 크기변경 x 2. 추가삭제시간 많이걸림) 을 보완

  • LinkedList는 불연속적으로 존재하는 데이터를 연결(link)
  • 불연속적
class Node{
	Node next; 
        Object obj;
        }
  • 단 한번의 참조변경으로 데이터 삭제 가능
  • 한번의 Node 객체생성과 두번의 참조 변경만으로 데이터 추가 가능

 

LinkedList - 이중 연결 리스트

  • LinkedList - 데이터 접근성이 나쁨
  • doubly linked list - 이중 연결 리스트, 접근성 향상
class Node{
	Node next; 
    Node previous;
        Object obj;
        }

 

  • doubly circular linked list - 이중 원형 연결리스트
  • 자바에서는 이중연결리스트로 구현되어 있음

 

ArrayList vs. LinkedList 

  • ArrayList가 추가할 때 더 빠름
  • 순차적으로 삭제할 때 ArrayList가 빠름
  • 비순차적으로 데이터 추가/삭제 - LinkedList가 빠름 (20배는 차이남)
  • 접근시간(access time)- ArrayList가 빠름 (400배 이상)
  • 읽기는 ArrayList가 빠르고 추가/삭제는 LinkedList가 빠름
  • LinkedList는 데이터가 많을수록 접근성이 떨어짐

 

 

 

 

 

 

 

자바가 모잘라서 자바 공부를 합니다.

사실 서버 배포도 공부해야하는데 자바를 모르는게 더 시급하다고 생각해서 자바의 정석을 들었습니다. 

Map, List, Set, Stream 등등 이번주는 컬렉션 프레임웍 뽀개기를 할겁니다.

그다음에 Spring 강의도 들어야겠습니다.

 

오늘은 전체 코드를 refactoring을 하고 발표자료를 만들었습니다. 다들 엄청 잘하셔서 든든합니다.

 

데이터에 좋아요 수를 넣어서 보내주는 것으로 변경했습니다.

자바가 뭐양

 

좋아요 true/false 와 좋아요 수 반환

 

@Service

@Transactional
public LikePostResponseDto likePost(Long postId, User user) {
    Post post = postRepository.findById(postId).orElseThrow(
            () -> new CustomException(ErrorCode.CONTENT_NOT_FOUND)
    );
    Long userId = user.getId();

    boolean likeCheck;

    Optional <LikePost> likePost = likePostRepository.findByPostIdAndUserId(postId, userId);

    if (likePost.isPresent()) {
        LikePost like = likePost.get();
        likePostRepository.delete(like);
        post.setLikeCount(post.getLikeCount()-1);

        likeCheck = false;

    } else{
        LikePost like = new LikePost(postId, userId);
        likePostRepository.save(like);
        post.setLikeCount(post.getLikeCount()+1);
        likeCheck = true;
    }


    return new LikePostResponseDto(likeCheck, post.getLikeCount());
}
  • boolean 으로 true/ false 만 반환했었는데 LikeCount도 같이 LikePostResponseDto에 넣어주었습니다.

 

@Controller

@ApiOperation(value = "게시글 좋아요")
@PostMapping("/post/{postId}")
public ResponseEntity<ResponseMessage> likePost(@PathVariable Long postId, @ApiIgnore @AuthenticationPrincipal UserDetailsImpl userDetails){

    LikePostResponseDto likePostResponseDto = likeService.likePost(postId, userDetails.getUser());

    ResponseMessage<LikePostResponseDto> responseMessage = new ResponseMessage<>("게시글 좋아요 성공", 200, likePostResponseDto);

    return new ResponseEntity<>(responseMessage, HttpStatus.valueOf(responseMessage.getStatusCode()));
}
  • LikePostResponseDto 의 parameter를 추가해줘서 프론트에서 요청한 '좋아요했는지 여부 true/false'와 좋아요 갯수'LikeCount' 를 반환합니다.

 

LikePostResponseDto

@Getter
@Setter
@NoArgsConstructor
public class LikePostResponseDto {
    private boolean postLiked;

    private Long likeCount;


    public LikePostResponseDto(boolean postLiked, Long likeCount) {
        this.postLiked = postLiked;
        this.likeCount = likeCount;
    }
}

 

  • 좋아요 갯수를 담을 Long likeCount와 좋아요 여부를 확인할 boolean postLiked를 넣어줬습니다.
  • 댓글 좋아요도 마찬가지로 진행했습니다.

 

 

 

ArrayList

  • ArrayList는 기존의 Vector를 개선한 것으로 구현원리와 기능적으로 동일
  • List인터페이스를 구현하므로, 저장순서가 유지되고 중복 허용
  • 데이터의 저장공간으로 배열을 사용
  • List 인터페이스 구현
  • 모든 종류의 객체 저장 가능

 

ArrayList 메서드

  • ArrayList()
  • ArrayList(Collection c)
  • ArrayList(int initialCapacity)
  • boolean add(Object o)
  • void add(int index Object element)
  • boolean addAll(Collection c)
  • boolean addAll(int index, Collection c)
  • boolean remove(Object o)
  • Object remove(int index)
  • boolean removeAll(Collection c)
  • void clear()
  • int indexOf(Object o)
  • int lastIndexOf(Object o)
  • boolean contains(Object o)
  • Object get(int index)
  • Object set(int index, Object element)
  • List subList(int fromindex, int toindex)
  • Object[] toArray() 
  • Object[] toArray(Object[] a)
  • boolean isEmpty ()
  • void trim ToSize()
  • int size() (저장된 객체 갯수 반환)

 

list1:[0,1,2,3,4,5]
list2:[0,2,4]

list1.containsAll(list2):true

containsAll: 포함하고 있는지 true/false 반환 하는 메서드

 

list1.remove(1) // 인덱스가 1인 객체를 삭제
list1.remove(new Integer(1)); // 1을 삭제

 

 

 

 

ArrayList 저장된 객체의 삭제 과정

- 마지막 객체부터 삭제하면 됨

 

 

 

 

 

  • collection: 여러 객체(데이터)를 모아 놓은 것
  • framework: 표준화, 정형화된 체계적인 프로그래밍 방식
  • collections framework:
    • 컬렉션을 다루기 위한 표준화된 프로그래밍 방식
    • 컬렉션을 쉽고 편리하게 다룰 수 있는 클래스를 제공
    • java.util 패키지에 포함. JDK1.2부터 제공
  • collection class: 다수의 데이터를 저장할 수 있음

 

컬렉션 프레임웍의 핵심 인터페이스

  • List:
    • 순서가 있는 데이터의 집합
    • 데이터의 중복을 허용
  • Set(집합):
    • 순서를 유지하지 않는 데이터의 집합
    • 데이터의 중복을 허용하지 않음
  • Map:
    • Key와 Value의 쌍(pair)로 이루어진 데이터의 집합
    • 순서는 유지되지 않으며, 키는 중복을 허용하지 않고 값은 중복 허용
    • ex) 우편번호, 지역번호

 

List 인터페이스 - 순서 o, 중복 x

 

List 인터페이스 메서드

 

Set 인터페이스 - 순서 x, 중복 x

 

 

 

Map 인터페이스 - 순서 , 중복 (키 x, 값 o)

 

Cascade 영속성 전이 사용

영속성 전이를 사용하거나 for문을 돌려서 순수 자바만을 사용했을 때는 아래처럼 일일히 데이터마다 쿼리를 날려서 지우게 했습니다. 지금은 그 수가 적어서 상관이 없지만 나중에 대용량 데이터를 다루게 될 때에 과부하가 걸릴 수도 있다는 판단이 들었습니다. 

 

 

cascade.remove 사용했을 때 query
중첩 for문으로 삭제했을 때 query

 

Where in query 사용

where in 을 사용해서 query를 날리면 댓글을 하나하나 삭제를 하는 것이아니라 한번에 날려줍니다.

public interface CommentRepository extends JpaRepository<Comment, Long>{
	@Modifying //기존에 있는 메서드를 변경하기 때문에
	@Query("delete from Comment c where c.id in :ids")
	void deleteAllByIdIn(@Param("ids") List<Long> ids);
}

위의 코드는 where in을 사용해서 comment와 Likecomment, likepost, post 를 한번씩만 쿼리를 날려서 관련 목록을 다 삭제하였습니다.

 

 

다음에 코드 정리해서 포스팅 해보도록 하겠습니다.

 

참고블로그:

 

 

JPA에서 대량의 데이터를 삭제할때 주의해야할 점

안녕하세요? 이번 시간엔 JPA에서 대량의 데이터를 삭제할때 주의해야할 점을 샘플예제로 소개드리려고 합니다. 모든 코드는 Github에 있기 때문에 함께 보시면 더 이해하기 쉬우실 것 같습니다. (

jojoldu.tistory.com

주말에 오랜만에 놀았더니 오전에 집중하는 게 힘들었던 월요일입니다.  점심시간에 파워냅 1시간 하고 돌아와서 다시 정신 차리고 합니다. 오늘은 영하 15도까지 내려갔다고 하네요. 집에 보일러가 고장나서 슬픈 캥거루족입니다. 얼른 개발자로 취직해서 판교에서 자취하고 싶어요. 어제 오랜만에 대학 친구들을 만났는데 한 친구가 미국 온라인 대학원을 다니고 있다는 소식을 들었습니다. 오프라인과 같은 학위를 받지만 전체 온라인 수업이라 학비도 상대적으로 저렴했습니다. 저도 나중에 취업하고 다녀볼까봐요. BBA & 컴공 master?!

 

추워요...

좋아요를 하고 취소하는 API를 만들어 놓고 정작 좋아요 갯수를 세는 기능이 없어서 오늘은 좋아요 갯수 세는 기능을 추가했습니다.

 

생각보다 간단해서 낮잠 자고 멀쩡한 정신으로 해결했습니다. 다음과 같이 @Service에 코드를 추가했습니다.

 

좋아요 취소 시 좋아요 수 -1

Long likeCount = likePostRepository.countByPostId(postId);
post.setLikecount(post.getLikeCount()-1);

 

 

좋아요 성공 시 좋아요 수 +1

Long likeCount = likePostRepository.countByPostId(postId);
post.setLikecount(post.getLikeCount()+1);

 

 

숫자를 저장할 Long 타입 변수를 만들고 해당 게시물 Id를 이용해서 좋아요 수를 저장했습니다.

post Entity에 있는 Likecount 변수에 넣어주었습니다.

 

Comment를 좋아요 한 변수는 처음에 0으로 설정해서 Nullpointerexception error를 방지합니다.

 

 

CASCADE 영속성 전이

조장님이 던져준 미션인 cascade.remove를 사용하지 않고 게시물 삭제와 동시에 연관된 좋아요, 댓글, 댓글좋아요를 삭제하는 방법에 대해 연구했습니다. Cascade를 사용하면 연관된 테이블이 자동으로 함께 지워진다는 편리함이 있지만 주의해야할 점이 있습니다. 

이에 대해 인프런 JPA 강의 Q&A에서 김영한님의 친절한 답변이 다음과 같이 달렸습니다.

 

cascade 옵션은 단순히 생각하면, 그냥 persist() 호출을 줄여줄 수 있기 때문에, 유용해 보이지만, 반대로 생각하면, Order 엔티티를 저장할 때, 연관된 어떤 엔티티들이 함께 저장될까? 를 계속 코드를 보며 추적해야 합니다.
따라서 질문하신 것 처럼 어디까지는 cascade로 함께 저장하고, 어디까지는 함께 저장하면 안될까? 하는 명확한 기준이 필요합니다.
그래서 이런 기준을 잡기 애매한 경우에는 사실 사용하지 않는 것이 좋습니다.
통상적으로 권장하는 cascade 범위는, 완전히 개인 소유하는 엔티티일 때, 예를 들어서 게시판과 첨부파일이 있을 때 첨부파일은 게시판 엔티티만 참조하므로, 개인 소유 입니다. 이런 경우에는 사용해도 됩니다. 그럼 반대로 개인 소유하지 않는 엔티티는 무엇일까요? 예를 들어서, 회원, 상품 등등이 있습니다.
이 예제에서 Order -> OrderItem을 개인소유 하기 때문에 cascade를 사용했습니다. 그런데 Order 입장에서 Delivery는 좀 애매합니다. 여기서는 프로젝트 규모가 작기 때문에 매우 단순하게 표현했지만, 실무에서 프로젝트 규모가 커지면, Delivery로 여러곳에서 참조될 수 있습니다. 그러면 사용하면 안됩니다.
추가로 도메인 주도 설계(DDD)의 Aggregate Root 개념을 이해하고, 프로젝트 적용하면 여기에 맞추어 cascade 옵션을 더 잘 활용할 수 있습니다.
정리하면
1. 완전 개인 소유인 경우에 사용할 수 있다.
2. DDD의 Aggregate Root와 어울린다.
3. 애매하면 사용하지 않는다.

더 자세한 내용은 JPA 기본편 섹션 8에 있는 영속성 전이(CASCADE)와 고아 객체를 참고해주세요.
감사합니다.

출처:
https://www.inflearn.com/questions/31969/cascade-%EC%98%B5%EC%85%98-%EC%A7%88%EB%AC%B8

 

1. 완전 개인 소유인 경우에 사용할 수 있다.
2. DDD의 Aggregate Root와 어울린다.
3. 애매하면 사용하지 않는다.

 

제가 봉착한 문제는 Cascade의 저 조건에 부합하지 않는(완전 개인의 소유가 아닌)

comment(한 게시물에 여러 댓글 여러 회원)는 deleteAllByPostId로 삭제하고

postLike(포스트에는 댓글과 좋아요가 있음)도 deleteAllbyPostId로 삭제를 하고

comment(댓글은 게시글과 게시글좋아요와 댓글좋아요가 있음)도 deleteAllbyPostId로 삭제를하고

 

Likecomment는 ...

 

comment와 likecomment 뿐입니다.

post를 지울때 likecomment를 cascade를 사용하지 않고 지운다면

post의 모든 comment의 id값을 각각 불러와서 그에 맞는 like값을 deleteAllbycommentId를 해야하는데

commentlist를 조회해서 그들의 Id값을 뽑아서 그들의 Id값에 따른 Likelist를 찾아서 삭제를 해줘야합니다.

그래서 제가 생각한 것은 comment와 Likecomment만 cascade.remove를 사용해도 되지 않겠냐는 겁니다.

 

댓글과 댓글좋아요의 관계에서 댓글좋아요는 댓글만을 참조하기 때문에 cascade를 사용해도 되겠다고 판단했습니다.

 

저는 중첩 for문 돌리는 것을 그렇게 좋아하는 편은 아닙니다.  

 

 

CASCADE를 사용한다면,

연관관계설정을 다시 한 후 해야겠고요.

 

기술매니저님께 여쭤본 결과, where in 이라는 방법으로 N+1 을 해결 할 수 있다고 합니다.

 

각각의 방법을 비교해서 정리해보라는 조언을 주셨습니다. 각 방법 별로 성능이 달라질 수도 있다고 합니다.

내일은 이것만 파야겠네요.

 

 

일단 끝.

Spring 강의 좀 보다가 자야겠습니다.

 

 

CORS(Cross-Origin Resource Sharing)

 

 

[WEB] 📚 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏

악명 높은 CORS 에러 메세지 웹 개발을 하다보면 반드시 마주치는 멍멍 같은 에러가 바로 CORS 이다. 웹 개발의 신입 신고식이라고 할 정도로, CORS는 누구나 한 번 정도는 겪게 된다고 해도 과언이

inpa.tistory.com

 

CORS는 위의 블로그 글을 참조하면 됩니다.

 

 

+ Recent posts