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
# ๋ฐ๋ณต๋ฌธ์์ ์ฌ์ฉ
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์์๋ ๋ค์๊ณผ ๊ฐ์ ์ฅ๋จ์ ์ ์ค๋ช ํ๋ค.
- ์ฅ์
- ์ด๋ฆ์ด ์์ผ๋ฏ๋ก ์์ฑ์์ ๋นํด ๊ฐ๋ ์ฑ์ด ์ข๋ค.
- ํธ์ถํ ๋๋ง๋ค ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ ํ์๊ฐ ์๋ค.
- ํ์ ์๋ฃํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ ์ ์๋ค.
- ํ์ธ์ ์๋ฃํ(parameterized type) ๊ฐ์ฒด๋ฅผ ๋ง๋ค ๋ ํธํ๋ค.
- ๋จ์
- ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ง ์๋ ํด๋์ค๋ผ๋ฉด, ์์ฑ์๊ฐ ์์ผ๋ฏ๋ก ํ์ ํด๋์ค๋ฅผ ๋ชป ๋ง๋ ๋ค.
- ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ ๋ค๋ฅธ ์ ์ ๋ฉ์๋์ ์ ๊ตฌ๋ถ๋์ง ์๋๋ค.(๋ฌธ์๋ง์ผ๋ก ํ์ธํ๊ธฐ ์ด๋ ค์ธ ์ ์์)
# ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ ํน์ง
- ๊ฐ๋ ์ฑ์ด ์ข๋ค.
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 ์ ์
- then().assertThat()
- 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"))