๐ŸŽฏ 1์ฃผ์ฐจ Unit 2.2 โ€” ๊ฐ€๋ณ€์ธ์ž (Varargs)

Psjยท4์ผ ์ „

F-lab

๋ชฉ๋ก ๋ณด๊ธฐ
24/42

๐ŸŽฏ Unit 2.2 โ€” ๊ฐ€๋ณ€์ธ์ž (Varargs)

F-lab Java 1์ฃผ์ฐจ / Phase 2 / Unit 2.2 ๋ณธ๊ฒฉ ํ•™์Šต ์ž๋ฃŒ
9-์„น์…˜ ๋งˆ์Šคํ„ฐ ํ”„๋กฌํ”„ํŠธ ํ˜•์‹์œผ๋กœ ๊นŠ์ด ํŒŒํ—ค์นœ๋‹ค.

์„ ์ˆ˜ ์ง€์‹: Unit 2.1 (๋ฉ”์„œ๋“œ์˜ ๊ตฌ์กฐ)
๋‹ค์Œ Unit: 2.3 โ€” ์ƒ์†๊ณผ ์ƒ์„ฑ์ž ์ฒด์ด๋‹


๐ŸŒ 1. ์„ธ์ƒ ์† ๋น„์œ 

๊ฐ€๋ณ€์ธ์ž = "๋งˆํŠธ ๊ณ„์‚ฐ๋Œ€"

๋งˆํŠธ ๊ณ„์‚ฐ๋Œ€์—์„œ ๊ฒฐ์ œํ•  ๋•Œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์„ธ์š”. ์†๋‹˜๋งˆ๋‹ค ์‚ฌ๋Š” ๋ฌผ๊ฑด์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค:

  • ์†๋‹˜ A: ์‚ฌ๊ณผ 1๊ฐœ๋งŒ (1๊ฐœ)
  • ์†๋‹˜ B: ์‚ฌ๊ณผ 1๊ฐœ, ์šฐ์œ  2๊ฐœ (2๊ฐœ)
  • ์†๋‹˜ C: ์‚ฌ๊ณผ 1๊ฐœ, ์šฐ์œ  2๊ฐœ, ๋นต 3๊ฐœ, ์น˜์ฆˆ 4๊ฐœ, ๋ผ๋ฉด 1๊ฐœ (5๊ฐœ)
  • ์†๋‹˜ D: ๊ทธ๋ƒฅ ๋‘˜๋Ÿฌ๋ณด๋‹ค ๊ทธ๋ƒฅ ๊ฐ (0๊ฐœ)

๊ณ„์‚ฐ์›์ด ์ผํ•˜๋Š” ๋ฐฉ์‹:

  • ์†๋‹˜์ด ์นดํŠธ์— ๋‹ด์•„์˜จ ๋ชจ๋“  ๋ฌผ๊ฑด ์„ ๋ฐ›์Œ
  • ๊ฐœ์ˆ˜๊ฐ€ 1๊ฐœ๋“  100๊ฐœ๋“  ์ƒ๊ด€์—†์Œ
  • ๊ณ„์‚ฐ์›์—๊ฒŒ ๊ฐ€์„œ "๋ฌผ๊ฑด๋“ค ๊ฒฐ์ œํ•ด์ฃผ์„ธ์š”" ํ•œ ๋งˆ๋””

๋งŒ์•ฝ ๊ณ„์‚ฐ์›์ด ์ด๋Ÿฐ ์‹์ด๋ผ๋ฉด ๋”์ฐํ•  ๊ฒƒ:

  • "1๊ฐœ์งœ๋ฆฌ ๊ณ„์‚ฐ๋Œ€"
  • "2๊ฐœ์งœ๋ฆฌ ๊ณ„์‚ฐ๋Œ€"
  • "3๊ฐœ์งœ๋ฆฌ ๊ณ„์‚ฐ๋Œ€"
  • ... "100๊ฐœ์งœ๋ฆฌ ๊ณ„์‚ฐ๋Œ€"

โ†’ ๊ฐ€๋ณ€์ธ์ž๋Š” "๊ฐœ์ˆ˜์— ์ƒ๊ด€์—†์ด ๋ฐ›์•„์ฃผ๋Š” ๊ณ„์‚ฐ๋Œ€" ์˜ ์ •์‹ .


๋” ์ž๋ฐ”์Šค๋Ÿฌ์šด ๋น„์œ  โ€” System.out.printf

์ž๋ฐ”๋ฅผ ์จ๋ณธ ์‚ฌ๋žŒ์ด๋ผ๋ฉด ์ด๋ฏธ ๊ฐ€๋ณ€์ธ์ž๋ฅผ ๋งค์ผ ์“ฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

System.out.printf("์ด๋ฆ„: %s%n", "Alice");
System.out.printf("์ด๋ฆ„: %s, ๋‚˜์ด: %d%n", "Alice", 25);
System.out.printf("์ขŒํ‘œ: (%d, %d, %d)%n", 1, 2, 3);

๊ฐ™์€ printf ๋ฉ”์„œ๋“œ์ธ๋ฐ ์ธ์ž ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค ๋‹ค๋ฆ„. ์–ด๋–ป๊ฒŒ ๊ฐ€๋Šฅํ• ๊นŒ์š”?

printf ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜:

public PrintStream printf(String format, Object... args) { ... }
//                                      โ†‘ ๊ฐ€๋ณ€์ธ์ž

โ†’ Object... args ๊ฐ€ "๋ช‡ ๊ฐœ๋“  ๋ฐ›์•„์ฃผ๊ฒ ๋‹ค" ๋Š” ์„ ์–ธ.

์ด๊ฒŒ ๊ฐ€๋ณ€์ธ์ž(varargs).


๋น„์œ ์˜ ํ•ต์‹ฌ

๋น„์œ  ์š”์†Œ์ž๋ฐ” ๊ฐ€๋ณ€์ธ์ž
๋งˆํŠธ ๊ณ„์‚ฐ๋Œ€๊ฐ€๋ณ€์ธ์ž ๋ฉ”์„œ๋“œ
์นดํŠธ์˜ ๋ฌผ๊ฑด๋“ค๊ฐ€๋ณ€์ธ์ž๋กœ ์ „๋‹ฌ๋˜๋Š” ์ธ์ž๋“ค
1๊ฐœ๋“  100๊ฐœ๋“  OK0๊ฐœ๋ถ€ํ„ฐ N๊ฐœ๊นŒ์ง€ ์ž์œ 
ํ•œ ์ค„์— ๋ชจ๋“  ์†๋‹˜ ์ฒ˜๋ฆฌํ•œ ๋ฉ”์„œ๋“œ๋กœ ๋ชจ๋“  ์‹œ๋‚˜๋ฆฌ์˜ค ์ฒ˜๋ฆฌ

๐Ÿ”ฅ 2. ํƒ„์ƒ ๋ฐฐ๊ฒฝ

๊ฐ€๋ณ€์ธ์ž ์—†๋˜ ์‹œ์ ˆ โ€” ์˜ค๋ฒ„๋กœ๋”ฉ ์ง€์˜ฅ

์ž๋ฐ” 1.4 ์ด์ „ (2004๋…„ ์ด์ „), ๊ฐ€๋ณ€์ธ์ž๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์ธ์ž ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค์–‘ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด?

๋ฐฉ๋ฒ• 1 โ€” ์˜ค๋ฒ„๋กœ๋”ฉ ํญ์ฆ:

public class Logger {
    public void log(String msg1) {
        System.out.println(msg1);
    }
    
    public void log(String msg1, String msg2) {
        System.out.println(msg1 + " " + msg2);
    }
    
    public void log(String msg1, String msg2, String msg3) {
        System.out.println(msg1 + " " + msg2 + " " + msg3);
    }
    
    public void log(String msg1, String msg2, String msg3, String msg4) {
        System.out.println(...);
    }
    
    // ... 5๊ฐœ, 6๊ฐœ, 7๊ฐœ... ๋์—†์ด โŒ
}

๋ฌธ์ œ:

  • ์‚ฌ์šฉ์ž๊ฐ€ 5๊ฐœ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌํ•˜๋ฉด? ๋ฉ”์„œ๋“œ ์—†์Œ โ†’ ์ปดํŒŒ์ผ ์—๋Ÿฌ
  • 100๊ฐœ ๋ฐ›๋Š” ๋ฉ”์„œ๋“œ ๋งŒ๋“ค ์ˆ˜๋„ ์—†์Œ
  • ๊ฐ™์€ ์ฝ”๋“œ์˜ ๋ฐ˜๋ณต

๋ฐฉ๋ฒ• 2 โ€” ๋ฐฐ์—ด๋กœ ๋ฐ›๊ธฐ:

public class Logger {
    public void log(String[] messages) {
        for (String msg : messages) {
            System.out.println(msg);
        }
    }
}

// ์‚ฌ์šฉ โ€” ๋งค๋ฒˆ ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด์•ผ ํ•จ โŒ
logger.log(new String[]{"hello"});
logger.log(new String[]{"hello", "world"});
logger.log(new String[]{"a", "b", "c", "d"});

๋ฌธ์ œ:

  • ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค new String[]{...} ์ž‘์„ฑ โ€” ๋ฒˆ๊ฑฐ๋กœ์›€
  • "๊ทธ๋ƒฅ ์ธ์ž๋งŒ ๋„˜๊ธฐ๊ณ  ์‹ถ์€๋ฐ" ๋ผ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ์š•๊ตฌ ๋ถˆ๋งŒ

Java 5์˜ ๋“ฑ์žฅ (2004) โ€” ๊ฐ€๋ณ€์ธ์ž ๋„์ž… โญ

Java 5 ์—์„œ ... ๋ฌธ๋ฒ• ์ด ๋“ฑ์žฅ:

public class Logger {
    public void log(String... messages) {  // โ† ๊ฐ€๋ณ€์ธ์ž
        for (String msg : messages) {
            System.out.println(msg);
        }
    }
}

// ์‚ฌ์šฉ โ€” ์ž์—ฐ์Šค๋Ÿฌ์›€ โœ…
logger.log("hello");
logger.log("hello", "world");
logger.log("a", "b", "c", "d");
logger.log();  // 0๊ฐœ๋„ OK!

ํšจ๊ณผ:

  • ์˜ค๋ฒ„๋กœ๋”ฉ ํญ์ฆ ํ•ด๊ฒฐ
  • ๋ฐฐ์—ด ๋ช…์‹œ์  ์ƒ์„ฑ ๋ถˆํ•„์š”
  • ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค ์ฒ˜๋ฆฌ

โ†’ Java 5๋Š” ๊ฐ€๋ณ€์ธ์ž ์™ธ์—๋„ ์ œ๋„ค๋ฆญ, ์–ด๋…ธํ…Œ์ด์…˜, enum ๋“ฑ ์ž๋ฐ” ์—ญ์‚ฌ์˜ ๋ถ„์ˆ˜๋ น.


ํ•ต์‹ฌ ํ†ต์ฐฐ

"๊ฐ€๋ณ€์ธ์ž๋Š” '๋ฉ”์„œ๋“œ์˜ ์ž…๋ ฅ ์œ ์—ฐ์„ฑ' ์„ ๊ทน๋Œ€ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ๋ฒ•์  ์„คํƒ•(syntactic sugar)์ด๋‹ค."

๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ์—ฌ์ „ํžˆ ๋ฐฐ์—ด ์ž…๋‹ˆ๋‹ค. ๋‹จ์ง€ ํ˜ธ์ถœํ•˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŽธํ•˜๊ฒŒ ์“ฐ๋„๋ก ํ•ด์ค€ ๊ฒƒ๋ฟ.


๐Ÿ’ฃ 3. ์—†์œผ๋ฉด ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ

๊ฐ€๋ณ€์ธ์ž๊ฐ€ ์—†์„ ๋•Œ ์–ด๋–ค ๋ถˆํŽธํ•จ์ด ์žˆ๋Š”์ง€ ์‹ค์ œ ์‹œ๋‚˜๋ฆฌ์˜ค ๋กœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์‹œ๋‚˜๋ฆฌ์˜ค 1: ILIC ์šด์ž„ ๊ฒ€์ƒ‰ API

์šด์ž„ ๊ฒฌ์  ๊ฒ€์ƒ‰์—์„œ ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์„ ๋ฐ›๊ณ  ์‹ถ๋‹ค๊ณ  ํ•ฉ์‹œ๋‹ค:

  • ์ตœ์†Œ ๊ฐ€๊ฒฉ์œผ๋กœ๋งŒ ๊ฒ€์ƒ‰
  • ์ตœ์†Œ + ์ตœ๋Œ€ ๊ฐ€๊ฒฉ์œผ๋กœ ๊ฒ€์ƒ‰
  • ์ตœ์†Œ + ์ตœ๋Œ€ + ํ†ตํ™” + ์ถœ๋ฐœ์ง€ + ๋„์ฐฉ์ง€๋กœ ๊ฒ€์ƒ‰
  • ... ๋‹ค์–‘ํ•œ ์กฐํ•ฉ

๊ฐ€๋ณ€์ธ์ž ์—†์ด โ€” ์˜ค๋ฒ„๋กœ๋”ฉ ํญ์ฆ

public class FareSearchService {
    
    public List<Fare> search(int minPrice) { ... }
    public List<Fare> search(int minPrice, int maxPrice) { ... }
    public List<Fare> search(int minPrice, int maxPrice, String currency) { ... }
    public List<Fare> search(int minPrice, int maxPrice, String currency, String origin) { ... }
    public List<Fare> search(int minPrice, int maxPrice, String currency, String origin, String dest) { ... }
    // ... ์‹œ๋‚˜๋ฆฌ์˜ค ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€ โŒ
    
    public List<Fare> search(int maxPrice, boolean isMaxOnly) {
        // "์ตœ๋Œ€ ๊ฐ€๊ฒฉ๋งŒ์œผ๋กœ ๊ฒ€์ƒ‰" ์‹œ๋‚˜๋ฆฌ์˜ค โ€” ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๊ฐ™์€ ํƒ€์ž…์ด๋ผ ๋ณ„๋„ ์ฒ˜๋ฆฌ โŒ
    }
}

๋ฌธ์ œ:
1. ๋ฉ”์„œ๋“œ ํญ์ฆ โ€” ์กฐํ•ฉ๋งˆ๋‹ค ์ƒˆ ๋ฉ”์„œ๋“œ
2. ํƒ€์ž…์ด ๊ฐ™์œผ๋ฉด ๋ชจํ˜ธํ•จ (์œ„ ์ฝ”๋“œ์˜ ๋งˆ์ง€๋ง‰ ๋ฉ”์„œ๋“œ ์ฐธ๊ณ )
3. ์œ ์ง€๋ณด์ˆ˜ ์ง€์˜ฅ โ€” ๊ฒ€์ƒ‰ ๋กœ์ง ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋“  ๋ฉ”์„œ๋“œ ์ˆ˜์ •


๊ฐ€๋ณ€์ธ์ž ์—†์ด โ€” ๋ฐฐ์—ด ๊ฐ•์ œ

public class FareSearchService {
    public List<Fare> search(SearchCriteria[] criteria) { ... }
}

// ์‚ฌ์šฉ โ€” ๋ฐฐ์—ด ๋งค๋ฒˆ ์ƒ์„ฑ โŒ
service.search(new SearchCriteria[]{
    new SearchCriteria("price", ">=", 1000)
});

service.search(new SearchCriteria[]{
    new SearchCriteria("price", ">=", 1000),
    new SearchCriteria("price", "<=", 5000)
});

// "์กฐ๊ฑด ์—†์ด ์ „์ฒด ๊ฒ€์ƒ‰"
service.search(new SearchCriteria[0]);  // ๋นˆ ๋ฐฐ์—ด โŒ ์–ด์ƒ‰ํ•จ

๋ฌธ์ œ:
1. ํ˜ธ์ถœ ์‹œ ๋…ธ์ด์ฆˆ โ€” new SearchCriteria[]{...} ๋งค๋ฒˆ
2. ๋นˆ ์ธ์ž ํ‘œํ˜„ ์–ด์ƒ‰ โ€” new SearchCriteria[0]
3. ๊ฐ€๋…์„ฑ โ†“


๊ฐ€๋ณ€์ธ์ž ๋„์ž… โ€” ๊น”๋”ํ•œ ํ•ด๊ฒฐ

public class FareSearchService {
    public List<Fare> search(SearchCriteria... criteria) { ... }
}

// ์‚ฌ์šฉ โ€” ์ž์—ฐ์Šค๋Ÿฌ์›€ โœ…
service.search();  // ์กฐ๊ฑด ์—†์Œ โ†’ ์ „์ฒด ๊ฒ€์ƒ‰
service.search(priceMin);
service.search(priceMin, priceMax);
service.search(priceMin, priceMax, currency, origin, dest);

ํšจ๊ณผ:

  • ๋ฉ”์„œ๋“œ 1๊ฐœ๋กœ ๋ชจ๋“  ์‹œ๋‚˜๋ฆฌ์˜ค ์ฒ˜๋ฆฌ
  • ํ˜ธ์ถœ์ด ์ž์—ฐ์Šค๋Ÿฌ์›€
  • 0๊ฐœ ์ธ์ž๋„ ๊ฐ€๋Šฅ

์ž๋ฐ” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฐ€๋ณ€์ธ์ž ํ™œ์šฉ โญ

๊ฐ€๋ณ€์ธ์ž๊ฐ€ ์—†์œผ๋ฉด ์ž๋ฐ” ์ž์ฒด๊ฐ€ ๋งค์šฐ ๋ถˆํŽธํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค:

// 1. printf ๊ณ„์—ด
System.out.printf("์ด๋ฆ„: %s, ๋‚˜์ด: %d", name, age);

// 2. String.format
String.format("Hello, %s!", "Alice");

// 3. List.of, Set.of, Map.of (Java 9+)
List.of("a", "b", "c");
Set.of(1, 2, 3, 4, 5);

// 4. Arrays.asList
Arrays.asList("x", "y", "z");

// 5. String.join
String.join(", ", "a", "b", "c");  // "a, b, c"

// 6. Stream.of
Stream.of(1, 2, 3, 4, 5);

โ†’ ๋ชจ๋‘ ๊ฐ€๋ณ€์ธ์ž ๋•๋ถ„. ์—†์—ˆ๋‹ค๋ฉด ์ด ๋ชจ๋“  ๊ฒŒ ๋ฐฐ์—ด์„ ๋งค๋ฒˆ ๋งŒ๋“ค์–ด์•ผ ํ–ˆ์„ ๊ฒƒ.


โœ… 4. ํ•ด๊ฒฐ์ฑ… โ€” ๊ฐ€๋ณ€์ธ์ž ๋ฌธ๋ฒ•

๊ธฐ๋ณธ ๋ฌธ๋ฒ•

[์ ‘๊ทผ์ œ์–ด์ž] ๋ฐ˜ํ™˜ํƒ€์ž… ๋ฉ”์„œ๋“œ๋ช…(ํƒ€์ž…... ๋ณ€์ˆ˜๋ช…) {
    // ๋ณ€์ˆ˜๋ช…์€ ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋‹ค๋ฃธ
}

ํ•ต์‹ฌ ํ‘œ์‹œ: ... (์  3๊ฐœ)


์‹ค์ œ ์˜ˆ์‹œ

public class Logger {
    public void log(String... messages) {
        // messages๋Š” String[] ๋ฐฐ์—ด๋กœ ๋‹ค๋ฃธ
        System.out.println("๋ฐ›์€ ๋ฉ”์‹œ์ง€ ๊ฐœ์ˆ˜: " + messages.length);
        for (String msg : messages) {
            System.out.println("- " + msg);
        }
    }
}

Logger logger = new Logger();
logger.log();                          // 0๊ฐœ
logger.log("hello");                   // 1๊ฐœ
logger.log("hello", "world");          // 2๊ฐœ
logger.log("a", "b", "c", "d", "e");   // 5๊ฐœ

์ถœ๋ ฅ:

๋ฐ›์€ ๋ฉ”์‹œ์ง€ ๊ฐœ์ˆ˜: 0

๋ฐ›์€ ๋ฉ”์‹œ์ง€ ๊ฐœ์ˆ˜: 1
- hello

๋ฐ›์€ ๋ฉ”์‹œ์ง€ ๊ฐœ์ˆ˜: 2
- hello
- world

๋ฐ›์€ ๋ฉ”์‹œ์ง€ ๊ฐœ์ˆ˜: 5
- a
- b
- c
- d
- e

๋ฉ”์„œ๋“œ ์•ˆ์—์„œ๋Š” ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋‹ค๋ฃธ

public void process(int... numbers) {
    // numbers๋Š” int[]
    
    // 1. length ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    System.out.println("๊ฐœ์ˆ˜: " + numbers.length);
    
    // 2. ์ธ๋ฑ์Šค ์ ‘๊ทผ ๊ฐ€๋Šฅ
    if (numbers.length > 0) {
        System.out.println("์ฒซ ๋ฒˆ์งธ: " + numbers[0]);
    }
    
    // 3. for-each ๊ฐ€๋Šฅ
    for (int n : numbers) {
        System.out.println(n);
    }
    
    // 4. for ๋ฃจํ”„ ๊ฐ€๋Šฅ
    for (int i = 0; i < numbers.length; i++) {
        System.out.println(i + ": " + numbers[i]);
    }
    
    // 5. Arrays ์œ ํ‹ธ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    int sum = Arrays.stream(numbers).sum();
}

โ†’ ํ˜ธ์ถœํ•˜๋Š” ์ชฝ์€ ์ธ์ž ๋‚˜์—ด, ๋ฐ›๋Š” ์ชฝ์€ ๋ฐฐ์—ด ์ฒ˜๋ฆฌ.


๊ฐ€๋ณ€์ธ์ž + ์ผ๋ฐ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ํ˜ผํ•ฉ โญ

๊ฐ€๋ณ€์ธ์ž๋Š” ๋‹ค๋ฅธ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ:

public class Logger {
    public void log(String level, String... messages) {
        for (String msg : messages) {
            System.out.println("[" + level + "] " + msg);
        }
    }
}

logger.log("INFO");                              // 0๊ฐœ ๋ฉ”์‹œ์ง€
logger.log("INFO", "์‹œ์ž‘");                       // 1๊ฐœ
logger.log("ERROR", "DB ์—ฐ๊ฒฐ ์‹คํŒจ", "์žฌ์‹œ๋„ ์ค‘");   // 2๊ฐœ
logger.log("DEBUG", "a", "b", "c");              // 3๊ฐœ

ํ•ต์‹ฌ ๊ทœ์น™ โญ (๋ฉด์ ‘ ๋‹จ๊ณจ)

๊ทœ์น™ 1: ๊ฐ€๋ณ€์ธ์ž๋Š” ๋งˆ์ง€๋ง‰ ๋งค๊ฐœ๋ณ€์ˆ˜ ์—ฌ์•ผ ํ•จ

public void log(String level, String... messages) { ... }  // โœ… ๋งˆ์ง€๋ง‰

public void log(String... messages, String level) { ... }  // โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ

์™œ?: ์ž๋ฐ”๊ฐ€ ์–ด๋””๊นŒ์ง€๊ฐ€ ๊ฐ€๋ณ€์ธ์ž์ธ์ง€ ๊ตฌ๋ณ„ ๋ถˆ๊ฐ€.

logger.log("INFO", "msg1", "msg2", "ERROR");
// "INFO"๊ฐ€ ์ฒซ ์ธ์ž? "ERROR"๊ฐ€ level? ์ž๋ฐ”๊ฐ€ ๋ชจ๋ฆ„

๊ทœ์น™ 2: ๊ฐ€๋ณ€์ธ์ž๋Š” ๋ฉ”์„œ๋“œ๋‹น 1๊ฐœ๋งŒ ๊ฐ€๋Šฅ

public void method(String... s, int... i) { ... }  // โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ

์œ„ ๊ทœ์น™ 1๊ณผ ๊ฐ™์€ ์ด์œ  โ€” ์–ด๋””๊นŒ์ง€๊ฐ€ ์ฒซ ๊ฐ€๋ณ€์ธ์ž, ์–ด๋””๋ถ€ํ„ฐ ๋‘ ๋ฒˆ์งธ์ธ์ง€ ๋ชจ๋ฆ„.


๊ทœ์น™ 3: 0๊ฐœ๋ถ€ํ„ฐ N๊ฐœ๊นŒ์ง€ ์ž์œ 

public void log(String... messages) { ... }

logger.log();           // 0๊ฐœ OK
logger.log("a");        // 1๊ฐœ OK
logger.log("a", "b");   // 2๊ฐœ OK
// 100๊ฐœ๋„ OK

๐Ÿ—๏ธ 5. ๋‚ด๋ถ€ ๋™์ž‘ ์›๋ฆฌ

๊ฐ€๋ณ€์ธ์ž๋Š” ์‚ฌ์‹ค ๋ฐฐ์—ด์ด๋‹ค โญโญ (๋ฉด์ ‘ ๋‹จ๊ณจ)

"๊ฐ€๋ณ€์ธ์ž๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋ฌธ๋ฒ•์  ์„คํƒ•(syntactic sugar)"

์‹ค์ œ ๋™์ž‘:

// ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ
public void log(String... messages) {
    System.out.println(messages.length);
}

logger.log("a", "b", "c");

์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ณ€ํ™˜ํ•œ ์ฝ”๋“œ:

public void log(String[] messages) {  // โ† ์‚ฌ์‹ค์€ ๋ฐฐ์—ด
    System.out.println(messages.length);
}

logger.log(new String[]{"a", "b", "c"});  // โ† ํ˜ธ์ถœ ์‹œ ์ž๋™์œผ๋กœ ๋ฐฐ์—ด ์ƒ์„ฑ

โ†’ JVM ์ž…์žฅ์—์„œ๋Š” ๊ฐ€๋ณ€์ธ์ž์™€ ๋ฐฐ์—ด์ด ์™„์ „ํžˆ ๋™์ผ.


๋ฉ”๋ชจ๋ฆฌ ๊ด€์ 

logger.log("a", "b", "c");

JVM ๋‚ด๋ถ€ ํ๋ฆ„:

1. ํ˜ธ์ถœ ์‹œ์ :
   - JVM์ด "a", "b", "c"๋ฅผ ๋‹ด์€ String[] ๋ฐฐ์—ด์„ Heap์— ์ƒ์„ฑ
   - ๊ทธ ๋ฐฐ์—ด์˜ ์ฐธ์กฐ๋ฅผ log ๋ฉ”์„œ๋“œ์˜ messages ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ

2. ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ:
   - messages๋Š” ๊ทธ ๋ฐฐ์—ด์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฐธ์กฐ
   - ๋ฐฐ์—ด์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ/์†์„ฑ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

3. ๋ฉ”์„œ๋“œ ์ข…๋ฃŒ ํ›„:
   - ๋ฐฐ์—ด์€ ๋” ์ด์ƒ ์ฐธ์กฐ๋˜์ง€ ์•Š์Œ
   - ๋‹ค์Œ GC์—์„œ ์ˆ˜๊ฑฐ๋จ

โ†’ ๊ฐ€๋ณ€์ธ์ž ํ˜ธ์ถœ์€ ๋งค๋ฒˆ ์ƒˆ ๋ฐฐ์—ด ์ƒ์„ฑ (์„ฑ๋Šฅ ์˜ํ–ฅ ๊ฐ€๋Šฅ โ€” 7๋ฒˆ ์„น์…˜์—์„œ ์ž์„ธํžˆ)


๊ฐ€๋ณ€์ธ์ž์— ๋ฐฐ์—ด์„ ์ง์ ‘ ๋„˜๊ธธ ์ˆ˜๋„ ์žˆ๋‹ค โญ

public void log(String... messages) { ... }

// 1. ์ผ๋ฐ˜์ ์ธ ํ˜ธ์ถœ โ€” ์ธ์ž ๋‚˜์—ด
logger.log("a", "b", "c");

// 2. ๋ฐฐ์—ด์„ ์ง์ ‘ ์ „๋‹ฌ
String[] arr = {"a", "b", "c"};
logger.log(arr);  // โœ… ๊ฐ€๋Šฅ

// 3. new๋กœ ๋งŒ๋“  ๋ฐฐ์—ด ์ง์ ‘ ์ „๋‹ฌ
logger.log(new String[]{"a", "b", "c"});  // โœ… ๊ฐ€๋Šฅ (๊ฐ€๋ณ€์ธ์ž ์—†์„ ๋•Œ ๋ฐฉ์‹)

์™œ?: ์–ด์ฐจํ”ผ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฐฐ์—ด์ด๋ผ์„œ.


null ์ „๋‹ฌ ์‹œ ํ•จ์ • โš ๏ธ

public void log(String... messages) {
    System.out.println(messages.length);  // โš ๏ธ
}

// 1. null ์ง์ ‘ ์ „๋‹ฌ
logger.log(null);  // โ†’ messages๊ฐ€ null
                   // โ†’ messages.length โ†’ NullPointerException!

// 2. null ์ธ์ž
logger.log("a", null, "b");  // โ†’ messages = ["a", null, "b"]
                              // โ†’ messages.length = 3 (OK)
                              // โ†’ messages[1] ์‚ฌ์šฉ ์‹œ NullPointerException ๊ฐ€๋Šฅ

// 3. ๋นˆ ๋ฐฐ์—ด๊ณผ ๋‹ค๋ฆ„
logger.log(new String[0]);  // โ†’ messages = [] (๋นˆ ๋ฐฐ์—ด)
                            // โ†’ messages.length = 0

์•ˆ์ „ํ•œ ์ฝ”๋“œ:

public void log(String... messages) {
    if (messages == null) {
        return;  // ๋˜๋Š” ๋นˆ ๋ฐฐ์—ด๋กœ ์ฒ˜๋ฆฌ
    }
    for (String msg : messages) {
        if (msg != null) {
            System.out.println(msg);
        }
    }
}

์˜คํ† ๋ฐ•์‹ฑ๊ณผ ๊ฐ€๋ณ€์ธ์ž โš ๏ธ

public void process(Integer... nums) { ... }

process(1, 2, 3);  // int โ†’ Integer ์ž๋™ ๋ฐ•์‹ฑ
                    // โ†’ new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)}
                    // โ†’ 3๋ฒˆ์˜ ๋ฐ•์‹ฑ ๋ฐœ์ƒ (์„ฑ๋Šฅ ์˜ํ–ฅ)

๋Œ€์•ˆ โ€” ๊ธฐ๋ณธํ˜• ๊ฐ€๋ณ€์ธ์ž:

public void process(int... nums) { ... }

process(1, 2, 3);  // โ†’ new int[]{1, 2, 3}
                    // โ†’ ๋ฐ•์‹ฑ ์—†์Œ โœ…

โ†’ ๊ธฐ๋ณธํ˜•์ด ๊ฐ€๋Šฅํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ๊ธฐ๋ณธํ˜• ๊ฐ€๋ณ€์ธ์ž ๊ถŒ์žฅ.


๐Ÿ’ป 6. ์‹ค์ „ ์ฝ”๋“œ ์˜ˆ์‹œ

ILIC ์šด์ž„ ์‹œ์Šคํ…œ์—์„œ ๊ฐ€๋ณ€์ธ์ž๋ฅผ ๋‹ค์–‘ํ•˜๊ฒŒ ํ™œ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋“ค.

์˜ˆ์‹œ 1: ๋กœ๊น… ๋ฉ”์„œ๋“œ โ€” ๊ฐ€์žฅ ํ”ํ•œ ํ™œ์šฉ

public class IlicLogger {
    
    public void info(String message, Object... args) {
        String formatted = String.format(message, args);
        System.out.println("[INFO] " + formatted);
    }
    
    public void error(String message, Throwable error, Object... args) {
        String formatted = String.format(message, args);
        System.err.println("[ERROR] " + formatted);
        error.printStackTrace();
    }
}

// ์‚ฌ์šฉ
logger.info("์šด์ž„ ์ƒ์„ฑ ์™„๋ฃŒ");
logger.info("์šด์ž„ ID: %d", 100);
logger.info("๊ณ ๊ฐ %s, ๊ธˆ์•ก %d์›, ํ†ตํ™” %s", "Alice", 50000, "KRW");

logger.error("DB ์—ฐ๊ฒฐ ์‹คํŒจ", exception);
logger.error("์šด์ž„ %d ์ฒ˜๋ฆฌ ์‹คํŒจ: %s", exception, fareId, reason);

โ†’ SLF4J, Log4j ๋ชจ๋‘ ์ด๋Ÿฐ ํŒจํ„ด ์‚ฌ์šฉ.


์˜ˆ์‹œ 2: ๊ฒ€์ฆ ์œ ํ‹ธ๋ฆฌํ‹ฐ

public class FareValidator {
    
    public static void validateNotNull(String fieldName, Object... values) {
        for (int i = 0; i < values.length; i++) {
            if (values[i] == null) {
                throw new IllegalArgumentException(
                    fieldName + "[" + i + "] ๋Š” null์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค"
                );
            }
        }
    }
    
    public static int sum(int... numbers) {
        int total = 0;
        for (int n : numbers) {
            total += n;
        }
        return total;
    }
    
    public static int max(int first, int... rest) {
        // ์ตœ์†Œ 1๊ฐœ๋Š” ํ•„์ˆ˜, ๋‚˜๋จธ์ง€๋Š” ์„ ํƒ
        int max = first;
        for (int n : rest) {
            if (n > max) max = n;
        }
        return max;
    }
}

// ์‚ฌ์šฉ
FareValidator.validateNotNull("๊ณ ๊ฐ ์ •๋ณด", customerId, customerName, email);
int total = FareValidator.sum(1000, 2000, 3000);  // 6000
int largest = FareValidator.max(10, 5, 8, 12, 3);  // 12
FareValidator.max(10);  // 10 (rest๋Š” ๋นˆ ๋ฐฐ์—ด)

max(int first, int... rest) ํŒจํ„ด โญ :

  • ์ฒซ ์ธ์ž๋Š” ํ•„์ˆ˜
  • ๋‚˜๋จธ์ง€๋Š” ์„ ํƒ
  • ์ปดํŒŒ์ผ ์‹œ์ ์— "์ตœ์†Œ 1๊ฐœ๋Š” ํ•„์š”" ๊ฐ•์ œ ๊ฐ€๋Šฅ

์˜ˆ์‹œ 3: ๋นŒ๋” + ๊ฐ€๋ณ€์ธ์ž ์กฐํ•ฉ

public class FareQuery {
    private final List<String> conditions = new ArrayList<>();
    
    public FareQuery in(String field, Object... values) {
        if (values.length == 0) {
            return this;  // ๋ฌด์‹œ
        }
        String inClause = field + " IN (" + 
            Arrays.stream(values).map(v -> "?").collect(Collectors.joining(",")) +
            ")";
        conditions.add(inClause);
        return this;
    }
    
    public FareQuery between(String field, Object min, Object max) {
        conditions.add(field + " BETWEEN ? AND ?");
        return this;
    }
    
    public String build() {
        return "WHERE " + String.join(" AND ", conditions);
    }
}

// ์‚ฌ์šฉ
FareQuery query = new FareQuery()
    .in("status", "DRAFT", "SUBMITTED", "PAID")  // ๊ฐ€๋ณ€์ธ์ž
    .in("currency", "KRW")                        // 1๊ฐœ๋„ OK
    .between("amount", 1000, 100000);

String sql = query.build();
// "WHERE status IN (?,?,?) AND currency IN (?) AND amount BETWEEN ? AND ?"

์˜ˆ์‹œ 4: ๋ฉ”์‹œ์ง€ ํฌ๋งทํŒ…

public class NotificationService {
    
    public void sendToCustomers(String template, Customer... customers) {
        for (Customer customer : customers) {
            String message = template.replace("{name}", customer.getName());
            send(customer, message);
        }
    }
    
    private void send(Customer customer, String message) {
        // ๋ฐœ์†ก ๋กœ์ง
    }
}

// ์‚ฌ์šฉ
service.sendToCustomers("์•ˆ๋…•ํ•˜์„ธ์š” {name}๋‹˜", alice);
service.sendToCustomers("์ด๋ฒคํŠธ ์•ˆ๋‚ด {name}", alice, bob, charlie);

// ๋˜๋Š” Customer ๋ฐฐ์—ด์„ ์ง์ ‘
Customer[] vips = customerRepository.findVips();
service.sendToCustomers("VIP {name}๋‹˜๊ป˜", vips);  // ๋ฐฐ์—ด ์ง์ ‘ ์ „๋‹ฌ OK

์˜ˆ์‹œ 5: ์ž๋ฐ” ํ‘œ์ค€ API์˜ ๊ฐ€๋ณ€์ธ์ž ํ™œ์šฉ

// String.format
String msg = String.format("์ด๋ฆ„: %s, ๋‚˜์ด: %d, ์ง์—…: %s", "Alice", 25, "๊ฐœ๋ฐœ์ž");

// List.of (Java 9+) โ€” ๋ถˆ๋ณ€ ๋ฆฌ์ŠคํŠธ
List<String> tags = List.of("urgent", "shipping", "international");

// Arrays.asList
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Stream.of
Stream<String> stream = Stream.of("a", "b", "c");

// String.join
String joined = String.join(", ", "apple", "banana", "cherry");
// "apple, banana, cherry"

// Path.of (Java 11+)
Path p = Path.of("home", "user", "documents", "file.txt");

// Collections.addAll
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c", "d");

โ†’ ์ž๋ฐ”๋ฅผ ์ž˜ ์“ฐ๋ ค๋ฉด ๊ฐ€๋ณ€์ธ์ž๋Š” ํ•„์ˆ˜.


โš ๏ธ 7. ์ฃผ์˜์‚ฌํ•ญ & ํ”ํ•œ ์‹ค์ˆ˜

์‹ค์ˆ˜ 1: ๊ฐ€๋ณ€์ธ์ž ์œ„์น˜๋ฅผ ์ž˜๋ชป ๋‘ 

// โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ
public void log(String... messages, String level) { ... }

// โœ… ๋งˆ์ง€๋ง‰์— ์œ„์น˜
public void log(String level, String... messages) { ... }

๊ทœ์น™: ๊ฐ€๋ณ€์ธ์ž๋Š” ๋ฌด์กฐ๊ฑด ๋งˆ์ง€๋ง‰.


์‹ค์ˆ˜ 2: ๊ฐ€๋ณ€์ธ์ž๋ฅผ ๋‘ ๊ฐœ ์‚ฌ์šฉ

// โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ
public void method(String... names, int... ages) { ... }

// โœ… ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐ
public void method(String[] names, int[] ages) { ... }
public void method(List<String> names, List<Integer> ages) { ... }

์‹ค์ˆ˜ 3: ์˜ค๋ฒ„๋กœ๋”ฉ๊ณผ์˜ ๋ชจํ˜ธํ•จ โš ๏ธ

public class Service {
    public void process(int x) { System.out.println("int"); }
    public void process(int... nums) { System.out.println("varargs"); }
}

Service s = new Service();
s.process(1);  // โš ๏ธ "int" ์ถœ๋ ฅ โ€” ์ •ํ™•ํ•œ ๋งค์นญ์ด ์šฐ์„ 
s.process(1, 2);  // "varargs"
s.process();  // "varargs"

๊ทœ์น™ โญ :

  • ์ •ํ™•ํ•œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ๊ฐ€๋ณ€์ธ์ž๋ณด๋‹ค ์šฐ์„  ๋งค์นญ
  • ๊ทธ๋ž˜์„œ ์˜ค๋ฒ„๋กœ๋”ฉ๊ณผ ๊ฐ€๋ณ€์ธ์ž๋ฅผ ์„ž์œผ๋ฉด ํ˜ผ๋ž€

๊ถŒ์žฅ: ๊ฐ€๋ณ€์ธ์ž์™€ ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ ์˜ค๋ฒ„๋กœ๋”ฉํ•˜์ง€ ๋ง ๊ฒƒ.


์‹ค์ˆ˜ 4: ๋ฐฐ์—ด์„ "ํ•œ ์ธ์ž" ๋กœ ๋„˜๊ธฐ๊ณ  ์‹ถ์„ ๋•Œ

public void log(Object... args) {
    System.out.println("๊ฐœ์ˆ˜: " + args.length);
}

String[] arr = {"a", "b", "c"};
logger.log(arr);  // โš ๏ธ args.length = 3 (๋ฐฐ์—ด์˜ ์š”์†Œ๋“ค)

์™œ?: String[] ์€ Object[] ํ˜ธํ™˜ โ†’ ๋ฐฐ์—ด ์ž์ฒด๊ฐ€ ๊ฐ€๋ณ€์ธ์ž๋กœ ํ’€๋ฆผ.

ํ•ด๊ฒฐ โ€” ๋ฐฐ์—ด์„ ํ•œ ์ธ์ž๋กœ ๋ช…์‹œ์  ์ „๋‹ฌ:

logger.log((Object) arr);  // ์บ์ŠคํŒ…์œผ๋กœ ๋ฐฐ์—ด ์ž์ฒด๋ฅผ ํ•œ ์ธ์ž๋กœ
// โ†’ args.length = 1, args[0] = arr

โ†’ ํ—ท๊ฐˆ๋ฆฌ๋Š” ์ผ€์ด์Šค. ๋ฉด์ ‘์—์„œ๋„ ๊ฐ€๋” ์ถœ์ œ.


์‹ค์ˆ˜ 5: null ์ฒ˜๋ฆฌ ๋ˆ„๋ฝ

public void log(String... messages) {
    for (String msg : messages) {  // messages๊ฐ€ null์ด๋ฉด NPE!
        System.out.println(msg);
    }
}

logger.log(null);  // ๐Ÿ’ฅ NullPointerException

ํ•ด๊ฒฐ:

public void log(String... messages) {
    if (messages == null || messages.length == 0) {
        return;  // ๋˜๋Š” ๊ธฐ๋ณธ ๋™์ž‘
    }
    for (String msg : messages) {
        if (msg != null) {
            System.out.println(msg);
        }
    }
}

์‹ค์ˆ˜ 6: ์„ฑ๋Šฅ์„ ๊ณ ๋ ค ์•ˆ ํ•จ โš ๏ธ

๊ฐ€๋ณ€์ธ์ž๋Š” ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ ๋ฐฐ์—ด ์ƒ์„ฑ:

public void log(Object... args) { ... }

// ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค new Object[]{...} ์ƒ์„ฑ (Heap ์‚ฌ์šฉ)
for (int i = 0; i < 1000000; i++) {
    logger.log("msg", i, "data");  // 100๋งŒ ๋ฒˆ์˜ ๋ฐฐ์—ด ์ƒ์„ฑ
}

๊ณ ์„ฑ๋Šฅ์ด ํ•„์š”ํ•œ ํ•ซ ํŒจ์Šค(hot path)์—์„œ๋Š”:

  • ๊ฐ€๋ณ€์ธ์ž ๋Œ€์‹  ์˜ค๋ฒ„๋กœ๋”ฉ (์ž์ฃผ ์“ฐ๋Š” ์ผ€์ด์Šค๋งŒ)
  • ๋˜๋Š” String.format ๋Œ€์‹  StringBuilder
// ์ž์ฃผ ์“ฐ๋Š” ์ผ€์ด์Šค ์˜ค๋ฒ„๋กœ๋”ฉ
public void log(String message) { ... }       // 1๊ฐœ โ€” ๋ฐฐ์—ด ์ƒ์„ฑ X
public void log(String m1, String m2) { ... } // 2๊ฐœ โ€” ๋ฐฐ์—ด ์ƒ์„ฑ X
public void log(String.<.. messages) { ... }   // N๊ฐœ โ€” ๋ฐฐ์—ด ์ƒ์„ฑ

โ†’ ๋กœ๊น… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (SLF4J ๋“ฑ) ๊ฐ€ ์ •ํ™•ํžˆ ์ด ํŒจํ„ด์„ ์‚ฌ์šฉ.


์‹ค์ˆ˜ 7: ๊ฐ€๋ณ€์ธ์ž์— ์˜์กดํ•œ API ์„ค๊ณ„

// โš ๏ธ ์˜๋„๊ฐ€ ๋ถˆ๋ช…ํ™•
public Fare create(String... params) {
    // params[0] = customerId
    // params[1] = amount
    // params[2] = currency
    // ... ํ˜ธ์ถœ์ž๊ฐ€ ์ˆœ์„œ๋ฅผ ์™ธ์›Œ์•ผ ํ•จ
}

fareService.create("1", "50000", "KRW");  // โŒ ์˜๋„ ๋ถˆ๋ช…ํ™•

ํ•ด๊ฒฐ โ€” ๊ฐ์ฒด๋กœ ๋ช…ํ™•ํžˆ:

public Fare create(FareCreateRequest request) {
    // ๋ช…ํ™•ํ•œ ํ•„๋“œ๋ช…
}

fareService.create(new FareCreateRequest(1L, 50000, "KRW"));

โ†’ ๊ฐ€๋ณ€์ธ์ž๋Š” "๋™์งˆ์  ๋ฐ์ดํ„ฐ" ์ผ ๋•Œ๋งŒ. ์˜๋ฏธ๊ฐ€ ๋‹ค๋ฅธ ๊ฐ’๋“ค์€ ๊ฐ์ฒด๋กœ.


๐Ÿ”— 8. ์—ฐ๊ด€ ๊ฐœ๋… ๋งต

์ง์ ‘ ์ด์–ด์ง€๋Š” ํ•™์Šต

[Unit 2.1: ๋ฉ”์„œ๋“œ์˜ ๊ตฌ์กฐ]
        โ†“
[Unit 2.2: ๊ฐ€๋ณ€์ธ์ž]  โ† ์ง€๊ธˆ ์—ฌ๊ธฐ
        โ†“
[Unit 2.3: ์ƒ์†๊ณผ ์ƒ์„ฑ์ž ์ฒด์ด๋‹]
        โ†“
[Unit 2.4: ๋‹คํ˜•์„ฑ]

์ด Unit์˜ ๊ฐœ๋…์ด ํ™œ์šฉ๋˜๋Š” ๊ณณ

1์ฃผ์ฐจ ๋‚ด:

  • Phase 6 (์ปฌ๋ ‰์…˜): List.of(...), Set.of(...), Arrays.asList(...) ๋ชจ๋‘ ๊ฐ€๋ณ€์ธ์ž
  • Phase 7 (I/O): Path.of("home", "user", "file") ๊ฐ™์€ ํŒจํ„ด

๋ฏธ๋ž˜ ์ฃผ์ฐจ:

  • 3์ฃผ์ฐจ (์ œ๋„ค๋ฆญ): <T> T method(T... values) ๊ฐ™์€ ์ œ๋„ค๋ฆญ ๊ฐ€๋ณ€์ธ์ž
  • 3์ฃผ์ฐจ (๋žŒ๋‹ค/์ŠคํŠธ๋ฆผ): Stream.of(1, 2, 3), Collectors.toMap(...)
  • 5์ฃผ์ฐจ (Spring): @RequestMapping(value = {...}, method = {...}) ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜ ๊ฐ€๋ณ€๊ฐ’
  • 6์ฃผ์ฐจ (ํ…Œ์ŠคํŠธ): assertThat(list).contains("a", "b", "c") ๊ฐ™์€ assertion
  • 15์ฃผ์ฐจ (Spring MVC): @PathVariable, @RequestParam ์˜ ๋‹ค์ค‘ ๊ฐ’ ์ฒ˜๋ฆฌ

๊ฐ€๋ณ€์ธ์ž vs ์ปฌ๋ ‰์…˜

์–ธ์ œ ๋ฌด์—‡์„?

์ƒํ™ฉ์ถ”์ฒœ
ํ˜ธ์ถœ ์‹œ ์ธ์ž๋ฅผ ์ง์ ‘ ๋‚˜์—ด๊ฐ€๋ณ€์ธ์ž (method("a", "b", "c"))
์ด๋ฏธ List/๋ฐฐ์—ด์ด ์žˆ์Œ์ปฌ๋ ‰์…˜ ๋งค๊ฐœ๋ณ€์ˆ˜ (method(List<String>))
๋‘˜ ๋‹ค ์ž์ฃผ ๋ฐœ์ƒ๊ฐ€๋ณ€์ธ์ž (๋ฐฐ์—ด ์ง์ ‘ ์ „๋‹ฌ๋„ ๊ฐ€๋Šฅ)
๋งค์šฐ ๋นˆ๋ฒˆํ•œ ํ˜ธ์ถœ (์„ฑ๋Šฅ ์ค‘์š”)์ผ๋ฐ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋˜๋Š” ์˜ค๋ฒ„๋กœ๋”ฉ

์œ ์—ฐํ•œ ํŒจํ„ด โ€” ๊ฐ€๋ณ€์ธ์ž๊ฐ€ ๋‘˜ ๋‹ค ๋ฐ›์Œ:

public void process(String... items) { ... }

process("a", "b", "c");           // ์ง์ ‘ ๋‚˜์—ด
process(myList.toArray(new String[0]));  // ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ ํ›„ ์ „๋‹ฌ

๋ฉด์ ‘ ๋‹จ๊ณจ ์งˆ๋ฌธ ๋งคํ•‘

์งˆ๋ฌธ์ด Unit์—์„œ์˜ ๋‹ต
"๊ฐ€๋ณ€์ธ์ž๋ž€?"ํƒ€์ž…... ๋ณ€์ˆ˜๋ช… ํ˜•์‹, ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ๋Š” ๋ฐฐ์—ด๋กœ ๋‹ค๋ฃธ
"๊ฐ€๋ณ€์ธ์ž ์œ„์น˜ ๊ทœ์น™?"๋งˆ์ง€๋ง‰์— 1๊ฐœ๋งŒ
"๋‚ด๋ถ€์ ์œผ๋กœ๋Š”?"์ปดํŒŒ์ผ ์‹œ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜๋˜๋Š” syntactic sugar
"๋ฐฐ์—ด ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ์ฐจ์ด?"ํ˜ธ์ถœ ํŽธ์˜์„ฑ (ํ˜ธ์ถœ์ž๊ฐ€ ๋ฐฐ์—ด ์•ˆ ๋งŒ๋“ค์–ด๋„ ๋จ)
"0๊ฐœ ์ธ์ž๋„ ๊ฐ€๋Šฅ?"YES โ€” ๋นˆ ๋ฐฐ์—ด๋กœ ์ฒ˜๋ฆฌ๋จ

๐Ÿ“ 9. ํ•ต์‹ฌ ์š”์•ฝ โ€” 3์ค„ ์ •๋ฆฌ

1๏ธโƒฃ ๊ฐ€๋ณ€์ธ์ž๋Š” "๋ฉ”์„œ๋“œ์˜ ์ž…๋ ฅ ์œ ์—ฐ์„ฑ์„ ์œ„ํ•œ ๋ฌธ๋ฒ•์  ์„คํƒ•" ์ด๋‹ค.

ํƒ€์ž…... ๋ณ€์ˆ˜๋ช… ์œผ๋กœ ์„ ์–ธํ•˜๋ฉด 0๊ฐœ๋ถ€ํ„ฐ N๊ฐœ๊นŒ์ง€ ์ž์œ ๋กญ๊ฒŒ ์ธ์ž๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ ๋˜๋ฏ€๋กœ, JVM ์ž…์žฅ์—์„œ๋Š” ๊ฐ€๋ณ€์ธ์ž์™€ ๋ฐฐ์—ด์ด ์™„์ „ํžˆ ๋™์ผํ•˜๋‹ค. ํ˜ธ์ถœ์ž์˜ ํŽธ์˜๋ฅผ ์œ„ํ•œ ๋ฌธ๋ฒ•.

2๏ธโƒฃ 2๊ฐ€์ง€ ํ•ต์‹ฌ ๊ทœ์น™: ๋งˆ์ง€๋ง‰์—, 1๊ฐœ๋งŒ.

๊ฐ€๋ณ€์ธ์ž๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก์˜ ๋งˆ์ง€๋ง‰ ์—๋งŒ ์˜ฌ ์ˆ˜ ์žˆ๊ณ , ๋ฉ”์„œ๋“œ๋‹น 1๊ฐœ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด ๋‘ ๊ทœ์น™์€ ์ž๋ฐ” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์–ด๋””๊นŒ์ง€๊ฐ€ ๊ฐ€๋ณ€์ธ์ž์ธ์ง€ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. ์ด๊ฑธ ์–ด๊ธฐ๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ.

3๏ธโƒฃ ํŽธํ•˜์ง€๋งŒ ํ•จ์ •๋„ ์žˆ๋‹ค โ€” null, ์„ฑ๋Šฅ, ๋ชจํ˜ธํ•จ.

null ์ง์ ‘ ์ „๋‹ฌ ์‹œ NPE, ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค ๋ฐฐ์—ด ์ƒ์„ฑ์œผ๋กœ ์„ฑ๋Šฅ ์˜ํ–ฅ, ์˜ค๋ฒ„๋กœ๋”ฉ๊ณผ ์„ž์œผ๋ฉด ๋งค์นญ ์šฐ์„ ์ˆœ์œ„ ํ—ท๊ฐˆ๋ฆผ. ์˜๋ฏธ๊ฐ€ ๋‹ค๋ฅธ ๊ฐ’๋“ค์€ ๊ฐ์ฒด๋กœ ๋ฌถ๋Š” ๊ฒŒ ์ข‹๊ณ , ๋™์งˆ์  ๋ฐ์ดํ„ฐ ์ผ ๋•Œ๋งŒ ๊ฐ€๋ณ€์ธ์ž๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.


๐ŸŽ“ ํ•™์Šต ์ž๊ธฐ ์ ๊ฒ€

๊ธฐ๋ณธ ์ดํ•ด

  • ๊ฐ€๋ณ€์ธ์ž ๋ฌธ๋ฒ• (ํƒ€์ž…... ๋ณ€์ˆ˜๋ช…) ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค
  • ๊ฐ€๋ณ€์ธ์ž๋Š” ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ๋ฐฐ์—ด๋กœ ๋‹ค๋ฃฌ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•ˆ๋‹ค
  • ๊ฐ€๋ณ€์ธ์ž 2๊ฐ€์ง€ ํ•ต์‹ฌ ๊ทœ์น™ (๋งˆ์ง€๋ง‰, 1๊ฐœ๋งŒ) ์„ ๋งํ•  ์ˆ˜ ์žˆ๋‹ค
  • 0๊ฐœ ์ธ์ž๋„ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•ˆ๋‹ค

์‹ค์ „ ์ ์šฉ

  • ILIC ์ฝ”๋“œ์—์„œ ๊ฐ€๋ณ€์ธ์ž๊ฐ€ ์ ํ•ฉํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค
  • String.format, List.of ๋“ฑ ์ž๋ฐ” ํ‘œ์ค€ API์˜ ๊ฐ€๋ณ€์ธ์ž๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์˜๋ฏธ๊ฐ€ ๋‹ค๋ฅธ ๊ฐ’๋“ค๊ณผ ๋™์งˆ์  ๊ฐ’๋“ค์„ ๊ตฌ๋ณ„ํ•ด์„œ ๋งค๊ฐœ๋ณ€์ˆ˜ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค

๋ฉด์ ‘ ๋Œ€๋น„ (1-2๋ถ„ ๋‹ต๋ณ€)

  • "๊ฐ€๋ณ€์ธ์ž๋ž€ ๋ฌด์—‡์ธ๊ฐ€?" ๋‹ต๋ณ€ ๊ฐ€๋Šฅ
  • "๊ฐ€๋ณ€์ธ์ž์™€ ๋ฐฐ์—ด ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ฐจ์ด?" ๋‹ต๋ณ€ ๊ฐ€๋Šฅ
  • "๋‚ด๋ถ€ ๋™์ž‘ ์›๋ฆฌ?" ๋‹ต๋ณ€ ๊ฐ€๋Šฅ (๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜๋˜๋Š” syntactic sugar)

์ž๊ธฐ ์ ๊ฒ€ ์งˆ๋ฌธ ๋‹ต๋ณ€

Q1: void log(String... args) ์™€ void log(String[] args) ์˜ ์ฐจ์ด๋Š”?

ํ˜ธ์ถœ ์ธก๋ฉด (๊ฐ€์žฅ ํฐ ์ฐจ์ด):

// ๊ฐ€๋ณ€์ธ์ž โ€” ์ž์—ฐ์Šค๋Ÿฌ์›€
log("a", "b", "c");

// ๋ฐฐ์—ด ๋งค๊ฐœ๋ณ€์ˆ˜ โ€” ๋งค๋ฒˆ ๋ฐฐ์—ด ์ƒ์„ฑ ํ•„์š”
log(new String[]{"a", "b", "c"});

๋ฉ”์„œ๋“œ ์•ˆ์—์„œ๋Š” ๋™์ผ โ€” ๋‘˜ ๋‹ค String[] ๋กœ ๋‹ค๋ฃธ:

public void log(String... args) {
    System.out.println(args.length);  // OK
    for (String s : args) { ... }      // OK
}

public void log(String[] args) {
    System.out.println(args.length);  // ๋™์ผ
    for (String s : args) { ... }      // ๋™์ผ
}

JVM ๊ด€์ :

  • ์ปดํŒŒ์ผ ํ›„ ๋‘˜ ๋‹ค String[] ์œผ๋กœ ๋ณ€ํ™˜๋จ
  • ์‹œ๊ทธ๋‹ˆ์ฒ˜๋„ ๊ฑฐ์˜ ๊ฐ™์Œ (๊ฐ€๋ณ€์ธ์ž๋Š” ACC_VARARGS ํ”Œ๋ž˜๊ทธ๊ฐ€ ์ถ”๊ฐ€๋  ๋ฟ)
  • ๊ทธ๋ž˜์„œ ๋‘˜์„ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ช…์œผ๋กœ ์˜ค๋ฒ„๋กœ๋”ฉ ๋ถˆ๊ฐ€:
// โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ โ€” ๊ฐ™์€ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋กœ ์ธ์‹
public void log(String... args) { ... }
public void log(String[] args) { ... }

๊ฒฐ๋ก :

  • ํ˜ธ์ถœ ํŽธ์˜์„ฑ ์ฐจ์ด๋งŒ ์žˆ๊ณ 
  • ๋ณธ์งˆ์€ ๊ฐ™๋‹ค (๋ฐฐ์—ด)
  • ํ˜ธ์ถœ์ž๊ฐ€ ์ธ์ž๋ฅผ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒŒ ๊ฐ€๋ณ€์ธ์ž

Q2: ๊ฐ€๋ณ€์ธ์ž๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก์˜ ์–ด๋А ์œ„์น˜์— ์™€์•ผ ํ•˜๋Š”๊ฐ€?

๋ฐ˜๋“œ์‹œ ๋งˆ์ง€๋ง‰ ์œ„์น˜.

// โœ… OK
public void method(int a, String... rest) { ... }
public void method(int a, double b, Object... rest) { ... }

// โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ
public void method(String... rest, int a) { ... }
public void method(int a, String... rest, int b) { ... }

์™œ?:

  • ์ž๋ฐ”๊ฐ€ ์–ด๋””๊นŒ์ง€๊ฐ€ ๊ฐ€๋ณ€์ธ์ž์ธ์ง€ ๊ตฌ๋ณ„ ๋ชป ํ•จ
  • ์˜ˆ: method("a", "b", 1) โ€” "a", "b" ๊ฐ€ ๊ฐ€๋ณ€์ธ์ž? ์•„๋‹ˆ๋ฉด "a" ๋งŒ?
  • ๋งˆ์ง€๋ง‰์— ๋‘๋ฉด ๋ช…ํ™•: ์•ž์˜ ์ธ์ž๋“ค์€ ์ผ๋ฐ˜ ๋งค๊ฐœ๋ณ€์ˆ˜, ๋’ค๋Š” ๋ชจ๋‘ ๊ฐ€๋ณ€์ธ์ž

๋˜ํ•œ โ€” ๋ฉ”์„œ๋“œ๋‹น ๊ฐ€๋ณ€์ธ์ž๋Š” 1๊ฐœ๋งŒ:

// โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ
public void method(String... s, int... i) { ... }

๊ฐ™์€ ์ด์œ .


๋‹ค์Œ Unit์œผ๋กœ

  • ์ƒ์†๊ณผ ์ƒ์„ฑ์ž ์ฒด์ด๋‹ ์„ ํ•™์Šตํ•  ์ค€๋น„ ์™„๋ฃŒ
  • extends, super() ๊ฐ™์€ ํ‚ค์›Œ๋“œ์˜ ์˜๋ฏธ๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค

profile
Software Developer

0๊ฐœ์˜ ๋Œ“๊ธ€