1101 - 1107


# 1101 - 1107

# 1101 - HTTP API์™€ REST API

HTTP API์™€ REST API๋Š” ์‚ฌ์‹ค ๊ฑฐ์˜ ๊ฐ™์€ ์˜๋ฏธ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
ํ•˜์ง€๋งŒ ๋””ํ…Œ์ผํ•˜๊ฒŒ ๋“ค์–ด๊ฐ€๋ฉด ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

  • HTTP API๋Š” HTTP๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์„œ๋กœ ์ •ํ•ด๋‘” ์ŠคํŽ™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›์œผ๋ฉด ํ†ต์‹ ํ•˜๋Š” ๊ฒƒ, ์ƒ๋‹นํžˆ ๋„“์€ ์˜๋ฏธ๋กœ ์‚ฌ์šฉ
  • ๋ฐ˜๋ฉด, REST API๋Š” HTTP API์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ œ์•ฝ ์กฐ๊ฑด์ด ์ถ”๊ฐ€๋œ๋‹ค.
    • ์ž์›์˜ ์‹๋ณ„
    • ๋ฉ”์„ธ์ง€๋ฅผ ํ†ตํ•œ ๋ฆฌ์†Œ์Šค ์กฐ์ž‘
    • ์ž๊ธฐ์„œ์ˆ ์  ๋ฉ”์„ธ์ง€
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ์— ๋Œ€ํ•œ ์—”์ง„์œผ๋กœ์„œ ํ•˜์ดํผ๋ฏธ๋””์–ด

์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ์ง€๋งŒ ๋Œ€ํ‘œ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ์–ด๋ ค์šด ๋ถ€๋ถ„์ด ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์ด๋‹ค. ์ด๊ฒƒ์€ HTML์ฒ˜๋Ÿผ ํ•˜์ดํผ๋งํฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด์„œ ๋‹ค์Œ์— ์–ด๋–ค API๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ํ•ด๋‹น ๋งํฌ๋ฅผ ํ†ตํ•ด์„œ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ ๋ถ€๋ถ„์„ ์™„๋ณ€ํ•˜๊ฒŒ ์ง€ํ‚ค๋ฉด์„œ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์„ RESTful API๋ผ๊ณ  ํ•œ๋‹ค. ์‹ค๋ฌด์—์„œ ์ด๋Ÿฐ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐญ๋ผํ•˜๋Š” ๊ฒƒ์€ ํ˜„์‹ค์ ์œผ๋กœ ์–ด๋ ต๊ณ , ๋˜ ์ถ”๊ฐ€ ๊ฐœ๋ฐœ ๋น„์šฉ๋Œ€๋น„ ํšจ๊ณผ๊ฐ€ ๋ถ€์กฑํ•˜๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด๋ฏธ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ํ•ด๋‹น ์กฐ๊ฑด์„ ์ง€ํ‚ค์ง€ ์•Š์•„๋„ REST API๋ผ๊ณ  ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, HTTP API๋‚˜ REST API๋ฅผ ๊ฑฐ์˜ ๊ฐ™์€ ์˜๋ฏธ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์•ž์„œ ์ด์•ผ๊ธฐํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ ์—„๊ฒฉํ•˜๊ฒŒ ์œ„์˜ ๋‚ด์šฉ๋“ค์„ ๋ชจ๋‘ ์ง€์ผœ์•ผ RESTfulํ•œ API๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.


# 1102 - ์ž๋ฐ” var ํ‚ค์›Œ๋“œ

Java 10์—์„œ ๋„์ž…๋œ var๋Š” ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ๋•Œ ํƒ€์ž…์„ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํƒ€์ž…์„ ์ถ”๋ก ํ•œ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ String ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์—ฌ ๋ฒˆ์ˆ˜์— ํƒ€์ž…์„ ์ง€์ •ํ•ด ์ค€๋‹ค. Kotlin๊ณผ ๊ฐ™์ด ํƒ€์ž… ์ถœ๋ก ์„ ์ง€์›ํ•˜๋Š” ์–ธ์–ด์™€ ๊ฐ™์ด ์ง€์›ํ•œ๋‹ค.

var string = "Hello, World";
  • ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ถ”๋ก ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, Runtime์— ์ถ”๊ฐ€ ์—ฐ์‚ฐ์„ ํ•˜์ง€ ์•Š์•„ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ฃผ์ง€๋Š” ์•Š๋Š”๋‹ค.
  • Java์—์„œ var๋Š” ์ง€์—ญ ๋ณ€์ˆ˜์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋”ฐ. ๋˜ํ•œ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํƒ€์ž…์„ ์ถ”๋ก ํ•  ์ˆ˜ ์—†๋Š” ์• ๋งคํ•œ ์ƒํ™ฉ์ผ ๋•Œ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

# var๋กœ ๋ณ€์ˆ˜ ์„ ์–ธ

  • Java 9์ดํ•˜
String str = "Hello, World";
  • Java 10
var str = "Hello, World";

if(str instanceof String) {
    System.out.println("This is a String : " + str);
}

// This is a String : Hello, World

๋‹ค๋ฅธ ํด๋ž˜์Šค๋“ค๋„ var๋กœ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.

var list = new ArrayList<String>();

if (list instanceof ArrayList) {
    System.out.println("This is a ArrayList");
}

// This is a ArrayList

์—ฌ๊ธฐ์„œ list๋Š” ArrayListํƒ€์ž…์œผ๋กœ ์„ ์–ธ๋˜๋ฉฐ, var list = new ArrayList();๋กœ ์„ ์–ธํ•˜๋ฉด ํƒ€์ž…์€ ArrayList๊ฐ€ ๋œ๋‹ค.

# ๋ฐ˜๋ณต๋ฌธ์—์„œ ์‚ฌ์šฉ

int[] arr = {1, 2, 3};

for (var n : arr) {
    System.out.println("n : " + n);
}

// n : 1
// n : 2
// n : 3

# ์ œ์•ฝ ์‚ฌํ•ญ

  • ์ง€์—ญ ๋ณ€์ˆ˜์—์„œ๋งŒ ์‚ฌ์šฉ
  • ์ดˆ๊ธฐํ™” ํ•„์š”
  • null๋กœ ์ดˆ๊ธฐํ™”ํ•  ์ˆ˜ ์—†์Œ
  • ๋ฐฐ์—ด์— ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ
  • Lambda์— ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ

# 1103 - BigDecimal

์ž๋ฐ”๋Š” IEEE 754 ๋ถ€๋™ ์†Œ์ˆ˜์  ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋–„๋ฌธ์—
์ •ํ™•ํ•œ ์‹ค์ˆ˜๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ์ตœ๋Œ€ํ•œ ์™„๋ฒฝ์— ๊ฐ€๊น๊ธฐ๋ฅผ ๋ฐ”๋ผ๋Š” ๊ทผ์‚ฌ์น˜ ๊ฐ’์„ ์ €์žฅํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ๊ธˆ์œต๊ถŒ์—์„œ ๋‹ฌ๋Ÿฌ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ double์„ ์ด์šฉํ•œ๋‹ค๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ์œ„ํ•ด ๋ถ€๋™ ์†Œ์ˆซ์  ๋ฐฉ์‹์ด ์•„๋‹Œ, ์ •์ˆ˜๋ฅผ ์ด์šฉํ•ด ์‹ค์ˆ˜๋ฅผ ํ‘œํ˜„ํ•˜๋Š” java.math.BigDecimalํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

# BigDecimal์ด๋ž€?

  • BigDecimal์€ Java ์–ธ์–ด์—์„œ ์ˆซ์ž๋ฅผ ์ •๋ฐ€ํ•˜๊ฒŒ ์ €์žฅํ•˜๊ณ  ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์†Œ์ˆ˜์ ์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ํฌ๊ธฐ๊ฐ€ ํฐ ํƒ€์ž…์ธ double์€ ์†Œ์ˆ˜์ ์˜ ์ •๋ฐ€๋„์— ํ•œ๊ณ„๊นŒ ์žˆ์–ด ๊ฐ’์ด ์œ ์‹ค๋  ์ˆ˜ ์žˆ๋‹ค.
  • Java ์–ธ์–ด์—์„œ ๋ˆ๊ณผ ์†Œ์ˆ˜์ ์„ ๋‹ค๋ฃฌ๋‹ค๋ฉด BigDecimal์€ ์„ ํƒ์ด ์•„๋‹ˆ๋ผ ํ•„์ˆ˜์ด๋‹ค.
  • BigDecimal์˜ ์œ ์ผํ•œ ๋‹จ์ ์€ ๋Š๋ฆฐ ์†๋„์™€ ๊ธฐ๋ณธ ํƒ€์ž…๋ณด๋‹ค ์กฐ๊ธˆ ๋ถˆํŽธํ•œ ์‚ฌ์šฉ๋ฒ• ์ด๋‹ค.

# double, ๋ฌด์—‡์ด ๋ฌธ์ œ์ธ๊ฐ€?

  • ์†Œ์ˆ˜์  ์ดํ•˜์˜ ์ˆ˜๋ฅผ ๋‹ค๋ฃฐ ๋•Œ double ํƒ€์ž…์€ ์‚ฌ์น™์—ฐ์‚ฐ์‹œ ๊ธฐ๋Œ€ ๊ฐ’๊ณผ ๋‹ค๋ฅธ ๊ฐ’์„ ์ถœ๋ ฅํ•œ๋‹ค. ์ด์œ ๋Š” double ํƒ€์ž…์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์ˆ˜๋ฅผ ์ €์žฅํ•  ๋•Œ ์ด์ง„์ˆ˜์˜ ๊ทผ์‚ฌ์น˜๋ฅผ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ €์žฅ๋œ ์ˆ˜๋ฅผ ๋‹ค์‹œ ์‹ญ์ง„์ˆ˜๋กœ ํ‘œํ˜„ํ•˜๋ฉด์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. BigDecimal ํƒ€์ž…์€ ๋‚ด๋ถ€์ ์œผ๋กœ ์ˆ˜๋ฅผ ์‹ญ์ง„์ˆ˜๋กœ ์ €์žฅํ•˜์—ฌ ์•„์ฃผ ์ž‘์€ ์ˆ˜์™€ ํฐ ์ˆ˜์˜ ์—ฐ์‚ฐ์— ๋Œ€ํ•ด ๊ฑฐ์˜ ๋ฌดํ•œํ•œ ์ •๋ฐ€๋„๋ฅผ ๋ณด์žฅํ•œ๋‹ค.
double a = 10.0000;
double b = 3.0000;

// ๊ธฐ๋Œ€๊ฐ’: 13
// ์‹ค์ œ๊ฐ’: 13.000001999999999
a + b;

// ๊ธฐ๋Œ€๊ฐ’: 7
// ์‹ค์ œ๊ฐ’: 6.999999999999999
a - b;

// ๊ธฐ๋Œ€๊ฐ’: 30
// ์‹ค์ œ๊ฐ’: 30.000013000000997
a * b;

// ๊ธฐ๋Œ€๊ฐ’: 3.33333...
// ์‹ค์ œ๊ฐ’: 3.333332555555814
a / b;

# BigDecimal ์‚ฌ์šฉ

# BigDecimal ๊ธฐ๋ณธ ์šฉ์–ด

  • precision : ์ˆซ์ž๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์ „์ฒด ์ž๋ฆฌ์ˆ˜๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ํŽธํ•˜๋‚˜, ์ •ํ™•ํ•˜๊ฒŒ ํ’€์ดํ•˜๋ฉด ์™ผ์ชฝ๋ถ€ํ„ฐ 0์ด ์•„๋‹Œ ์ˆ˜๊ฐ€ ์‹œ์ž‘ํ•˜๋Š” ์œ„์น˜๋ถ€ํ„ฐ ์˜ค๋ฅธ์ชฝ๋ถ€ํ„ฐ 0์ด ์•„๋‹Œ ์ˆ˜๋กœ ๋๋‚˜๋Š” ์œ„์น˜๊นŒ์ง€์˜ ์ด ์ž๋ฆฌ์ˆ˜์ด๋‹ค. unscale๊ณผ ๋™์˜์–ด์ด๋‹ค. (ex: 012345.67890์˜ precision์€ 11์ด ์•„๋‹Œ9์ด๋‹ค.)
  • scale : ์ „์ฒด ์†Œ์ˆ˜์  ์ž๋ฆฌ์ˆ˜๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ํŽธํ•˜๋‚˜, ์ •ํ™•ํ•˜๊ฒŒ ํ’€์ดํ•˜๋ฉด ์†Œ์ˆ˜์  ์ฒซ์จฐ ์ž๋ฆฌ๋ถ€ํ„ฐ ์˜ค๋ฅธ์ชฝ๋ถ€ํ„ฐ 0์ด ์•„๋‹Œ ์ˆ˜๋กœ ๋๋‚˜๋Š” ์œ„์น˜๊นŒ์ง€์˜ ์ด ์†Œ์ˆ˜์  ์ž๋ฆฌ์ˆ˜์ด๋‹ค. fraction๊ณผ ๋™์˜์–ด์ด๋‹ค. (ex: 012345.67890์˜ scale์€ 4์ด๋‹ค. ํ•˜์ง€๋งŒ 0.00, 0.0์˜ scale์€ ๋ชจ๋‘ 1์ด๋‹ค.) BigDecimal์€ 32bit์˜ ์†Œ์ˆ˜์  ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง„๋‹ค.
  • DECIMAL128: IEEE 754-2008์— ์˜ํ•ด ํ‘œ์ค€ํ™”๋œ, ๋ถ€ํ˜ธ์™€ ์†Œ์ˆ˜์ ์„ ์ˆ˜์šฉํ•˜๋ฉฐ, ์ตœ๋Œ€ 34์ž๋ฆฌ๊นŒ์ง€ ํ‘œํ˜„ ๊ฐ€๋Šฅํ•œ 10์ง„์ˆ˜๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•์‹์ด๋‹ค. 2018๋…„ ๋ฏธ๊ตญ ์ •๋ถ€์˜ ์ด ๋ถ€์ฑ„์•ก์ด 15์กฐ 7์ฒœ 500์–ต ๋‹ฌ๋Ÿฌ๋กœ ์ด 14์ž๋ฆฌ ์ž„์„ ๊ฐ์•ˆํ•˜๋ฉด, ๊ธˆ์œต๊ถŒ์—์„œ ์ฒ˜๋ฆฌ๋˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ธˆ์•ก์„ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํฌ๊ธฐ์ด๋‹ค. Java์—์„œ๋Š” BigDecimal ํƒ€์ž…์„ ํ†ตํ•ด ๊ณต์‹์ ์œผ๋กœ ์ง€์›ํ•œ๋‹ค.

# BigDecimal ๊ธฐ๋ณธ ์ƒ์ˆ˜

  • float, double ํƒ€์ž…๊ณผ ๋‹ค๋ฅด๊ฒŒ BigDecimal ํƒ€์ž…์€ ์ดˆ๊ธฐํ™”๊ฐ€ ์žฅํ™ฉํ•œ ํŽธ์ด๋‹ค. ๊ทธ๋ž˜์„œ, ์ž์ฃผ ์“ฐ๋Š” 0, 1, 100์€ ์“ฐ๊ธฐ ํŽธํ•˜๊ฒŒ ๋ฏธ๋ฆฌ ์ƒ์ˆ˜๋กœ ์ •์˜๋˜์–ด ์žˆ๋‹ค.
// ํ”ํžˆ ์“ฐ์ด๋Š” ๊ฐ’์€ ์ƒ์ˆ˜๋กœ ์ •์˜
// 0
BigDecimal.ZERO

// 1
BigDecimal.ONE

// 10
BigDecimal.TEN

# BigDecimal ์ดˆ๊ธฐํ™”

  • double ํƒ€์ž…์œผ๋กœ ๋ถ€ํ„ฐ BigDecimal ํƒ€์ž…์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ๊ฒƒ์€ ๋ฌธ์ž์—ด์˜ ํ˜•ํƒœ๋กœ ์ƒ์„ฑ์ž์— ์ „๋‹ฌํ•˜์—ฌ ์ดˆ๊ธฐํ™” ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. double ํƒ€์ž…์˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•  ๊ฒฝ์šฐ ์•ž์„œ ์‚ฌ์น™์—ฐ์‚ฐ ๊ฒฐ๊ณผ์—์„œ ๋ณธ ๊ฒƒ๊ณผ ๊ฐ™์ด ์ด์ง„์ˆ˜์˜ ๊ทผ์‚ฌ์น˜๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜์–ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅธ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
// double ํƒ€์ž…์„ ๊ทธ๋Œ€๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ๊ธฐ๋Œ€๊ฐ’๊ณผ ๋‹ค๋ฅธ ๊ฐ’์„ ๊ฐ€์ง„๋‹ค.
// 0.01000000000000000020816681711721685132943093776702880859375
new BigDecimal(0.01);

// ๋ฌธ์ž์—ด๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ์ •์ƒ ์ธ์‹
// 0.01
new BigDecimal("0.01");

// ์œ„์™€ ๋™์ผํ•œ ๊ฒฐ๊ณผ, double#toString์„ ์ด์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด๋กœ ์ดˆ๊ธฐํ™”
// 0.01
BigDecimal.valueOf(0.01);

# BigDecimal ๋น„๊ต ์—ฐ์‚ฐ

  • BigDecimal์€ ๊ธฐ๋ณธ ํƒ€์ž…์ด ์•„๋‹Œ ์˜ค๋ธŒ์ ํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ํŠนํžˆ, ๋™๋“ฑ ๋น„๊ต ์—ฐ์‚ฐ์„ ์œ ์˜ํ•ด์•ผ ํ•œ๋‹ค. double ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋˜ ์Šต๊ด€๋Œ€๋กœ ๋ฌด์˜์‹์ ์œผ๋กœ == ๊ธฐํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
BigDecimal a = new BigDecimal("2.01");
BigDecimal b = new BigDecimal("2.010");

// ๊ฐ์ฒด์˜ ๋ ˆํผ๋Ÿฐ์Šค ์ฃผ์†Œ์— ๋Œ€ํ•œ ๋น„๊ต ์—ฐ์‚ฐ์ž๋กœ ๋ฌด์˜์‹์ ์œผ๋กœ ๊ฐ’์˜ ๋น„๊ต๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋™์ž‘
// false
a == b;

// ๊ฐ’์˜ ๋น„๊ต๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ, ์†Œ์ˆ˜์  ๋งจ ๋์˜ 0๊นŒ์ง€ ์™„์ „ํžˆ ๊ฐ’์ด ๋™์ผํ•ด์•ผ true ๋ฐ˜ํ™˜
// false
a.equals(b);

// ๊ฐ’์˜ ๋น„๊ต๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ, ์†Œ์ˆ˜์  ๋งจ ๋์˜ 0์„ ๋ฌด์‹œํ•˜๊ณ  ๊ฐ’์ด ๋™์ผํ•˜๋ฉด 0, ์ ์œผ๋ฉด -1, ๋งŽ์œผ๋ฉด 1์„ ๋ฐ˜ํ™˜
// 0
a.compareTo(b);

# BigDecimal ์‚ฌ์น™ ์—ฐ์‚ฐ

  • Java์—์„œ BigDecimal ํƒ€์ž…์˜ ์‚ฌ์น™ ์—ฐ์‚ฐ ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ๋ณด๋‹ค์‹œํ”ผ double ํƒ€์ž…๋ณด๋‹ค ์žฅํ™ฉํ•˜๊ณ  ๊ท€์ฐฎ์€ ํŽธ์ด๋‹ค.
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");

// ๋”ํ•˜๊ธฐ
// 13
a.add(b);

// ๋นผ๊ธฐ
// 7
a.subtract(b);

// ๊ณฑํ•˜๊ธฐ
// 30
a.multiply(b);

// ๋‚˜๋ˆ„๊ธฐ
// 3.333333...
// java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
a.divide(b);

// ๋‚˜๋ˆ„๊ธฐ
// 3.333
a.divide(b, 3, RoundingMode.HALF_EVEN);

// ๋‚˜๋ˆ„๊ธฐ ํ›„ ๋‚˜๋จธ์ง€
// ์ „์ฒด ์ž๋ฆฌ์ˆ˜๋ฅผ 34๊ฐœ๋กœ ์ œํ•œ
// 1
a.remainder(b, MathContext.DECIMAL128);

// ์ ˆ๋Œ€๊ฐ’
// 3
new BigDecimal("-3").abs();

// ๋‘ ์ˆ˜ ์ค‘ ์ตœ์†Œ๊ฐ’
// 3
a.min(b);

// ๋‘ ์ˆ˜ ์ค‘ ์ตœ๋Œ€๊ฐ’
// 10
a.max(b);

# BigDecimal ์†Œ์ˆ˜์  ์ฒ˜๋ฆฌ

  • RoundingMode.HALF_EVEN์€ Java์˜ ๊ธฐ๋ณธ ๋ฐ˜์˜ฌ๋ฆผ ์ •์ฑ…์œผ๋กœ ๊ธˆ์œต๊ถŒ์—์„œ ์‚ฌ์šฉํ•˜๋Š” Bankers Rounding์™€ ๋™์ผํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค. ๊ธˆ์œต๊ถŒ์—์„œ๋Š” ์‹œ์Šคํ…œ ๊ฐœ๋ฐœ์‹œ ํ˜ผ๋ž€์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์š”๊ตฌ์‚ฌํ•ญ์— ๋ฐ˜์˜ฌ๋ฆผ ์ •์ฑ…์„ ๋ช…ํ™•ํžˆ ๋ช…์‹œํ•˜์—ฌ ๊ฐœ๋ฐœํ•œ๋‹ค.
// ์†Œ์ˆ˜์  ์ดํ•˜๋ฅผ ์ ˆ์‚ฌํ•œ๋‹ค.
// 1
new BigDecimal("1.1234567890").setScale(0, RoundingMode.FLOOR);

// ์†Œ์ˆ˜์  ์ดํ•˜๋ฅผ ์ ˆ์‚ฌํ•˜๊ณ  1์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
// 2
new BigDecimal("1.1234567890").setScale(0, RoundingMode.CEILING);
// ์Œ์ˆ˜์—์„œ๋Š” ์†Œ์ˆ˜์  ์ดํ•˜๋งŒ ์ ˆ์‚ฌํ•œ๋‹ค.
// -1
new BigDecimal("-1.1234567890").setScale(0, RoundingMode.CEILING);

// ์†Œ์ˆ˜์  ์ž๋ฆฌ์ˆ˜์—์„œ ์˜ค๋ฅธ์ชฝ์˜ 0 ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
// 0.9999
new BigDecimal("0.99990").stripTrailingZeros();

// ์†Œ์ˆ˜์  ์ž๋ฆฌ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•œ๋‹ค.
// ์›๋ž˜ ์†Œ์ˆ˜์  ์ž๋ฆฌ์ˆ˜๋ณด๋‹ค ์ž‘์€ ์ž๋ฆฌ์ˆ˜์˜ ์†Œ์ˆ˜์ ์„ ์„ค์ •ํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
// java.lang.ArithmeticException: Rounding necessary
new BigDecimal("0.1234").setScale(3);

// ๋ฐ˜์˜ฌ๋ฆผ ์ •์ฑ…์„ ๋ช…์‹œํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
// 0.123
new BigDecimal("0.1234").setScale(3, RoundingMode.HALF_EVEN);

// ์†Œ์ˆ˜์ ์„ ๋‚จ๊ธฐ์ง€ ์•Š๊ณ  ๋ฐ˜์˜ฌ๋ฆผํ•œ๋‹ค.
// 0
new BigDecimal("0.1234").setScale(0, RoundingMode.HALF_EVEN);
// 1
new BigDecimal("0.9876").setScale(0, RoundingMode.HALF_EVEN);

# BigDecimal ๋‚˜๋ˆ„๊ธฐ ์ฒ˜๋ฆฌ

BigDecimal b10 = new BigDecimal("10");
BigDecimal b3 = new BigDecimal("3");

// ๋‚˜๋ˆ„๊ธฐ ๊ฒฐ๊ณผ๊ฐ€ ๋ฌดํ•œ์œผ๋กœ ๋–จ์–ด์ง€๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ
// java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
b10.divide(b3);

// ๋ฐ˜์˜ฌ๋ฆผ ์ •์ฑ…์„ ๋ช…์‹œํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ
// 3
b10.divide(b3, RoundingMode.HALF_EVEN);

// ๋ฐ˜์˜ฌ๋ฆผ ์ž๋ฆฌ๊ฐ’์„ ๋ช…์‹œ
// 3.333333
b10.divide(b3, 6, RoundingMode.HALF_EVEN);

// 3.333333333
b10.divide(b3, 9, RoundingMode.HALF_EVEN);

// ์ „์ฒด ์ž๋ฆฌ์ˆ˜๋ฅผ 7๊ฐœ๋กœ ์ œํ•œํ•˜๊ณ  HALF_EVEN ๋ฐ˜์˜ฌ๋ฆผ์„ ์ ์šฉํ•œ๋‹ค.
// 3.333333
b10.divide(b3, MathContext.DECIMAL32);

// ์ „์ฒด ์ž๋ฆฌ์ˆ˜๋ฅผ 16๊ฐœ๋กœ ์ œํ•œํ•˜๊ณ  HALF_EVEN ๋ฐ˜์˜ฌ๋ฆผ์„ ์ ์šฉํ•œ๋‹ค.
// 3.333333333333333
b10.divide(b3, MathContext.DECIMAL64);

// ์ „์ฒด ์ž๋ฆฌ์ˆ˜๋ฅผ 34๊ฐœ๋กœ ์ œํ•œํ•˜๊ณ  HALF_EVEN ๋ฐ˜์˜ฌ๋ฆผ์„ ์ ์šฉํ•œ๋‹ค.
// 3.333333333333333333333333333333333
b10.divide(b3, MathContext.DECIMAL128);

// ์ „์ฒด ์ž๋ฆฌ์ˆ˜๋ฅผ ์ œํ•œํ•˜์ง€ ์•Š๋Š”๋‹ค.
// java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
b10.divide(b3, MathContext.UNLIMITED);

# BigDecimal ๋ฌธ์ž์—ด ๋ณ€ํ™˜ ์ถœ๋ ฅ

  • .setScale()์„ ์‚ฌ์šฉํ•˜์—ฌ ์†Œ์ˆ˜์  ์ž๋ฆฌ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋ฉด ์›๋ณธ์˜ ์†Œ์ˆ˜์  ๊ฐ’์€ ์ƒ์‹คํ•ด ๋ฒ„๋ฆฐ๋‹ค. ๋ฌธ์ž์—ด๋กœ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ด๋ผ๋ฉด NumberFormat ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•˜๋‹ค.
NumberFormat format = NumberFormat.getInstance();
format.setMaximumFractionDigits(6);
format.setRoundingMode(RoundingMode.HALF_EVEN);
// 0.123457
format.format(new BigDecimal("0.1234567890"));

# MySQL๊ณผ BigDecimal

  • MySQL ๋˜ํ•œ Java์™€ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. FLOAT, DOUBLE ํƒ€์ž…์— ์†Œ์ˆ˜๋ฅผ ๊ฐ€์ง„ ์ˆ˜๋ฅผ ์ €์žฅํ•  ๊ฒฝ์šฐ ์•ž์„œ์™€ ๋™์ผํ•œ ์—ฐ์‚ฐ์˜ ์ •ํ™•๋„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด DECIMAL ํƒ€์ž…์„ ์ œ๊ณตํ•œ๋‹ค.
foo DECIMAL(5,2) DEFAULT 0.00 NOT NULL
  • DECIMAL ํƒ€์ž… ์„ ์–ธ์‹œ ๊ด„ํ˜ธ ์•ˆ์˜ ์ˆซ์ž์˜ ์˜๋ฏธ๋Š” PRECISION, SCALE์„ ์˜๋ฏธํ•œ๋‹ค. (5,2)์˜ ๊ฒฝ์šฐ ์ „์ฒด ์ž๋ฆฌ์ˆ˜๋Š” 5, ์†Œ์ˆ˜์  ์ดํ•˜ ์ž๋ฆฌ์ˆ˜๋Š” 2๋กœ ์„ ์–ธํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ๊ธฐ๋ณธ์œผ๋กœ (10,0)์ด ์ ์šฉ๋œ๋‹ค. PRECISION์˜ ์ตœ๋Œ€๊ฐ’์€ 65๋กœ ์‚ฐ์—… ํ‘œ์ค€์ธ DECIMAL128์„ ์ถฉ๋ถ„ํžˆ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. SCALE์˜ ์ตœ๋Œ€๊ฐ’์€ 30์œผ๋กœ PRECISION๋ณด๋‹ค ํด ์ˆ˜ ์—†๋‹ค.
  • ๋งŒ์•ฝ, ์ง€์ •๋œ ์†Œ์ˆ˜ ์ž๋ฆฌ์ˆ˜๋ณด๋‹ค ๋งŽ์€ ๊ฐ’์„ ์ €์žฅํ•  ๊ฒฝ์šฐ, ์ง€์ •๋œ ์†Œ์ˆ˜ ์ž๋ฆฌ์ˆ˜ ์ดํ•˜๋Š” ์ ˆ์‚ฌ(floor)๋œ๋‹ค.

# JPA์—์„œ์˜ BigDecimal ์ฒ˜๋ฆฌ

  • JDBC์—์„œ MySQL/MariaDB์˜ DECIMAL ํƒ€์ž…์€ ResultSet ์ธํ„ฐํŽ˜์ด์Šค์˜ getBigDecimal(), getString() 2๊ฐœ ๋ฉ”์„œ๋“œ๋กœ ํš๋“์ด ๊ฐ€๋Šฅํ•˜๋‹ค. JPAใ„ท ๋˜ํ•œ ๋ณ„๋„์˜ ์ž‘์—… ์—†์ด ์—”ํ‹ฐํ‹ฐ ํ•„๋“œ์— BigDecimal ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋œ๋‹ค.
  • ๋งŒ์•ฝ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ €์žฅ์‹œ ์†Œ์ˆ˜์  ์ดํ•˜ ์ž๋ฆฌ์ˆ˜์™€ ๋ฐ˜์˜ฌ๋ฆผ ๋ฐฉ๋ฒ•์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ปค์Šคํ…€ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ์ œ์ž‘ํ•˜๋ฉด ๋œ๋‹ค.

# BigDecimal๊ณผ Java Stream

// POJO ๋ชฉ๋ก์—์„œ BigDecimal ํƒ€์ž…์„ ๊ฐ€์ง„ ํŠน์ • ํ•„๋“œ์˜ ํ•ฉ์„ ๋ฐ˜ํ™˜
BigDecimal sumOfFoo = fooList.stream()
    .map(FooEntity::getFooBigDecimal)
    .filter(foo -> Objects.nonNull(foo))
    .reduce(BigDecimal.ZERO, BigDecimal::add);

// ํŠน์ • BigDecimal ํ•„๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜
foolist.stream()
    .sorted(Comparator.comparing(it -> it.getAmount()))
    .collect(Collectors.toList());

// ์œ„์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ, ์ •๋ ฌ๋œ ์ƒˆ๋กœ์šด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ์›๋ณธ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ”๋กœ ์ •๋ ฌ
foolist.sort(Comparator.comparing(it -> it.getAmount()));

https://jsonobject.tistory.com/466


# 1104 - ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ(static factory method)

# ๊ฐœ์š”

๊ฐ์ฒด ์ƒ์„ฑ์„ ์บก์Šํ™”ํ•˜๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.
์ข€ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ , static์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.
์ž๋ฐ”๋กœ ์ฝ”๋”ฉํ•  ๋•Œ ํ”ํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๋Š” valueOf ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ์˜ ํ•œ ์˜ˆ๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

BigInteger answer = BigInteger.valueOf(42L); // BigInteger 42๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค

static์œผ๋กœ ์„ ์–ธ๋œ ๋ฉ”์„œ๋“œ์ด๋ฉฐ, new BigInteger(...)๋ฅผ ์€๋‹‰ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
valueOf ์™ธ์—, ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์œผ๋กœ ํ”ํžˆ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • valueOf
  • of
  • getInstance
  • newInstance
  • getType
  • newType

# Effective Java

์ดํŽ™ํ‹ฐ๋ธŒ ์ž์•„ 2ํŒ์€ "๊ทœ์น  1"์—์„œ ์ด ๊ธฐ๋ฒ•์„ ์†Œ๊ฐœํ•˜๊ณ  ์žˆ๋‹ค.
๊ทœ์น™ 1. ์ƒ์„ฑ์ž ๋Œ€์‹  ์ •์  ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด๋ผ.

  • ๋‹จ, GoF์˜ ๋””์ž์ธ ํŒจํ„ด ์ฑ…์— ๋‚˜์˜ค๋Š” ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด๊ณผ๋Š” ๋‹ค๋ฅธ ํŒจํ„ด์ด๋‹ค. ์ด๋ฆ„๋งŒ ๋น„์Šทํ•˜๋‹ค.
  • Effective Java ์ €์ž ์กฐ์Šˆ์•ผ ๋ธ”๋กœํ๋„ GoF์˜ ๋””์ž์ธ ํŒจํ„ด ์ฑ…์— ๋‚˜์˜จ ์–ด๋–ค ํŒจํ„ด๊ณผ๋„ ๋งž์•„ ๋–จ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค๋ฉฐ ์ฃผ์˜ํ•˜๋ผ๊ณ  ๋งํ•จ.

Effective Java์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์žฅ๋‹จ์ ์„ ์„ค๋ช…ํ•œ๋‹ค.

  • ์žฅ์ 
    1. ์ด๋ฆ„์ด ์žˆ์œผ๋ฏ€๋กœ ์ƒ์„ฑ์ž์— ๋น„ํ•ด ๊ฐ€๋…์„ฑ์ด ์ข‹๋‹ค.
    2. ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
    3. ํ•˜์œ„ ์ž๋ฃŒํ˜• ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
    4. ํ˜•์ธ์ž ์ž๋ฃŒํ˜•(parameterized type) ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๋•Œ ํŽธํ•˜๋‹ค.
  • ๋‹จ์ 
    1. ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋งŒ ์žˆ๋Š” ํด๋ž˜์Šค๋ผ๋ฉด, ์ƒ์„ฑ์ž๊ฐ€ ์—†์œผ๋ฏ€๋กœ ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋ชป ๋งŒ๋“ ๋‹ค.
    2. ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค๋ฅธ ์ •์  ๋ฉ”์„œ๋“œ์™€ ์ž˜ ๊ตฌ๋ถ„๋˜์ง€ ์•Š๋Š”๋‹ค.(๋ฌธ์„œ๋งŒ์œผ๋กœ ํ™•์ธํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Œ)

# ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŠน์ง•

  • ๊ฐ€๋…์„ฑ์ด ์ข‹๋‹ค.
class Character {

    int intelligence, strength, hitPoint, magicPoint;

    public Character(int intelligence, int strength, int hitPoint, int magicPoint) {
        this.intelligence = intelligence;   // ์ง€๋Šฅ
        this.strength = strength;           // ํž˜
        this.hitPoint = hitPoint;           // HP
        this.magicPoint = magicPoint;       // MP
    }

    // ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ
    public static Character newWarrior() {
        return new Character(5, 15, 20, 3);     // ์ „์‚ฌ๋Š” ํž˜๊ณผ HP๊ฐ€ ๋†’๋‹ค
    }

    // ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ
    public static Character newMage() {
        return new Character(15, 5, 10, 15);    // ๋งˆ๋ฒ•์‚ฌ๋Š” ์ง€๋Šฅ๊ณผ MP๊ฐ€ ๋†’๋‹ค
    }
}

// ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ
Character warrior = Character.newWarrior();
Character mage = Character.newMage();

// ์ƒ์„ฑ์ž
Character warrior = new Character(5, 15, 20, 3);
Character mage = new Character(15, 5, 10, 15);
  • ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
    ์‚ฌ์‹ค ์œ„์™€ ๊ฐ™์ด ๋งˆ๋ฒ•์‚ฌ์™€ ์ „์‚ฌ๋ฅผ ๋งŒ๋“œ๋Š” ์ฝ”๋“œ๋Š” ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค new Character(...)๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค.
    ๊ทธ๋Ÿฌ๋‚˜ immutable ๊ฐ์ฒด๋ฅผ ์บ์‹œํ•ด์„œ ์“ฐ๊ณ  ์žˆ๋‹ค๋ฉด ๊ตณ์ด ์ผ์ผ์ด new ๊ฐ™์€ ๋น„์‹ผ ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
    java.math.BigInteger.valueOf ์˜ˆ์ œ
public static final BigInteger ZERO = new BigInteger(new int[0], 0);

private final static int MAX_CONSTANT = 16;
private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];

static {
    /* posConst์— 1 ~ 16๊นŒ์ง€์˜ BigInteger ๊ฐ’์„ ๋‹ด๋Š”๋‹ค. */
    /* negConst์— -1 ~ -16๊นŒ์ง€์˜ BigInteger ๊ฐ’์„ ๋‹ด๋Š”๋‹ค. */
}

public static BigInteger valueOf(long val) {
    // ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค
    if (val == 0)
        return ZERO;
    if (val > 0 && val <= MAX_CONSTANT)
        return posConst[(int) val];
    else if (val < 0 && val >= -MAX_CONSTANT)
        return negConst[(int) -val];

    // ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๋ฆฌํ„ดํ•œ๋‹ค
    return new BigInteger(val);
}
  • ํ•˜์œ„ ์ž๋ฃŒํ˜• ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฆฌํ„ดํ•˜๋Š” ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ์œ ์—ฐํ•˜๊ฒŒ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    ๋‹ค์Œ์€ ์–ด๋Š ๊ฐ€์ƒ์˜ ์ธํ„ฐ๋„ท ์‡ผํ•‘๋ชฐ์—์„œ ํ• ์ธ ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ์ด๋‹ค.
class OrderUtil {

    public static Discount createDiscountItem(String discountCode) throws Exception {
        if(!isValidCode(discountCode)) {
            throw new Exception("์ž˜๋ชป๋œ ํ• ์ธ ์ฝ”๋“œ");
        }
        // ์ฟ ํฐ ์ฝ”๋“œ์ธ๊ฐ€? ํฌ์ธํŠธ ์ฝ”๋“œ์ธ๊ฐ€?
        if(isUsableCoupon(discountCode)) {
            return new Coupon(1000);
        } else if(isUsablePoint(discountCode)) {
            return new Point(500);
        }
        throw new Exception("์ด๋ฏธ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ");
    }
}

class Coupon extends Discount { }
class Point extends Discount { }

ํ• ์ธ ์ฝ”๋“œ์˜ ๊ทœ์น™์— ๋”ฐ๋ž€ Coupon๊ณผ point ๊ฐ์ฒด๋ฅผ ์„ ํƒ์ ์œผ๋กœ ๋ฆฌํ„ดํ•˜๊ณ  ์žˆ๋‹ค.
์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋‘ ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜, ๊ฐ™์€ ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ๊ฐ–๋„๋ก ํ•˜๋ฉด ๋œ๋‹ค. ๋งŒ์•ฝ ํŒŒ์ผ์„ ๋ถ„๋ฆฌํ•˜๊ธฐ ์• ๋งคํ•œ ์ž‘์€ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด private class๋ฅผ ํ™œ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๋‹ค์Œ์€ java.util.Collections์—์„œ EMPTY_MAP๋ถ€๋ถ„์„ ๋ฐœ์ทŒํ•œ ๊ฒƒ

@SuppressWarnings("rawtypes")
public static final Map EMPTY_MAP = new EmptyMap<>();

/**
 * Returns an empty map (immutable).  This map is serializable.
 */
@SuppressWarnings("unchecked")
public static final <K,V> Map<K,V> emptyMap() {
    return (Map<K,V>) EMPTY_MAP;
}

private static class EmptyMap<K,V> extends AbstractMap<K,V> implements Serializable {
    /* ์ƒ๋žต */
}

EmptyMap ํด๋ž˜์Šค๋Š” java.util.Collections ๋‚ด์— private static์œผ๋กœ ์„ ์–ธ๋˜์—ˆ์œผ๋ฉฐ, emptyMap์ด๋ผ๋Š” ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์บ์ŠคํŒ…๋œ ์ธ์Šคํ„ด์Šค๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

  • ํ˜•์ธ์ž ์ž๋ฃŒํ˜• ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๋•Œ ํŽธ๋ฆฌํ•˜๋‹ค Java 1.7์ด์ „์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ˜•์ธ์ž ์ž๋ฃŒํ˜• ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ–ˆ๋‹ค.
Map<String, List<String>> list = new HashMap<String, List<String>>();

// ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ: type inference๋ฅผ ์ด์šฉํ•œ๋‹ค
public static <K, V> HashMap<K, V> newInstance() {
    return new HashMap<K, V>();
}

// ์œ„์˜ ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค
Map<String, List<String>> list = HashMap.newInstance();

// Java 1.7 ์ดํ›„
Map<String, List<String>> list = new HashMap<>();

Java 1.7๋ถ€ํ„ฐ ํ˜•์ธ์ž ์—†์ด ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜์–ด์„œ, ์˜๋ฏธ๋ฅผ ๊ฑฐ์˜ ์žƒ์—ˆ๋‹ค.

  • Lombok RequiredArgsConstructor.staticName์˜ ์‚ฌ์šฉ Lombok์˜ RequiredArgsConstructor๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
import lombok.RequiredArgsConstructor;

//                                      โ†“ ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„
@RequiredArgsConstructor(staticName = "of")
public class BlogUser {
  private final Long id;
  private final String name;
}

BlogUser user = BlogUser.of(1L, "JohnGrib");

์œ„์™€ ๊ฐ™์ด staticName์„ ์„ ์–ธํ•˜๋ฉด ๋กฌ๋ณต์ด of๋ผ๋Š” ์ด๋ฆ„์„ ๊ฐ€์ง„ ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.


# 1105 - Fixture์™€ Mock

# Test Fixture

Fixture๋Š” '๊ณ ์ •๋˜์–ด ์žˆ๋Š” ๋ฌผ์ฒด'๋ฅผ ์˜๋ฏธ

# Junit ํŒ€์—์„œ ๋งํ•˜๋Š” ํ…Œ์ŠคํŠธ ํ”ฝ์Šค์ฒ˜๋ž€?

์˜์—ญํ•˜์ž๋ฉด, ํ…Œ์ŠคํŠธ ์‹คํ–‰์„ ์œ„ํ•ด ๋ฒ ์ด์Šค๋ผ์ธ์œผ๋กœ์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด๋“ค์˜ ๊ณ ์ •๋œ ์ƒํƒœ์ด๋‹ค. ํ…Œ์ŠคํŠธ ํ”ฝ์Šค์ฒ˜์˜ ๋ชฉ์ ์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜๋ณต๊ฐ€๋Šฅ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์•Œ ์ˆ˜ ์žˆ๊ณ , ๊ณ ์ •๋œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

# ์˜ˆ์‹œ

  • ๋ชฉ ๋˜๋Š” ๊ฐ€์งœ ๊ฐ์ฒด์˜ ์„ธํŒ…์ด๋‚˜ ์ƒ์„ฑ ๊ทธ๋ฆฌ๊ณ  ์‚ฝ์ž…ํ•  ๋ฐ์ดํ„ฐ์˜ ์ค€๋น„
  • ๊ตฌ์ฒด์ ์ด๋ฉฐ ์•Œ๊ณ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ง€๋‹Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋กœ๋”ฉ
  • ํ…Œ์ŠคํŠธ ํ”ฝ์Šค์ฒ˜๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ํŠน์ • ํŒŒ์ผ๋“ค์„ ๋ณต์‚ฌํ•˜๋ฉด ํŠน์ • ์ƒํƒœ๋กœ ์ดˆ๊ธฐํ™”๋œ ๊ฐ์ฒด๋“ค์ด ์ƒ์„ฑ๋จ.

Junit์€ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋“ค์ด ๋งค๋ฒˆ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „/ํ›„ ์•„๋‹ˆ๋ฉด ํ•œ๋ฒˆ๋งŒ ํ”ฝ์Šค์ฒ˜๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ œ๊ณตํ•œ๋‹ค.(Junit4์ด ์ œ๊ณตํ•˜๋Š” 4๊ฐ€์ง€ ํ”ฝ์Šค์ฒ˜ ์• ๋…ธํ…Œ์ด์…˜: @Before, @BeforeClass, @After, @AfterClass)

# Mock, Mocking

์ฃผ๋กœ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์œผ๋กœ ๊ฐœ๋ฐœํ•œ ํ”„๋กœ๊ทธ๋žจ์„ ํ…Œ์ŠคํŠธ ํ•  ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋ชจ๋“ˆ๊ณผ ์—ฐ๊ฒฐ๋˜๋Š” ์™ธ๋ถ€์˜ ๋‹ค๋ฅธ ์„œ๋น„์Šค๋‚˜ ๋ชจ๋“ˆ๋“ค์„ ์‹ค์ œ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹ค์ œ์˜ ๋ชจ๋“ˆ์„ "ํ‰๋‚ด"๋‚ด๋Š” "๊ฐ€์งœ"๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•˜์—ฌ ํ…Œ์ŠคํŠธ์˜ ํšจ์šฉ์„ฑ์„ ๋†’์ด๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด์ด๋‹ค. ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค(UI)๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ŠคํŠธ ๋“ฑ๊ณผ ๊ฐ™์ด ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์–ด๋ ค์šธ ๋•Œ ๋„๋ฆฌ ์‚ฌ์šฉ๋œ๋‹ค.

# Mocking

Mocking์€ ์œ ๋‹› ํ…Œ์ŠคํŠธ์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๊ฐ์ฒด๋Š” ๋ณดํ†ต ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค๊ณผ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์›ํ•˜๋Š” ๊ฐ์ฒด์˜ ํ–‰๋™์„ ๊ณ ๋ฆฝ์‹œํ‚ค๊ธฐ ์œ„ํ•ด(์˜์กด์„ฑ ์—†์ด) ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์„ ์‹ค์ œ ๊ฐ์ฒด์˜ ํ–‰๋™์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” mock์œผ๋กœ ๋Œ€์ฒด ์‹œ์ผœ์•ผํ•œ๋‹ค.

์ด๋Š” ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์— ํ†ตํ•ฉํ•˜๊ธฐ์— ์‹ค์šฉ์ ์ด์ง€ ์•Š์„ ๋•Œ ์œ ์šฉํ•˜๋‹ค

๊ฐ„๋žตํžˆ ๋งํ•ด, Mocking์ด๋ž€ ์‹ค์ œ ๊ฐ์ฒด๋“ค์˜ ํ–‰๋™์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ๊ฐ์ฒด๋“ค์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.


# 1106 - REST Assured

Java ํด๋ž˜์Šค์˜ ๋™์ž‘์„ ํ™•์ธํ•˜๋Š” Unit ํ…Œ์ŠคํŠธ ์ˆ˜ํ–‰์€, ํ…Œ์ŠคํŠธ ์ „๋žต์˜ ์ฒซ ๋‹จ๊ณ„์ด๋‹ค.
๊ฐœ๋ณ„ Javaํด๋ž˜์Šค๊ฐ€ ๋…๋ฆญ์ ‘์œผ๋กœ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๊ณ  ํ•ด์„œ ๋ชจ๋“  ํด๋ž˜์Šค๊ฐ€ ํ•จ๊ป˜ ๋ฌถ์ผ ๋•Œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž์ฒด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๋‹จ์œ„ํ…Œ์ŠคํŠธ ์™ธ์—๋„ ํ†ตํ•ฉํ…Œ์ŠคํŠธ(๋ชจ๋“ˆ์— ์ดˆ์ ์„ ๋งž์ถ˜ ํ…Œ์ŠคํŠธ), ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ(๋ฐฐํฌ๋œ๋Œ€๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉํ•˜๋Š” end-to-end ํ…Œ์ŠคํŠธ), ์‚ฌ์šฉ์ž ์Šน์ธ ํ…Œ์ŠคํŠธ(GUI ํ…Œ์ŠคํŠธ)๊ฐ€ ์žˆ๋‹ค.

# REST Assured๋ž€?

REST Assured๋Š” REST ์›น ์„œ๋น„์Šค๋ฅผ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ Java ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
HTTP endpoint์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ ๋ฐ ์˜ˆ์ƒ๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์นœ์ˆ™ํ•œ DSL(Domain Specific Languages)์„ ์ œ๊ณตํ•œ๋‹ค.

  • ์˜ˆ์ œ
import org.junit.Test;
import io.restassured.RestAssured;
public class SampleTest {
    @Test
    public void test() {
        RestAssured.given()
                    .when().get("http://www.google.com")
                    .then().statusCode(200);
    }
}
  • given-when-then ํŒจํ„ด์„ ์ด์šฉํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ
    • given : Test setup(ํ…Œ์ŠคํŠธ์‹œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ, ๋ฐ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์…‹ํŒ…)
    • when : Test action(Method type์„ ์ •์˜)
    • then : Test verification(Response Data๋ฅผ ๊ฒ€์ฆ)

# REST Assured ์‚ฌ์šฉ

# ์„ค์ •

  • gradle
dependencies {
    ...
    testImplementation 'io.rest-assured:rest-assured:4.4.0'
    testImplementation 'io.rest-assured:json-schema-validator:4.4.0'
    ...
}

# ์‚ฌ์šฉ๋ฒ•

  • Parameters
given().
       param("param1", "value1").
       param("param2", "value2").
when().
       get("/something");
       
// given().param("myList", "value1", "value2");

// List<String> values = new ArrayList<String>();
// values.add("value1");
// values.add("value2");
// given().param("myList", values)

REST Assured๋Š” HTTP method์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ parameter type์„ ์ž๋™์œผ๋กœ ๊ฒฐ์ •, GET => query parameters / POST => form parameters

given().
       formParam("formParamName", "value1").
       queryParam("q0-998ueryParamName", "value2").
when().
       post("/something");

ํ•˜์ง€๋งŒ, PUT, POST type์—์„œ query parameter์™€ form parameter๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ •ํ™•ํ•˜๊ฒŒ ๋ช…์‹œํ•ด์•ผํ•œ๋‹ค.

  • path parameter
post("/reserve/{hotelId}/{roomNumber}", "My Hotel", 23);

# Response JSON์˜ Assersion ์ •์˜

  1. then().assertThat()
  2. Response Message์—์„œ Assert ๊ตฌ๋ฌธ์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
  • Response Data ๊ฒ€์ฆ
    • equalTo : then().assertThat().body(equalTo("something"))
    • hasItems : then(). assertThat().body("lotto.winners.winnerId", hasItems(23, 54));
    • startsWith, endsWithPath : body("href", and(startsWith("http:/localhost:8080/"), endsWithPath("userId")));
    • time : when(). get("/"). then(). time(lessThan(2000L)); // Milliseconds
    • size : then().assertThat().body("size()", equalTo(10))
    • contain : then().assertThat(). body(containsString("some"))
Last update: September 13, 2022 21:44
Contributors: ahnjs