네로개발일기

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

'programming language/Java'에 해당되는 글 16건


반응형

DTO(Data Transfer Object)

계층(Layer)간 데이터를 교환하기 위한 객체

DTO의 특징

1. DTO는 데이터 접근 메서드 외 기능을 가지고 있지 않는다. (getter, setter 메서드 외에 비즈니스 로직을 가지지 않는다.)

- 정렬, 직렬화 등 데이터 표현을 위한 기능은 가질 수 있다.

2. 값을 유연하게 변경할 수 있다. (가변성, mutable)

3. 데이터 캡슐화를 통해 유연한 대응이 가능하다.

- 데이터 요청 수 감소 효과

 

VO (Value Object)

값을 가지는 객체

VO의 특징

1. 변하지 않는 값을 가지는 객체(불변성, immutable)

- 값이 변하지 않음을 보장하며 코드의 안정성과 생산성을 높임

2. 값이 같다면 동일한 객체

- 각 객체를 비교하는데 사용되는 ID가 없음

- 같은 객체인지 판단하기 위해 각 속성들의 값을 비교함

- equals() 메서드와 hashCode() 메서드를 오버라이드해서 객체 비교를 구현함

 

공통점 및 차이점

공통점

- 레이어 간 데이터를 전달할 때 사용 가능

- VO는 불변을 보장하기 때문에 데이터 전달 용도로 사용 가능

차이점

DTO VO
값이 변할 수 있음 (가변 객체) 값이 변하지 않음 (불변 객체)
레이어와 레이어 사이에서 사용 가능 모든 레이어에서 사용 가능
내부의 속성(필드)값이 같아도 다른 객체로 식별 내부의 속성(필드)값들이 같다면 같은 객체로 식별
데이터 접근 이외의 기능을 가지지 않음 특정 비즈니스 로직을 가질 수 없음

 

 참고 

https://parkadd.tistory.com/53

 

DTO와 VO 둘 의 사실과 오해 (그리고 Entity)

보통 DTO == VO 즉, DTO와 VO는 혼용해도 된다, DTO와 VO는 같은것이다. 라는 오해가 많이 있습니다. (그런 오해를 가진 분들을 위한 글입니다!! 이미 알고 계신분은 글을 읽고 검수 해주시면 더욱 감사

parkadd.tistory.com

 

728x90
반응형
blog image

Written by ner.o

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

반응형

필요한 데이터를 저장하기 위해 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

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

반응형

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

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

반응형

Wrapper Class 

1. 기본 자료형 클래스

byte, short, int long, float, double, boolean, char

기본 자료형을 객체로 변환하기 위해서, 기본 자료형 각각에 대한 클래스가 Java 표준 라이브러리(java.lang 패키지)에 포함되어 있다.

  • byte - Byte
  • short - Short
  • int - Integer
  • long - Long
  • float - Float
  • double - Double
  • boolean - Boolean
  • char - Character

기본 자료형 클래스에는 equals 메소드가 재정의되어있음.

Integer x = new Integer(3); 
Integer y = new Integer(3); 
System.out.println(x.equals(y)); // true 출력!!!!

2. Auto-boxing & Auto-unboxing

래퍼 클래스는 산술 연산을 위해 정의된 클래스가 아니므로, 인스턴스에 저장된 값을 변경할 수 없다.

단지, 값을 참조하기 위해 새로운 인스턴스를 생성하고, 생성된 인스턴스의 값만을 참조할 수 있다.

Auto-boxing

Object a1 = 3;
Object a2 = new Integer(3);


둘은 같은 코드
컴파일러가 윗 코드를 아래코드로 자동으로 생성 Autoboxing

 

Auto-unboxing

Integer i1 = new Integer(3); 
int i2 = i1;
int i2 = i1.intValue();

 

3. nullable integer

null 값이 가능한 int값을 java 변수에 대입하려면 기본 자료형이 int 변수를 사용할 수 없고 Integer 객체 참조 변수를 사용해야한다.

728x90
반응형
blog image

Written by ner.o

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