-
μλμ Javaμμ PIT (Pitest) Mutation Testingμ μ¬μ©νλ λ°©λ²μ λ¨κ³λ³λ‘ μ λ¦¬ν΄ λ립λλ€. PITλ μλ° μ½λμ ν μ€νΈ 컀λ²λ¦¬μ§λ₯Ό μ€μ λ‘ κ²μ¦νλ κ°λ ₯ν λꡬλ‘, μλͺ»λ(λ³μ΄λ) μ½λλ₯Ό ν μ€νΈκ° μΌλ§λ μ μ‘μλ΄λμ§λ₯Ό μΈ‘μ ν©λλ€.
π 1. PIT(Pitest) μκ°
-
Mutation Testingμ΄λ?
- κΈ°μ‘΄ μ½λλ₯Ό μΌλΆλ¬ βλ³μ΄(mutant)β μμΌμ ν μ€νΈλ₯Ό λλ €λ³΄λ κΈ°λ²μ λλ€.
- ν μ€νΈκ° μ΄ λ³μ΄λ₯Ό κ²μΆνμ§ λͺ»νλ©΄, ν μ€νΈμ νμ μ΄ μλ€λ λ»μ λλ€.
- λ¨μν λΌμΈ 컀λ²λ¦¬μ§λ³΄λ€ λ μ λ’°μ± μλ ν μ€νΈ νμ§ μ§νλ₯Ό μ 곡ν©λλ€.
-
PITμ νΉμ§
- JUnit κΈ°λ° ν μ€νΈμ μ ν΅ν©λ©λλ€.
- Maven, Gradle, Antμμ μ½κ² μ¬μ© κ°λ₯ν©λλ€.
- HTML λ° XML 리ν¬νΈλ₯Ό μμ±ν©λλ€.
βοΈ 2. Maven νλ‘μ νΈμ PIT μ μ©
2.1 Maven νλ¬κ·ΈμΈ μΆκ°
pom.xmlμ λ€μ νλ¬κ·ΈμΈμ μ€μ ν©λλ€:CreatedThu, 03 Jul 2025 10:44:24 +0900 -
-
Spring Boot 3μμ SSH ν°λμ ν΅ν PostgreSQL μ°κ²°μ μν μ€μ λ°©λ²μ μλ €λλ¦¬κ² μ΅λλ€.
1. application.yml μ€μ
spring: datasource: url: jdbc:postgresql://localhost:5433/your_database_name username: your_db_username password: your_db_password driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: validate show-sql: true properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect format_sql: true # SSH ν°λ μ€μ (컀μ€ν νλ‘νΌν°) app: ssh: tunnel: host: your-ssh-server.com port: 22 username: ssh_username private-key-path: ~/.ssh/id_rsa local-port: 5433 remote-host: localhost # SSH μλ²μμ λ³Έ DB νΈμ€νΈ remote-port: 5432 # μ€μ PostgreSQL ν¬νΈ2. SSH ν°λ μλ μ°κ²°μ μν Configuration ν΄λμ€## 3. νμν μμ‘΄μ± μΆκ° (build.gradle)
dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.postgresql:postgresql' implementation 'com.github.mwiede:jsch:0.2.17' // κΈ°ν νμν μμ‘΄μ±λ€... }3. ssh key λ§λ€κΈ° μμ
ssh-keygen -t rsa -b 4096 -m PEM -f ~/.ssh/id_rsa -C "ceo@pink-spider.io"- DBκ° μ€μΉλ μλ²μ ~/.ssh λ±μ authorized_keys (κΆν 644) νμΌμ id_rsa.pub λ΄μ© μΆκ°ν΄μΌ λ©λλ€.
- rsaκ° μλ OpenSShλ‘ keygen νμ κ²½μ° com.github.mwiede:jsch κ° μλ λ€λ₯Έ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¨μΌ λ©λλ€.
SshTunnelConfig
@Configuration @Slf4j @Profile({"local", "dev", "stage", "prod"}) public class SshTunnelConfig { @Value("${app.ssh.tunnel.host}") private String sshHost; @Value("${app.ssh.tunnel.port}") private int sshPort; @Value("${app.ssh.tunnel.username}") private String sshUsername; @Value("${app.ssh.tunnel.private-key-path}") private String privateKeyPath; @Value("${app.ssh.tunnel.local-port}") private int localPort; @Value("${app.ssh.tunnel.remote-host}") private String remoteHost; @Value("${app.ssh.tunnel.remote-port}") private int remotePort; @Value("${app.ssh.tunnel.passphrase:}") private String passphrase; private Session session; @PostConstruct public void createSshTunnel() { try { log.info("JSch SSH ν°λ μ°κ²° μμ..."); // λ‘컬 ν¬νΈκ° μ¬μ© κ°λ₯νμ§ νμΈ if (!isPortAvailable(localPort)) { throw new RuntimeException("λ‘컬 ν¬νΈ " + localPort + "κ° μ΄λ―Έ μ¬μ© μ€μ λλ€."); } JSch jsch = new JSch(); // κ°μΈν€ νμΌ κ²½λ‘ μ²λ¦¬ String keyPath = privateKeyPath; if (keyPath.startsWith("~/")) { keyPath = System.getProperty("user.home") + keyPath.substring(1); } // νμΌ μ‘΄μ¬ λ° μ½κΈ° κΆν νμΈ File keyFile = new File(keyPath); if (!keyFile.exists()) { throw new RuntimeException("SSH κ°μΈν€ νμΌμ μ°Ύμ μ μμ΅λλ€: " + keyPath); } if (!keyFile.canRead()) { throw new RuntimeException("SSH κ°μΈν€ νμΌμ μ½μ μ μμ΅λλ€. νμΌ κΆνμ νμΈνμΈμ: " + keyPath); } log.info("SSH κ°μΈν€ νμΌ: {}", keyPath); // ν€ νμ νμΈ (RSA νμμΈμ§ 체ν¬) try (java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.FileReader(keyFile))) { String firstLine = reader.readLine(); log.info("ν€ νμΌ νμ: {}", firstLine); if (firstLine != null && !firstLine.contains("BEGIN RSA PRIVATE KEY")) { log.warn("RSA νμμ΄ μλ ν€κ° κ°μ§λμμ΅λλ€: {}", firstLine); log.warn("RSA νμ ν€λ₯Ό μμ±νλ €λ©΄: ssh-keygen -t rsa -b 4096 -m PEM -f {}", keyPath); } } // κ°μΈν€ μΆκ° if (passphrase != null && !passphrase.trim().isEmpty()) { jsch.addIdentity(keyPath, passphrase); log.info("ν¨μ€νλ μ΄μ¦μ ν¨κ» κ°μΈν€ λ‘λ μλ£"); } else { jsch.addIdentity(keyPath); log.info("κ°μΈν€ λ‘λ μλ£"); } // SSH μΈμ μμ± session = jsch.getSession(sshUsername, sshHost, sshPort); session.setConfig("StrictHostKeyChecking", "no"); session.setConfig("PreferredAuthentications", "publickey"); session.setTimeout(30000); log.info("SSH μλ² μ°κ²° μλ: {}@{}:{}", sshUsername, sshHost, sshPort); session.connect(); log.info("SSH μ°κ²° μ±κ³΅"); // ν¬νΈ ν¬μλ© μ€μ session.setPortForwardingL(localPort, remoteHost, remotePort); // ν¬νΈκ° μ΄λ¦΄ λκΉμ§ λκΈ° waitForPortToOpen(localPort, 10000); log.info("SSH ν°λμ΄ μ±κ³΅μ μΌλ‘ μμ±λμμ΅λλ€: localhost:{} -> {}:{}:{}", localPort, sshHost, remoteHost, remotePort); } catch (JSchException e) { log.error("SSH ν°λ μμ± μ€ν¨: {}", e.getMessage(), e); // ꡬ체μ μΈ μλ¬ λ©μμ§ μ 곡 if (e.getMessage().contains("invalid privatekey")) { log.error("κ°μΈν€ νμμ΄ μλͺ»λμμ΅λλ€. RSA νμ ν€λ₯Ό μ¬μ©νμΈμ."); log.error("μ RSA ν€ μμ±: ssh-keygen -t rsa -b 4096 -m PEM -f ~/.ssh/level_up_rsa"); } else if (e.getMessage().contains("Auth fail")) { log.error("μΈμ¦μ μ€ν¨νμ΅λλ€. 곡κ°ν€κ° μλ²μ λ±λ‘λμ΄ μλμ§ νμΈνμΈμ."); log.error("곡κ°ν€ λ±λ‘: ssh-copy-id -i {} {}@{}", privateKeyPath + ".pub", sshUsername, sshHost); } else if (e.getMessage().contains("Connection refused")) { log.error("μλ² μ°κ²°μ΄ κ±°λΆλμμ΅λλ€. νΈμ€νΈμ ν¬νΈλ₯Ό νμΈνμΈμ."); } cleanupResources(); throw new RuntimeException("SSH ν°λ μ°κ²°μ μ€ν¨νμ΅λλ€: " + e.getMessage(), e); } catch (Exception e) { log.error("μμμΉ λͺ»ν μ€λ₯: {}", e.getMessage(), e); cleanupResources(); throw new RuntimeException("SSH ν°λ μ€μ μ€ μ€λ₯κ° λ°μνμ΅λλ€: " + e.getMessage(), e); } } @PreDestroy @EventListener(ContextClosedEvent.class) public void closeSshTunnel() { log.info("SSH ν°λ μ’ λ£ μμ..."); cleanupResources(); log.info("SSH ν°λ μ’ λ£ μλ£"); } private void cleanupResources() { if (session != null && session.isConnected()) { try { session.disconnect(); log.info("SSH μΈμ μ΄ μ’ λ£λμμ΅λλ€."); } catch (Exception e) { log.warn("SSH μΈμ μ’ λ£ μ€ μ€λ₯: {}", e.getMessage()); } } } private boolean isPortAvailable(int port) { try (ServerSocket serverSocket = new ServerSocket(port)) { return true; } catch (Exception e) { return false; } } private void waitForPortToOpen(int port, long timeoutMillis) throws InterruptedException { long startTime = System.currentTimeMillis(); while (System.currentTimeMillis() - startTime < timeoutMillis) { try (java.net.Socket socket = new java.net.Socket()) { socket.connect(new java.net.InetSocketAddress("localhost", port), 1000); log.info("ν¬νΈ {}κ° μ±κ³΅μ μΌλ‘ μ΄λ Έμ΅λλ€.", port); return; } catch (Exception e) { // ν¬νΈκ° μμ§ μ΄λ¦¬μ§ μμ, μ¬μλ Thread.sleep(500); } } log.warn("ν¬νΈ {}κ° {}ms λ΄μ μ΄λ¦¬μ§ μμμ΅λλ€.", port, timeoutMillis); } }CreatedThu, 03 Jul 2025 08:44:24 +0900 -
**Property-Based Testing(PBT)**μ μ λ ₯κ³Ό κ²°κ³Ό κ°μ **μΌλ°μ μΈ μμ±(Property)**μ μ μνκ³ , ν μ€νΈ νλ μμν¬κ° κ·Έ μμ±μ μΆ©μ‘±νλμ§λ₯Ό 무μμλ‘ μμ±λ λ€μν μ λ ₯κ°μ λν΄ νμΈνλ λ°©μμ ν μ€νΈμ λλ€. λ¨μ ν μ€νΈμ²λΌ νΉμ μ λ ₯κ°λ§ νμΈνλ κ²μ΄ μλλΌ, μμ² κ°μ μ λ ₯ μ‘°ν©μ μλμΌλ‘ κ²μ¬ν μ μλ€λ μ μμ λ§€μ° κ°λ ₯ν©λλ€.
π Property-Based Testingμ΄λ?
β ν΅μ¬ κ°λ
- μμ±(Property): ν μ€νΈ λμ ν¨μλ λ‘μ§μ΄ νμ λ§μ‘±ν΄μΌ νλ μΌλ°μ μΈ λ²μΉ λλ κ·μΉ.
- μ λ ₯κ° μλ μμ±: PBT νλ μμν¬κ° λ€μν μ λ ₯κ°μ 무μμλ‘ μμ±.
- Fail case μΆμ(Shrinking): μ€ν¨ν μ λ ₯κ°μ΄ λ°μνμ λ, μ€ν¨λ₯Ό μ¬νν μ μλ μ΅μ μ λ ₯κ°μΌλ‘ μ€μ¬μ λλ²κΉ μ μ½κ² ν¨.
π λ¨μ ν μ€νΈμμ λΉκ΅
νλͺ© λ¨μ ν μ€νΈ (Example-based) μμ± κΈ°λ° ν μ€νΈ (Property-based) μ λ ₯κ° κ³ μ λ μ¬λ‘ μλ μ§μ μλ μμ±λ λ€μν κ° ν μ€νΈ λ²μ μ νμ λ§€μ° κ΄λ²μ μ μ§λ³΄μ λ‘μ§ λ³κ²½ μ ν μ€νΈ μΆκ° νμ Propertyλ§ μ μ μνλ©΄ μλ μ μ© μ€ν¨ μ λλ²κΉ λͺ νν μ λ ₯κ° μΆμ κ³Όμ νμ
π§ͺ Spring Bootμμ Property-Based Test μ¬μ©νλ λ°©λ²
Spring Boot μ체λ JUnitμ κΈ°λ°μΌλ‘ ν λ¨μ ν μ€νΈκ° κΈ°λ³Έμ΄λ©°, PBTλ μΈλΆ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν΄μ ν΅ν©νλ κ²μ΄ μΌλ°μ μ λλ€. κ°μ₯ λ리 μ°μ΄λ Java κΈ°λ° λΌμ΄λΈλ¬λ¦¬λ λ€μκ³Ό κ°μ΅λλ€:
CreatedFri, 27 Jun 2025 10:18:03 +0900 -
Ubuntuμμ PostgreSQLμ μ€μΉνκ³ μΈλΆ μ μμ νμ©νλ €λ©΄ λ€μκ³Ό κ°μ λ¨κ³λ‘ μ§ννλ©΄ λ©λλ€.
1. PostgreSQL μ€μΉ
sudo apt update sudo apt install postgresql postgresql-contribμ€μΉ ν PostgreSQL μλΉμ€κ° μλ μμλ©λλ€. μν νμΈ:
sudo systemctl status postgresql
2. PostgreSQL μ μ λ° DB μ€μ
PostgreSQL μ€μΉ μ κΈ°λ³Έμ μΌλ‘
postgresλΌλ μ μ κ° μμ±λ©λλ€.sudo -i -u postgres psqlμνλ μ μ μ DBλ₯Ό λ§λ€κ³ λΉλ°λ²νΈ μ€μ :
CREATE USER myuser WITH PASSWORD 'mypassword'; CREATE DATABASE mydb OWNER myuser;κΆν λΆμ¬:
CreatedMon, 23 Jun 2025 10:14:00 +0900 -
컀λ§(Currying)μ μ¬λ¬ κ°μ μΈμλ₯Ό λ°λ ν¨μλ₯Ό νλμ μΈμλ§ λ°λ ν¨μλ€μ μ°μμΌλ‘ λ³ννλ κΈ°λ²μ λλ€. μνμ νμ€μΌ 컀리(Haskell Curry)μ μ΄λ¦μμ λ°μ¨ μ©μ΄μ λλ€.
κΈ°λ³Έ κ°λ
μΌλ°μ μΈ ν¨μ:
function add(a, b, c) { return a + b + c; } add(1, 2, 3); // 6컀λ§λ ν¨μ:
function curriedAdd(a) { return function(b) { return function(c) { return a + b + c; }; }; } curriedAdd(1)(2)(3); // 6νμ΄ν ν¨μλ‘ κ°λ¨νκ²
const curriedAdd = a => b => c => a + b + c; const result = curriedAdd(1)(2)(3); // 6λΆλΆ μ μ© (Partial Application)
컀λ§μ κ°μ₯ ν° μ₯μ μ λΆλΆ μ μ©μ΄ κ°λ₯νλ€λ κ²μ λλ€:
const curriedAdd = a => b => c => a + b + c; // λΆλΆ μ μ© const add5 = curriedAdd(5); const add5And3 = add5(3); console.log(add5And3(2)); // 10 (5 + 3 + 2) console.log(add5(4)(1)); // 10 (5 + 4 + 1)μ€μ©μ μΈ μμ λ€
1. λ¬Έμμ΄ κ²μ¬ ν¨μ
const hasSubstring = substring => str => str.includes(substring); const hasReact = hasSubstring('React'); const hasVue = hasSubstring('Vue'); console.log(hasReact('React κ°λ°μ')); // true console.log(hasVue('Vue.js νλ μμν¬')); // true // λ°°μ΄μμ νμ© const frameworks = ['React', 'Angular', 'Vue', 'Svelte']; const reactItems = frameworks.filter(hasReact); console.log(reactItems); // ['React']2. μν μ°μ°
const multiply = a => b => a * b; const divide = a => b => a / b; const double = multiply(2); const triple = multiply(3); const half = divide(1/2); // λλ multiply(0.5) console.log(double(5)); // 10 console.log(triple(4)); // 12 const numbers = [1, 2, 3, 4, 5]; const doubled = numbers.map(double); console.log(doubled); // [2, 4, 6, 8, 10]3. μ΄λ²€νΈ νΈλ€λ¬
const log = level => message => { console.log(`[${level}] ${message}`); }; const logError = log('ERROR'); const logInfo = log('INFO'); logError('λ°μ΄ν°λ² μ΄μ€ μ°κ²° μ€ν¨'); // [ERROR] λ°μ΄ν°λ² μ΄μ€ μ°κ²° μ€ν¨ logInfo('μλ² μμλ¨'); // [INFO] μλ² μμλ¨4. API μμ²
const apiRequest = method => url => data => { return fetch(url, { method: method, headers: { 'Content-Type': 'application/json' }, body: data ? JSON.stringify(data) : undefined }); }; const get = apiRequest('GET'); const post = apiRequest('POST'); const put = apiRequest('PUT'); // μ¬μ© get('/api/users')(); post('/api/users')({ name: 'κΉμ² μ', email: 'kim@example.com' });μλ μ»€λ§ ν¨μ λ§λ€κΈ°
function curry(fn) { return function curried(...args) { if (args.length >= fn.length) { return fn.apply(this, args); } else { return function(...nextArgs) { return curried.apply(this, args.concat(nextArgs)); }; } }; } // μ¬μ© μ function add(a, b, c) { return a + b + c; } const curriedAdd = curry(add); console.log(curriedAdd(1)(2)(3)); // 6 console.log(curriedAdd(1, 2)(3)); // 6 console.log(curriedAdd(1)(2, 3)); // 6 console.log(curriedAdd(1, 2, 3)); // 6λΌμ΄λΈλ¬λ¦¬μμμ νμ©
Lodash
const _ = require('lodash'); const add = (a, b, c) => a + b + c; const curriedAdd = _.curry(add); console.log(curriedAdd(1)(2)(3)); // 6Ramda
const R = require('ramda'); const users = [ { name: 'κΉμ² μ', age: 25 }, { name: 'μ΄μν¬', age: 30 }, { name: 'λ°λ―Όμ', age: 35 } ]; const getProperty = R.curry((prop, obj) => obj[prop]); const getName = getProperty('name'); const names = users.map(getName); console.log(names); // ['κΉμ² μ', 'μ΄μν¬', 'λ°λ―Όμ']컀λ§μ μ₯μ
- μ¬μ¬μ©μ±: νΉμ λ§€κ°λ³μκ° κ³ μ λ μλ‘μ΄ ν¨μλ₯Ό μ½κ² μμ±
- κ°λ μ±: ν¨μμ μλκ° λ λͺ νν΄μ§
- ν¨μ μ‘°ν©: λ€λ₯Έ κ³ μ°¨ ν¨μλ€κ³Ό μ‘°ν©νκΈ° μ¬μ
- λΆλΆ μ μ©: νμν λ μΌλΆ μΈμλ§ λ¨Όμ μ μ© κ°λ₯
μ£Όμμ¬ν
- μ±λ₯: ν¨μ νΈμΆμ΄ μ€μ²©λλ―λ‘ μ½κ°μ μ€λ²ν€λ λ°μ
- λλ²κΉ : μ€ν νΈλ μ΄μ€κ° 볡μ‘ν΄μ§ μ μμ
- κ°λ μ±: κ³Όλνκ² μ¬μ©νλ©΄ μ€νλ € μ½λλ₯Ό μ΄ν΄νκΈ° μ΄λ €μμ§ μ μμ
컀λ§μ ν¨μν νλ‘κ·Έλλ°μ ν΅μ¬ κ°λ μ€ νλλ‘, μ½λμ μ¬μ¬μ©μ±κ³Ό λͺ¨λμ±μ ν¬κ² ν₯μμν¬ μ μλ κ°λ ₯ν κΈ°λ²μ λλ€.
CreatedFri, 20 Jun 2025 14:11:00 +0900 -
1. ν¨μν μΈν°νμ΄μ€ μ¬μ© (Java 8+)
κΈ°λ³Έμ μΈ μ»€λ§ κ΅¬ν
import java.util.function.Function; public class CurryingExample { // 3κ° μΈμλ₯Ό λ°λ ν¨μλ₯Ό μ»€λ§ public static Function<Integer, Function<Integer, Function<Integer, Integer>>> curriedAdd() { return a -> b -> c -> a + b + c; } public static void main(String[] args) { // μ¬μ© μ Function<Integer, Function<Integer, Function<Integer, Integer>>> add = curriedAdd(); int result1 = add.apply(1).apply(2).apply(3); // 6 System.out.println(result1); // λΆλΆ μ μ© Function<Integer, Function<Integer, Integer>> add5 = add.apply(5); Function<Integer, Integer> add5And3 = add5.apply(3); int result2 = add5And3.apply(2); // 10 System.out.println(result2); } }λ 볡μ‘ν μμ - λ¬Έμμ΄ μ²λ¦¬
import java.util.function.Function; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StringCurrying { // λ¬Έμμ΄ ν¬ν¨ κ²μ¬ ν¨μ public static Function<String, Function<String, Boolean>> contains() { return substring -> str -> str.contains(substring); } // λ¬Έμμ΄ λ³ν ν¨μ public static Function<String, Function<String, String>> replace() { return target -> replacement -> str -> str.replace(target, replacement); } public static void main(String[] args) { List<String> frameworks = Arrays.asList("React", "Angular", "Vue", "Svelte"); // λΆλΆ μ μ©λ ν¨μ μμ± Function<String, Boolean> hasReact = contains().apply("React"); // μ€νΈλ¦Όκ³Ό ν¨κ» μ¬μ© List<String> reactItems = frameworks.stream() .filter(hasReact::apply) .collect(Collectors.toList()); System.out.println(reactItems); // [React] // λ¬Έμμ΄ μΉν Function<String, String> replaceJavaWithKotlin = replace().apply("Java").apply("Kotlin"); String result = replaceJavaWithKotlin.apply("I love Java programming"); System.out.println(result); // I love Kotlin programming } }2. μ λ€λ¦μ νμ©ν λ²μ© μ»€λ§ μ νΈλ¦¬ν°
import java.util.function.*; public class CurryUtil { // 2κ° μΈμ ν¨μ μ»€λ§ public static <A, B, R> Function<A, Function<B, R>> curry(BiFunction<A, B, R> function) { return a -> b -> function.apply(a, b); } // 3κ° μΈμ ν¨μλ₯Ό μν ν¨μν μΈν°νμ΄μ€ @FunctionalInterface public interface TriFunction<A, B, C, R> { R apply(A a, B b, C c); } // 3κ° μΈμ ν¨μ μ»€λ§ public static <A, B, C, R> Function<A, Function<B, Function<C, R>>> curry(TriFunction<A, B, C, R> function) { return a -> b -> c -> function.apply(a, b, c); } public static void main(String[] args) { // BiFunction μ»€λ§ BiFunction<Integer, Integer, Integer> multiply = (a, b) -> a * b; Function<Integer, Function<Integer, Integer>> curriedMultiply = curry(multiply); Function<Integer, Integer> double_ = curriedMultiply.apply(2); System.out.println(double_.apply(5)); // 10 // TriFunction μ»€λ§ TriFunction<Integer, Integer, Integer, Integer> add3 = (a, b, c) -> a + b + c; Function<Integer, Function<Integer, Function<Integer, Integer>>> curriedAdd3 = curry(add3); int result = curriedAdd3.apply(1).apply(2).apply(3); System.out.println(result); // 6 } }3. ν΄λμ€ κΈ°λ° κ΅¬ν
public class MathOperations { public static class CurriedAdd { private final int first; private CurriedAdd(int first) { this.first = first; } public static CurriedAdd of(int first) { return new CurriedAdd(first); } public CurriedAddSecond with(int second) { return new CurriedAddSecond(first, second); } public class CurriedAddSecond { private final int second; private CurriedAddSecond(int first, int second) { this.second = second; } public int and(int third) { return first + second + third; } } } public static void main(String[] args) { int result = CurriedAdd.of(1).with(2).and(3); // 6 System.out.println(result); // λΆλΆ μ μ© CurriedAdd add5 = CurriedAdd.of(5); CurriedAdd.CurriedAddSecond add5And3 = add5.with(3); int result2 = add5And3.and(2); // 10 System.out.println(result2); } }4. μ€μ©μ μΈ μμ - HTTP ν΄λΌμ΄μΈνΈ
import java.util.function.Function; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class CurriedHttpClient { public static Function<String, Function<String, Function<String, HttpRequest>>> httpRequest() { return method -> url -> body -> { HttpRequest.Builder builder = HttpRequest.newBuilder() .uri(URI.create(url)); switch (method.toUpperCase()) { case "GET": builder.GET(); break; case "POST": builder.POST(HttpRequest.BodyPublishers.ofString(body)); break; case "PUT": builder.PUT(HttpRequest.BodyPublishers.ofString(body)); break; } return builder.build(); }; } public static void main(String[] args) { // λΆλΆ μ μ©λ ν¨μλ€ μμ± Function<String, Function<String, HttpRequest>> get = httpRequest().apply("GET"); Function<String, Function<String, HttpRequest>> post = httpRequest().apply("POST"); // μ¬μ© HttpRequest getRequest = get.apply("https://api.example.com/users").apply(""); HttpRequest postRequest = post.apply("https://api.example.com/users") .apply("{\"name\":\"κΉμ² μ\"}"); System.out.println("GET: " + getRequest.uri()); System.out.println("POST: " + postRequest.uri()); } }5. Vavr λΌμ΄λΈλ¬λ¦¬ μ¬μ©
Vavr(μ΄μ Javaslang)λ μλ°μμ ν¨μν νλ‘κ·Έλλ°μ λ μ½κ² ν μ μκ² ν΄μ£Όλ λΌμ΄λΈλ¬λ¦¬μ λλ€:
CreatedFri, 20 Jun 2025 14:11:00 +0900