네로개발일기

개발자 네로의 개발 일기, 자바를 좋아합니다 !

'programming language'에 해당되는 글 67건


반응형

필요한 데이터를 저장하기 위해 Map<String, Object>를 사용하는 경우가 있다.

 

Map이 아닌 DTO 클래스를 사용해야 하는 이유

[Map을 사용할 때의 단점]

1. 컴파일 에러를 유발할 수 없음.

2. String 텍스트를 Key로 사용함.

3. 가독성이 떨어짐.

4. 타입캐스팅 비용이 발생함.

5. 불변성을 확보할 수 없음.

 

1. 컴파일 에러를 유발할 수 없음

Map의 Value는 Object 타입이다. 그리고 Object 클래스는 최상위 클래스이기 때문에 어떠한 데이터도 넣을 수 있다. Object를 사용할 때의 문제는 어떠한 데이터도 받아들일 수 있기 때문에 타입체크를 할 수 없다는 것이다. 잘못된 타입을 넣어줘도 컴파일 에러를 유발하지 않는다.

 

2. String 텍스트를 Key로 사용함

단순 String을 사용하는 것은 문제가 발생할 여지가 항상 열려있다는 것이다. 굳이 문제의 가능성을 열어두고 이로 인해 불필요한 시간 낭비의 여지를 줄 필요가 없다. DTO를 이용하면 이러한 문제를 해결할 수 있다.

 

3. 가독성이 떨어짐

Map을 사용하는 구조는 가독성이 떨어진다. 어떠한 데이터를 가지고 있는지를 확인할 때는 Map보다 DTO를 확인하는 것이 직관적이고 좋다. 만약 Map<String, Object>를 본다면, 우리가 받는 Key 값은 무엇이고, Value 값은 무엇이며 어떠한 타입인지를 파악하기가 쉽지않다. 만약 Map안에 또 다른 Map이 들어있다면 이러한 문제는 더욱 심각해진다. 결국 Map으로 작성된 코드를 이해하기 위해서는 불필요한 코드 리딩 시간이 필요하고 생산성이 떨어지게 된다.

 

4. 타입캐스팅 비용이 발생함

Map에 있는 데이터를 꺼내서 사용하기 위해서는 반드시 타입 캐스팅을 해야한다.

String name = (String) map.get("name");

이러한 타입캐스팅은 당연히 컴퓨팅 비용을 필요로 한다. 만약 꺼내야 하는 데이터가 많다면 이러한 비용은 더욱 증가하게 된다. 불필요한 타입 캐스팅 비용을 줄이기 위해서도 DTO를 사용하는 것이 좋다.

 

5. 불변성을 확보할 수 없음

Map을 사용하면 해당 데이터의 불변성을 확보할 수 없다. 만약 누군가가 실수로 put 코드를 추가하였다면 기존의 데이터는 없어지고 잘못된 데이터로 덮어 씌워진다.

Map<String, Object> map = new HashMap<>();
map.put("name", "jiyoon");

// 불변성을 확보할 수 없고 값이 변경될 수 있음.
map.put("name", "nero");

Map을 사용하면 불변성을 확보할 수 없으니 DTO를 사용하는 것이 좋다.

 

 

 

Map을 사용하면 위와 같은 단점들을 안게 된다. 이러한 이유로 DTO(Data Transfer Object)라는 데이터 전달 클래스를 사용하는 것이 좋다. DTO를 사용하면 추가적으로 정적 팩토리 메소드를 구현하여 많은 이점을 얻을 수도 있고, 빌더 패턴도 적용할 수 있어 상당히 유용하다. 실제로 업무를 하다보면 이러한 단점을 더욱 잘 체감할 수 있다.

물론 개인적으로 매우 제한적인 경우에 Map을 사용하기도 하는데, 현재도 그렇고 미래에도 절대적으로 단일 Key값을 갖는 케이스라면 컨트롤러에서 Collections.singletonMap로 응답을 반환하기도 한다. 그 외에도 Map을 사용해서 위에서 얘기한 단점들이 부각되지 않거나 유지보수성을 떨어뜨리지 않는다면 Map을 사용해서 오히려 좋아지는 케이스도 있다. 그렇기 때문에 상황을 고려해보았을 때, Map을 사용하여도 위에 적힌 단점들이 부각되지 않거나 오히려 이점을 얻을 수 있는 경우에는 Map을 사용해도 괜찮다. 하지만 위에서 얘기했던 단점들이 드러나는 상황이라면 Map보다는 DTO를 이용하는 것을 권장한다.



 출처 

https://mangkyu.tistory.com/164

 

[Java] Map보다 DTO 클래스를 사용해야 하는 이유

필요한 데이터를 저장하기 위해 Map 를 사용하는 개발자들이 있습니다. 하지만 Map을 사용하면 너무 많은 단점들을 안게 되는 것 같아서, 왜 Map이 아닌 DTO 클래스를 사용해야 하는지에 대해 정리

mangkyu.tistory.com

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

nullable한 두 개의 String의 equality 비교를 어떻게 null safe하게 할 수 있을까?

 

java.util.Objects.equals(Object, Object)

Java7부터 java.utils.Objects의 static 메서드 equals(Object, Object)를 사용할 수 있다. 이 메서드는 둘다 null이면 true를, 둘 중 하다가 null이면 false를, 그렇지 않으면 equals의 결과를 리턴한다.

 

nullable한 객체에서 메소드를 호출하는게 아니라 static 메소드이므로 NullPointerException의 발생 가능성이 없고 별도의 라이브러리를 추가할 필요가 없다는 장점이 있다.

public final class Objects {

    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }
}

StringUtils.equals(CharSequence, CharSequence) - Apache Commons

다른 방법으로는 apache commons 라이브러리의 StringUtils가 제공하는 static 메소드 equals()를 사용할 수 있다.

public class StringUtils {

    public static boolean equals(CharSequence cs1, CharSequence cs2) {
        if (cs1 == cs2) {
            return true;
        } else if (cs1 != null && cs2 != null) {
            if (cs1 instanceof String && cs2 instanceof String) {
                return cs1.equals(cs2);
            } else {
                return cs1.length() == cs2.length() && CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
            }
        } else {
            return false;
        }
    }
}

이를 사용하려면 apache commons 라이브러리 의존성을 추가해야한다.

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

scp 명령어

ssh 원격 접속 프로토콜을 기반으로 Secure Copy의 약자로 원격지에 있는 파일과 디렉터리를 보내거나 가져올 때 사용하는 파일 전송 프로토콜이다. 네트워크가 연결되어 있는 환경에서 ssh와 동일한 22번 포트와 identity file을 사용해서 파일을 송수신하기 때문에 보안적으로 안정된 프로토콜이다.

Local 로컬에서 Remote 원격지

1. 단일 파일을 원격지로 보낼 때

# scp [옵션] [파일명] [원격지_id]@[원격지_ip]:[파일이 저장될 경로]
# scp testfile2 root@192.168.12.14:/tmp/testclient

 

2. 복수의 파일을 원격지로 보낼 때

# scp [옵션] [파일명1] [파일명2] [원격지_id]@[원격지_ip]:[파일이 저장될 경로]
# scp testfile1 testfile2 root@192.168.12.52:/tmp/testclient

 

3. 여러 파일을 포함하고 있는 디렉터리를 원격지로 보낼 때 (-r 옵션을 사용한다)

# scp [옵션] [디렉터리 이름] [원격지_id]@[원격지_ip]:[파일이 저장될 경로]
# scp -r testdirectory root@192.168.12.52:/tmp/testclient

 

r 디렉터리 내 모든 파일/디렉터리 복사 scp -r
p (소문자) 원본 권한 속성 유지 복사 scp -p
P (대문자) 포트 번호 지정 복사 scp -P [포트번호] 
c (소문자) 압축 복사 scp -c 
v 과정 출력 복사 scp -v
a 아카이브 모드 복사 scp -a

 

Remote 원격지에서 Local 로컬

1. 단일 파일을 원격지에서 로컬로 가져올 때

# scp [옵션] [원격지_id]@[원격지_ip]:[원본 위치] [로컬 서버에 저장될 경로]
# scp root@192.168.14.12:/tmp/testclient/testfile1 /tmp

 

2. 복수의 파일을 원격지에서 로컬로 가져올 때

# scp [옵션] [원격지_id]@[원격지_ip]:[원본 위치1] [원본 위치2] [로컬 서버에 저장될 경로]
# scp root@192.168.14.12:"/tmp/testclient/testfile1 /tmp/testclient/testfile2" /tmp

 

3. 여러 개의 파일을 포함하는 디렉터리 원격지에서 로컬로 가져올 때

# scp [옵션] [원격지_id]@[원격지_ip]:[디렉터리 위치] [로컬 서버에 저장될 경로]
# scp -r root@192.168.14.12:/tmp/testclient/test /tmp
728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

인덱스(INDEX)

검색 속도를 높이기 위한 색인 기술이다.

보통 인덱스는 일반적으로 SELECT 쿼리의 WHERE에 사용할 컬럼에 대해 효율적인 검색을 위해 사용하거나, 다른 테이블과의 JOIN에 사용된다. (주로 효율적인 검색을 위해 사용된다.)

일반적으로 SQL 서버에 데이터를 저장할 때는 내부적으로 아무런 순서없이 저장한다. 이때, 데이터 저장영역은 Heap이다.

 

Heap에서는 인덱스가 없는 테이블의 데이터를 찾을 때, 전체 데이터 페이지의 처음 레코드부터 끝 페이지 마지막 레코드까지 모두 조회하게 된다.

이러한 방식을 풀 스캔(Full Scan) 또는 테이블 스캔(Table Scan) 검색 방식이라고 한다.

 

검색 속도 향상을위해서 인덱스를 사용해야 한다.

 

[ 어떤 컬럼에 Index를 설정해야 하는가? ]

1. 핵심 기준 4가지

- 카디널리티(Cardinality)

카디널리티가 높으면(한 컬럼이 갖고 있는 값의 중복도가 낮으면) 인덱스 설정에 좋은 컬럼이다. 

- 선택도 (Selectivity)

선택도가 낮으면(한 컬럼이 갖고 있는 값 하나로 적은 row가 찾아지면) 인덱스 설정에 좋은 컬럼이다.

- 조회 활용도

조회 활용도가 높으면 인덱스 설정에 좋은 컬럼이다.

- 수정 빈도

수정 빈도가 낮으면 인덱스 설정에 좋은 컬럼이다. (인덱스도 테이블이기 때문에 인덱스로 지정된 컬럼의 값이 바뀌게 되면 인덱스 테이블도 새롭게 갱신되어야 한다.)

 

2. 그 밖의 Index 명시 사항

- WHERE 절에 자주 사용되는 컬럼에 사용하기

- LIKE와 사용할 경우 %를 뒤에 사용하기

- ORDER BY 에 자주 사용되는 컬럼에 사용하기

- JOIN에 자주 사용되는 컬럼에 사용하기

- 데이터 변경이 잦은 컬럼에는 사용하지 않기

 

[ Index를 무조건 많이 설정하면? ]

1. 인덱스 설정 시, 데이터 베이스에 할당된 메모리를 사용하여 테이블 형태로 저장하게 된다. 즉, 인덱스가 많아지면 데이터베이스의 메모리를 많이 잡아먹게 된다.

2. 인덱스로 지정된 컬럼의 값이 바뀌게 되면 인덱스 테이블이 갱신되어야 하므로 느려질 수 있다.

 

전체적인 데이터베이스의 성능 부하를 초래할 수 있다.

 

[ 설정된 Index가 DML에 미치는 영향 ] 

* SELECT

Index는 주로 SELECT 쿼리에서 성능이 잘 나온다.

* UPDATE, DELETE

인덱스로 설정된 컬럼에 대해 조건(WHERE)을 사용할 수도 있는 UPDATE, DELETE 사용 시 조회에서는 성능이 크게 저하되지 않는다.

* INSERT

INSERT의 경우 효율이 좋지 않다. 새로운 데이터를 추가하면서 인덱스가 설정되어 있던 컬럼의 테이블도 같이 수정되어야 하기 때문이다.

 

[ Single Column Index와 Multi Column Index의 비교 ]

- Multi Column Index의 장점

질의(SQL) 컬럼이 모두 조합 인덱스에 있는 경우, 물리적인 데이터 블록을 읽을 필요가 없다. (인덱스 테이블만 읽으면 된다.)

- Multi Column Index를 고려해야 하는 경우

WHERE 절에서 AND 연산자에 의해 자주 같이 질의되는 컬럼인 경우

 

[ Index 특징 요약 ]

- 검색 (SELECT) 속도 향상

- 인덱스 테이블을 위한 추가 공간과 시간 필요

- INSERT, UPDATE, DELETE가 경우에 따라 성능 하락 발생

 

 출처 

https://velog.io/@jwpark06/%ED%9A%A8%EA%B3%BC%EC%A0%81%EC%9D%B8-DB-index-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

Java 파일 복사하는 방법

1. FileInputStream, FileOutputStream

2. Files.copy()

3. FileChannel

4. Apache Commons IO

 

1. FileInputStream, FileoutputStream / BufferedInputStream, BufferedOutputStream

FileInputStream으로 파일을 읽고, FileOutputStream으로 새로운 파일을 쓴다.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream
import java.io.IOExeption;

public class CopyFile {

    public static void main(String[] args) {
        File file = new File ("/tmp/text.txt");
        File newFile = new File ("/tmp/new_text.txt");
        
        BufferedInputStream input = null;
        BufferedOuputStream output = null;
        try {
            input = new BufferedInputStream(new FileInputStream(file));
            output = new BufferedOutputStream(new FileOutputStream(newFile));
            
            byte[] readBuffer = new byte[1024];
            while(input.read(readBuffer, 0, readBuffer.length) != -1). {
                output.write(readBuffer);
            }
        } catch (Exception e) {
            // log
        } finally {
            input.close();
            output.close();
        }
    }
}

 

2. Files.copy()

java.nio.file.Files 클래스는 파일을 복사할 수 있는 copy() 메서드를 제공한다.

public static Path copy(Path source, Path target, CopyOption... options)

 파라미터 

- source: source file path

- target: target file path

- options

1. REPLACE_EXISTING: target 파일이 존재하면 덮어쓴다.

2. COPY_ATTRIBUTES: 파일 속성을 복사한다.

3. NOFOLLOW_LINKS: 파일이 symbolic link이면 링크 대상이 아닌, symbolic link 자체가 복사된다.

 

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

public class CopyFile {

    public static void main(String[] args) {
        File source = new File("/tmp/text.txt");
        File target = new File("/tmp/new_text.txt");
        
        Files.copy(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }
}

 

3. FileChannel

FileChannel 클래스는 파일의 읽기, 쓰기, 매핑 등을 위한 채널을 제공한다.

transferForm(), transferTo() 메서드를 사용하여 내용을 복사할 수 있다.

public abstract long transferForm(ReadableByteChannel src, long position, long count);

src 파일 채널로부터 position 위치부터 count 사이즈만큼 데이터를 복사한다.

public abstract long transferTo(long position, long count, WritableByteChannel target);

target 파일 채널로 position 위치부터 count 사이즈만큼 데이터를 복사한다.

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;

public class CopyFile {

    public static void main(String[] args) throw IOException {
        RandomAccessFile file = new RandomAccessFile("/tmp/text.txt", "r");
        RandomAccessFile newFile = new RandomAccessFile("/tmp/new_text.txt", "rw");
        
        FileChannel source = file.getChannel();
        FileChannel target = newFile.getChannel();
        
        source.transferTo(0, source.size(), target); 
        // 또는 
        // target.transferFrom(source, 0, source.size());
    }
}

 

4. Apache Commons IO

Apache Commons IO 라이브러리를 사용한다. (FileUtils 클래스의 copyFile() 메서드를 사용한다.)

public static void copyFile(File srcFile, File destFile);

 

Apache Commons IO를 사용하기 위해서 아래 dependency를 추가한다.

<dependency>
    <groupId>commons-io</groupId> 
    <artifactId>commons-io</artifactId>
    <version>2.9.0</version>
</dependency>
import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

public class CopyFile {

    public static void main(String[] args) throws IOException {
    
        File file = new File("/tmp/text.txt");
        File newFile = new File("/tmp/new_text.txt");
        
        FileUtils.copyFile(file, newFile);
    }
}

=> 비슷하게 Spring frameworkdp FileCopyUtils 클래스가 존재한다.

// FileCopyUtils.copy()
public static int copy(File in, File out);
public static int copy(Reader in, Writer out);
// ...

 

 

참고

https://hianna.tistory.com/604

 

[Java] 파일 복사하기

Java에서 파일을 다루는 방법을 알아보고 있습니다. [Java] 텍스트 파일 읽기 ( FileReader, BufferedReader, Scanner, Files ) [Java] 파일 생성하는 3가지 방법 (File, FileOutputStream, Files) [Java] 파일,..

hianna.tistory.com

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !