8μ₯μμλ μλ° ν¨μν νλ‘κ·Έλ¨μ ν΅μ¬ κ°λ μ μ€λͺ νκ² λ€.
- ν¨μν λ°©μμ΄ λͺ λ Ήν λ°©μμ μλ±ν λ₯κ°νλ κ²½μ°.
- μ΅λͺ ν΄λμ€λ₯Ό λͺ μΎνκ² λ체νλ λ°©λ²
- μλ£ κ΅¬μ‘°λ₯Ό λ ν¨μ¨μ μΌλ‘ μννλ λ°©λ²
- μ΅μ λλ‘ νλ‘κ·Έλ¨μ λ μ·¨μ½νκ² λ§λλ λ°©λ²
8.1 μ΅λͺ ν΄λμ€ λμ λλ€ μ¬μ©νκΈ°
λ¬Έμ μ½λ
class Calculator {
Map<Double, Double> values = new HashMap<>();
Double square(Double x) {
Function<Double, Double> squareFunction =
new Function<Double, Double>() {
@Override
public Double apply(Double value) {
return value * value;
}
};
return values.computeIfAbsent(x, squareFunction);
}
}
μ μ½λλ μ΅λͺ ν΄λμ€λ₯Ό μ΄μ©ν΄μ Function<Double, Double> μΈν°νμ΄μ€λ₯Ό ꡬννκ³ μλ€.
-> μ΄λ¬ν μ΅λͺ ν΄λμ€λ μ½λλμ λλ¦¬κ³ νμ κ³Ό λ©μλλ₯Ό λ°λ³΅νλ©° μ€μ μ°μ°μ΄μΈμ κ²λ€μ΄ μ₯ν©νκ² νΌμ³μ§λ€.
μλ° 8μμλ μ΅λͺ ν΄λμ€ λμ "λλ€ ννμ"μΌλ‘ μ½λλ₯Ό ν₯μμν¬ μ μλ€.
κ°μ μ½λ
class Calculator {
Map<Double, Double> values = new HashMap<>();
Double square(Double value) {
Function<Double, Double> squareFunction = factor -> factor * factor;
return values.computeIfAbsent(value, squareFunction);
}
}
Function<Double, Double> squareFunction = factor -> factor * factor;
μ²λΌ λλ€μμΌλ‘ νννλλ μ°μ° λ‘μ§μ΄ λ°λ‘ 보μ΄λ©° μ½λκ° κ°κ²°ν΄μ‘λ€.
λλ€λ ν¨μν μΈν°νμ΄μ€, μ¦ λ¨μΌ μΆμ λ©μλ(SAM)λ₯Ό ν¬ν¨νλ μΈν°νμ΄μ€λ₯Ό ꡬν.
μ μμ μμλ Function μΈν°νμ΄μ€κ° apply() μΆμ λ©μλλ§ ν¬ν¨νλ λλ€μ λ€μ΄λ§λλ€.
λλ€λ μλ μ²λΌ ν μ€ λλ μ¬λ¬ μ€λ‘ μμ± κ°λ₯νλ€.
// single
Function<Double, Double> squareFunction = factor -> factor * factor;
// multi-liner
Function<Double, Double> squareFunction = factor -> {
return factor * factor;
8.2 λͺ λ Ήν λ°©μ λμ ν¨μν
컬λ μ μ²λ¦¬μ λν΄μλ ν¨μν νλ‘κ·Έλλ° λ°©μμ΄ λͺ λ Ήν λ°©μλ³΄λ€ μ½κΈ° μ½λ€.
λ¬Έμ μ½λ
class Inventory {
List<Supply> supplies = new ArrayList<>();
long countDifferentKinds() {
List<String> names = new ArrayList<>();
for (Supply supply : supplies) {
if (supply.isUncontaminated()) {
String name = supply.getName();
if (!names.contains(name)) {
names.add(name);
}
}
}
return names.size();
}
}
λͺ λ Ήν λ°©μμ 무μμ ν΄μΌνλμ§ μ΄λ»κ² ν΄μΌνλμ§ λͺ¨λ λͺ μμ μΌλ‘ μ½λλ₯Ό μμ±ν©λλ€.
νμ§λ§ λ©μλμ μλλ₯Ό νμ€ν λ€μ΄λ΄λ €λ©΄ μ΄λ»κ²λ νλμ§λ λΉΌκ³ λ¬΄μμ νλμ§λ§ λͺ μνλ©΄ λλ€.
λλ€λ‘ 무μμ΄ μ΄λ£¨μ΄μ§κΈΈ μνλμ§λ§ λͺ μν μ μλ€.
κ°μ μ½λ
class Inventory {
List<Supply> supplies = new ArrayList<>();
long countDifferentKinds() {
return supplies.stream()
.filter(supply -> supply.isUncontaminated())
.map(supply -> supply.getName())
.distinct()
.count();
}
}
- stream() 컬λ μ μ μ€νΈλ¦ΌμΌλ‘ λ³ν (컬λ μ λ΄ κ° μμ μ°Έμ‘° κ°λ₯)
- filter()λ₯Ό ν΅ν΄ μ€μΌλ μμ κ±Έλ¬λ (μΌμ’ μ κ΄λ¬Έ)
- κ° μμλ₯Ό λ³ννλ€. (μ΄λ€ ν¨μκ° νμ μ λ€λ₯Έ νμ μΌλ‘ 맀ν // supplyμμ .getName()μΌλ‘)
- dinstnct()λ‘ μ€λ³΅ κ±Έλ¬ λ΄κΈ°
- count()λ‘ λ¨μ κ°―μ μΈκΈ°
8.3 λλ€ λμ λ©μλ μ°Έμ‘°
λλ€ ννμμ μ¬μ©νλ©΄ μ½λκ° μ½κΈ° νΈν΄μ§λ€.
νμ§λ§ μ€νΈλ¦Ό μ€κ°λΆν° μ€νν μ μκ³ μ€μ§ μ€νΈλ¦Ό μ 체μ λν΄μλ§ μ€νν μ μλ€. (μΌλΆλ§ ν μ€νΈ νκΈ° μ΄λ ΅λ€)
λ§μ½, λλ€ννμμ΄ λ³΅μ‘ν΄μ§κ³ λ Όλ¦¬κ° λ§μμ§λ©΄ μ€λ₯ κ°λ₯μ±μ΄ λμμ§λλ° μ°Έμ‘°κ° λΆκ°λ₯ν΄ λ¨μ ν μ€νΈλ μλλ κΈ°λλλ‘ λμνλ μ§ κ²μ¦ν μ λ μλ€.
μλ°μ ν¨μν νλ‘κ·Έλλ°μμλ λ©μλ μ°Έμ‘°λ₯Ό μ¬μ©νλ©΄ λ©μλ νΈμΆμ λλ€ ννμμ λΌμ λ£μ μ μκ³ νμ§ λ³΄μ¦μ΄ μ¬μμ§λ€.
κ°μ μ½λ
class Inventory {
List<Supply> supplies = new ArrayList<>();
long countDifferentKinds() {
return supplies.stream()
.filter(Supply::isUncontaminated)
.map(Supply::getName)
.distinct()
.count();
}
}
μΌλ°μ μΈ λλ€ ννμ λμ 미리 μ μλ λ©μλλ₯Ό μ€νΈλ¦Ό λ΄μμ λ°λ‘ μ°Έμ‘°νλ©΄ λλ€.
μ΄λ κ² νλ©΄ λ©μλ κ°κ°μ νΈμΆν μ μκ³ λΆμ νΌνκΈ°λ¬Έμ λ ν΄κ²°ν μ μλ€.
8.4 λΆμ ν¨κ³Ό νΌνκΈ°
ν¨μν νλ‘κ·Έλλ°μ μ λ ₯μ λ°μ΄ν°λ‘ λ°μ μΆλ ₯μΌλ‘ μλ£¨μ΄ λ°μ΄ν°λ₯Ό μμ±νλ ν¨μμ΄λ―λ‘ λ°μ΄ν°λ λΆλ³μ΄λ€. λ°λΌμ λΆμ ν¨κ³Ό(side effect)κ° μλ€.
νμ§λ§ λͺ λ Ήνκ³Ό κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μ λ°μ΄ν°λ₯Ό λ°κΎΈλ―λ‘ λΆμ ν¨κ³Όμ μμ‘΄νλ€.
μλ°λ νμ¬ μΈ κ°μ§ λ°©μμ λͺ¨λ μ¬μ©νλ―λ‘ κ°λ ₯νμ§λ§ μ€λ₯κ° λ°μνκΈ°λ μ½λ€. λ°λΌμ μ½λ λ΄ λΆμν¨κ³Όλ₯Ό μ΅μννλ λ°©λ²μ μμμΌ νλ€.
λ¬Έμ μ½λ
class Inventory {
List<Supply> supplies = new ArrayList<>();
long countDifferentKinds() {
List<String> names = new ArrayList<>();
Consumer<String> addToNames = name -> names.add(name);
supplies.stream()
.filter(Supply::isUncontaminated)
.map(Supply::getName)
.distinct()
.forEach(addToNames);
return names.size();
}
}
μ€νΈλ¦Όμ forEach() λΆλΆμμ addToNamesλ₯Ό νΈμΆνλλ° μ΄λ λλ€ ννμ λ°μ μλ 리μ€νΈμ μμλ₯Ό μΆκ°νλ€.
-> μ΄λ λΆμν¨κ³Όκ° λ°μνλ€.
μ½λκ° κΈ°λ₯μμ μ€λ₯λ μμ§λ§ λμ μ€νμ΄ κ°λ₯νλλ‘ λ°κΎΈλ©΄ μ½κ² κ³ μ₯μ΄λλ€. (μλ°λ μ¬λ¬ μ€λ λ κ° λΆμν¨κ³Ό λ°μμ λν΄ λ³΄μ₯νμ§ μμΌλ―λ‘)
κ·Έλ¬λ©΄ "λΆμν¨κ³Ό"λ₯Ό μΌμΌν€μ§ μμΌλ©΄μ λλ€ ννμμ μ’ λ£νλ €λ©΄ μ΄λ»κ² ν΄μΌ ν κΉ?
κ°μ μ½λ
class Inventory {
List<Supply> supplies = new ArrayList<>();
long countDifferentKinds() {
List<String> names = supplies.stream()
.filter(Supply::isUncontaminated)
.map(Supply::getName)
.distinct()
.collect(Collectors.toList());
return names.size();
}
}
μ μ½λμμ κ°μ₯ μ€μν λΆλΆμ λλ€ ννμμμ μμ±νλ 리μ€νΈμ΄λ€.
리μ€νΈλ₯Ό μ§μ λ§λ€μ§ μκ³ μ»¬λ μ λ΄ μ€νΈλ¦Όμ λ¨μ μλ κ° μμλ₯Ό collect() νλ€.
μ΄λ 리μ€νΈλ₯Ό λ§λ€κΈ° μν΄μλ collect(Collectors.toList());λ‘ μ€νΈλ¦Όμ μ’
λ£ν΄μΌλ§ νλ€.
(Collectors.toSet()νλ©΄ Set μλ£κ΅¬μ‘°λ‘ λ§λ¬)
**μμ½**
- μ€νΈλ¦Όμ μ’ λ£μν¬ λ forEach()λ λΆμν¨κ³Όλ₯Ό μΌμΌν€λ κ°λ₯νλ©΄ μ°μ§λ§μ
- collect()μ reduce()λ₯Ό μ°λ €κ³ νμ. (μ€νΈλ¦Ό μ§μ μ’ λ£ + μνλ μλ£κ΅¬μ‘° μμ± κ°λ₯)
8.5 볡μ‘ν μ€νΈλ¦Ό μ’ λ£ μ 컬λ νΈ μ¬μ©νκΈ°
볡μ‘ν μ€νΈλ¦Ό μ’ λ£ μμ λΆμν¨κ³Όλ₯Ό νΌνλ λ°©λ²μ μ΅ν보μ..
μ°λ¦¬κ° μνλ λ°μ΄ν°λ
supplies 리μ€νΈ λ΄ κ³ μ μμ μλ₯Ό λͺ¨λ μΈλ λμ λ¨μ μ ν μλ₯Ό μ΄λ¦λ³λ‘ λ¬Άμ΄ κ³μ°νλ Map<String, Long>ννλ₯Ό λ§λ€κΈ°λ₯Ό μνλ€.
μΏΌλ¦¬λ‘ μκ°νμλ©΄ 'SELECT name, count(*) FROM supplies GROUP BY name;'μ΄λΌκ³ λ³Ό μ μλ€.
λ¬Έμ μ½λ
class Inventory {
List<Supply> supplies = new ArrayList<>();
Map<String, Long> countDifferentKinds() {
Map<String, Long> nameToCount = new HashMap<>();
Consumer<String> addToNames = name -> {
if (!nameToCount.containsKey(name)) {
nameToCount.put(name, 0L);
}
nameToCount.put(name, nameToCount.get(name) + 1);
};
supplies.stream()
.filter(Supply::isUncontaminated)
.map(Supply::getName)
.forEach(addToNames);
return nameToCount;
}
}
κ°μ μ½λ
class Inventory {
List<Supply> supplies = new ArrayList<>();
Map<String, Long> countDifferentKinds() {
return supplies.stream()
.filter(Supply::isUncontaminated)
.collect(Collectors.groupingBy(Supply::getName,
Collectors.counting())
);
}
}
μ€νΈλ¦Όμ κ²°κ³Όλ₯Ό CollectionμΌλ‘ λ§λ€μ΄μΌ ν κ²½μ° μ°λ¦¬λ Collectorsλ₯Ό μ΄μ©ν΄ μνλ μλ£κ΅¬μ‘° ννλ‘ λ§λ€ μ μλ€. (toList(), toSet(), toMap())
μ μ½λμμλ Collectors.groupingBy() μ°μ°μλ₯Ό Supply μΈμ€ν΄μ€μ μ€νΈλ¦Όμ μ μ©νλ€. μ΄ μ°μ°μλ Mapμλ£κ΅¬μ‘°λ₯Ό λ°ννλ€.
κ·Έλ£Ήνλ°μ΄μ 첫λ²μ§Έ μΈμλ‘λ ν€ νμ μ ν΄λΉνλ string, λλ²μ§Έ μΈμλ‘λ κ°―μμΈ Longμ λ£μ΄μ€λ€.
κ·Έλ¬λ©΄ μ°λ¦¬κ° μνλ μ΄λ¦λ³ νλͺ© μμΈ Map<String, Long>μ΄ κ²°κ³Όλ‘ λ°νλλ€.
collect() λ°©μμ΄ λ¬Έμ μ½λ λ³΄λ€ ν¨μ¬ κ°κ²°νκ³ μμ μ μ μ λ¬νλ©° μ¬μ§μ΄ SQL 쿼리 μ²λΌ μ½νλ€.
Collectorsλ μ΄μΈμλ joining(), maxBy() λ± λ§μ κΈ°λ₯μ μ 곡νκ³ μλ€.
8.6 μ€νΈλ¦Ό λ΄ μμΈ νΌνκΈ°
λ¬Έμ μ½λ
class LogBooks {
static List<LogBook> getAll() throws IOException {
return Files.walk(Paths.get("/var/log"))
.filter(Files::isRegularFile)
.filter(LogBook::isLogbook)
.map(path -> {
try {
return new LogBook(path);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
})
.collect(Collectors.toList());
}
}
λ¬Έμ μ½λλ₯Ό 보면 μμΈλ₯Ό μ²λ¦¬νλ λ°©μμ΄ λ§€μ° λ³΅μ‘νκ³ μ’μ보μ΄μ§ μλλ€.
κ·Έλ λ€λ©΄ ν¨μν νλ‘κ·Έλλ°μμλ μ΄λ»κ² μμΈλ₯Ό μ²λ¦¬ν΄μΌ ν κΉ?
κ°μ μ½λ
class LogBooks {
static List<LogBook> getAll() throws IOException {
try (Stream<Path> stream = Files.walk(Paths.get("/var/log"))) {
return stream.filter(Files::isRegularFile)
.filter(LogBook::isLogbook)
.flatMap(path -> {
try {
return Stream.of(new LogBook(path));
} catch (IOException e) {
return Stream.empty();
}
})
.collect(Collectors.toList());
}
}
}
μ¬μ ν try-catchλ¬Έμ μ¬μ©νμ§λ§ flatMap()μ μ¬μ©νλ€.
μ΄λ₯Ό ν΅ν΄ μ΄λ€ νμ μ λ€λ₯Έ νμ μ StreamμΌλ‘ 맀ννλ€. λ¬Έμ κ° λ°μνλ©΄ λ¨μ§ Stream.empty()λ₯Ό λ°ννλ€.
μμΈλ₯Ό νΌνλ €λ©΄ ν¨μν λ°©μμ λ°λ₯΄μΈμ..
8.7 λ λμ μ΅μ λ
κ°μ²΄λ₯Ό κ°λ₯΄ν€μ§ μλ μ°Έμ‘°λ nullμ κ°λ₯΄ν¨λ€. null μ°Έμ‘°λ‘ λ©μλλ₯Ό μ°Έμ‘°νλ©΄ NullPointerExceptionμ΄ λ°μνλ€.
μλ° 8κ³Ό λλ€ ννμμ λ±μ₯ μ΄ν κΈ°μ‘΄μ λ λ³΄νΈ μ΄μΈμ λ κ°μ²΄λ₯Ό ν΄κ²°ν λ€λ₯Έ λ°©λ²μ΄ μκ²Όλ€.
λ¬Έμ μ½λ
class Communicator {
Connection connectionToEarth;
void establishConnection() {
// used to set connectionToEarth, but may be unreliable
}
Connection getConnectionToEarth() {
return connectionToEarth;
}
}
κΈ°μ‘΄μλ if λ¬Έμ μΆκ°ν΄ nullμΈμ§ μλμ§ κ²μ¦νμ κ²μ΄λ€. νμ§λ§ if λ¬Έμ μ¬μ©νλ©΄ λλ€ ννμμ μ‘°ν©ν΄μ μ¬μ©νκΈ°λ λΆκ°λ₯νλ€.
μλ°λ λ μ’μ λ°©λ²μ μ¬μ©νκ³ μλ€.
κ°μ μ½λ
static void main2() {
Communicator communicationSystem = new Communicator();
communicationSystem.getConnectionToEarth()
.ifPresent(connection ->
connection.send("Houston, we got a problem!")
);
}
μλ°λ connectionToEarthκ° μμ μλ μλ°λ κ²μ "Optional"μ ν΅ν΄μ λͺ μνλ€. Optionalμλ κ°μ²΄κ° nullμΌμλ μκ³ μλμλ μλ€.
μ΄λ κ² μ¬μ©ν¨μΌλ‘μ¨ μ»μ μ μλ μ΄μ μ νΈμΆμκ° nullκ°μ μ΄λ»κ² μ²λ¦¬ν μ§ μκ°ν΄λ³Ό μ μκ²νλ€λ μ μ΄λ€.
μ¬μ ν μμΈλ λ°μν μ μμ§λ§ νΈμΆμκ° μ΄λ₯Ό μ μ ν ν΄κ²°ν μ μκ² ν΄μ€λ€.
8.8 μ ν νλλ 맀κ°λ³μ νΌνκΈ°
λ¬Έμ μ½λ
class Communicator {
Optional<Connection> connectionToEarth;
void setConnectionToEarth(Optional<Connection> connectionToEarth) {
this.connectionToEarth = connectionToEarth;
}
Optional<Connection> getConnectionToEarth() {
return connectionToEarth;
}
}
νλλ 맀κ°λ³μμ μ΅μ λ νμ μ μ¬μ©νλ©΄ μλλ€. μ΄λ μ½λλ₯Ό λ 볡μ‘ν΄μ§κ² λ§λ€ λΏμ΄λ€.
μ΅μ λμ 'λΆμ¬'μ 'μ‘΄μ¬'μ μνλ₯Ό κ°μ§λλ° μ΄ μ΅μ λμ΄ nullμ΄λ©΄ λ λΆμ¬νλ€λ λ»μΈκ°..? μλ¬΄νΌ μ΄ν΄ μλ¨.. μλ¬΄νΌ μ°λ©΄ ν·κ°λ¦Ό
λ§μ½, νλμ λ©μλ 맀κ°λ³μ νμ μμ Optionalμ μ¬μ©νλ€λ©΄ μ κ±°ν΄λΌ. κ·Έλ¦¬κ³ μ€μ§ λ°νκ°μμλ§ μ¬μ©ν΄λΌ.
κ°μ μ½λ
class Communicator {
Connection connectionToEarth;
void setConnectionToEarth(Connection connectionToEarth) {
this.connectionToEarth = Objects.requireNonNull(connectionToEarth);
}
Optional<Connection> getConnectionToEarth() {
return Optional.ofNullable(connectionToEarth);
}
void reset() {
connectionToEarth = null;
}
}
8.9 μ΅μ λμ μ€νΈλ¦ΌμΌλ‘ μ¬μ©νκΈ°
μ΅μ λμ nullμ νλ₯ν λ체ν μ μλ€. λΏλ§ μλλΌ μλ° λ΄ λλ€ ννμμ μ΅μ λ ν΄λμ€λ₯Ό μΆκ°νλ©΄ μ’λ€.
=> Optionalμ 0κ° λλ 1κ° μμλ§ ν¬ν¨νλ νΉλ³ν νμμ μ€νΈλ¦Όμ΄λ€.
μ΅μ λμ΄ μ€νΈλ¦Όμ΄κΈ° λλ¬Έμ filter(), map()κ³Ό κ°μ μΌλ°μ μΈ μ€νΈλ¦Ό μ°μ°μ λ°λ‘ μ μ©ν μ μλ€.
λ¬Έμ μ½λ
class BackupJob {
Communicator communicator;
Storage storage;
void backupToEarth() {
Optional<Connection> connectionOptional =
communicator.getConnectionToEarth();
if (!connectionOptional.isPresent()) {
throw new IllegalStateException();
}
Connection connection = connectionOptional.get();
if (!connection.isFree()) {
throw new IllegalStateException();
}
connection.send(storage.getBackup());
}
}
μ μ½λλ μ΄λ λΆλΆμ΄ 보기 μ’μ§ μμκΉ?
μ΅μ λμ λͺ λ Ήνμ΄ μλ ν¨μν νλ‘κ·Έλλ°μ μν΄ λ§λ€μ΄μ‘λ€.
λ°λΌμ λ λ°©μ κ°μ λ³νμ μν΄ μ μ½λμμλ get() κ°μ λ©μλλ‘ λ³νμ΄ μνλ κ²μ νμΈν μ μλ€.
μ΄λ¬ν λ¬Έλ§₯κ΅νμ΄ μμ΄μ§λ©΄ μ’ λ μ½λλ₯Ό ν₯μμν¬ μ μλ€.
κ°μ μ½λ
class BackupJob {
Communicator communicator;
Storage storage;
void backupToEarth() {
Connection connection = communicator.getConnectionToEarth()
.filter(Connection::isFree)
.orElseThrow(IllegalStateException::new);
connection.send(storage.getBackup());
}
}
ν¨μνμΌλ‘ μμ±μ μ΅μ λ ν΄λμ€μ λ€μ΄μλ λ©μλλ₯Ό μ¬μ©ν μ μλ€.
filter(), map(), flatMap()κ³Ό κ°μ μ€νΈλ¦Ό μ€κ° μ°μ°κ³Ό orElse(), orElseThrow(), orElseet(), ifPresent()λ₯Ό νμ©ν μ μλ€.
**μ€ν νλ¦**
- filter()λ₯Ό μ¬μ©ν΄ μ°κ²°μ΄ μ΄μ΄μ Έμκ³ μ¬μ©ν μ μλμ§ νμΈ
- μ°κ²°ν μ μλ€λ©΄ μμΈ λ°μ
- μ°κ²° κ°λ₯νλ―λ‘ send() μ€ν
ν¨μνμΌλ‘ μμ±νλ©΄ κΈ°μ‘΄μ λͺ λ Ήνλ³΄λ€ μ½λκ° κ°κ²°ν΄μ§κ³ μ€ν νλ¦μ μ΄ν΄νκΈ° μ¬μμ§λ€.
8.10 8μ₯μμ λ°°μ΄ λ΄μ©
ν¨μν λ°©μμ μλ°λ₯Ό μλ‘κ² νλ‘κ·Έλλ° ν μ μλ λ°©μμ΄λ€.
μ΅μν΄μ§λ €κ³ λ Έλ ₯νμ.
λ©μλ μ°Έμ‘°, μ΅μ λ, λλ€ ννμ λ±μ μ κ·Ή νμ©νμ.
'πμ½μ μ± μ 리 > μλ° μ½λ©μ κΈ°μ ' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[μλ° μ½λ©μ κΈ°μ ] 7μ₯ : κ°μ²΄ λμμΈ (0) | 2021.04.15 |
---|---|
[μλ° μ½λ©μ κΈ°μ ] 6μ₯ : μ¬λ°λ₯΄κ² λλ¬λ΄κΈ° (0) | 2021.04.15 |
[μλ° μ½λ©μ κΈ°μ ] 5μ₯ : λ¬Έμ λ°μμ λλΉνκΈ° (0) | 2021.04.14 |
[μλ° μ½λ©μ κΈ°μ ] 4μ₯ : μ¬λ°λ₯΄κ² λͺ λͺ νκΈ° (0) | 2021.04.13 |
[μλ° μ½λ©μ κΈ°μ ] 3μ₯ : μ¬κΈ°λ‘κ² μ£Όμ μ¬μ©νκΈ° (0) | 2021.04.09 |