![](https://habrastorage.org/files/b6a/ff7/dbe/b6aff7dbe4464863b9f7235b9007a6fb.jpeg)
ã¢ããã«é¢ããå€ãã®ããŒã ãšäŒèª¬ããããŸãã ãã¹ãŠã®èªå°å¿ã®ããããã°ã©ããŒã¯ã圌ã®æ©èœçæçã®éçšã§ãå°ãªããšã1ã€ã®ã¢ããã«é¢ãããã¥ãŒããªã¢ã«ãäœæããå¿ èŠããããšèšãããŠããŸã-ãã®ç¥ç§çãªç£ã飌ããªããããã«ãHaskellèšèªã®ãŠã§ããµã€ãã§ç¹å¥ãªã¿ã€ã ã©ã€ã³ãå®æœãããããšããçç±ããªãããã§ã¯ãããŸããã çµéšè±å¯ãªéçºè ã¯ã¢ããã®åªãã«ã€ããŠã話ããŸã -圌ãã¯ããã®ã¢ã³ã¹ã¿ãŒã®æ¬è³ªãç解ããŠãã人ã¯çãèŠããã®ã説æããèœåãå®å šã«å€±ããšèšããŸãã ãã®ããã«ãããã€ã㯠ã«ããŽãªãŒçè«ã§æŠè£ ã ãä»ã¯å®å®æãçãŠããŸãããã©ãããã¢ããã«å°éããåäžã®æ¹æ³ã¯ãªãããã§ãã
å®éãã¢ããã®æŠå¿µèªäœã¯çŽèŠ³çã§ã¯ãããŸããããªããªããé©åãªãã¬ãŒãã³ã°ãšçè«çãªæºåãªãã§ã¯çŽæãå°éã§ããªããããªæœè±¡åã®ã¬ãã«ã«ããããã§ãã ããããããã¯ãšãŠãéèŠã§ãããä»ã«æ¹æ³ã¯ãããŸãããïŒ ããã«ããããã®äžæè°ãªã¢ããã¯ãå€ãã®çããæããªãããã°ã©ããŒãæ¢ã«åãå²ãã§ããŸãã å®éãããèŠããšãæšæºã©ã€ãã©ãªã®ããã¥ã¡ã³ããŒã·ã§ã³ã§ã¯ãã¢ããããšããåèªã¯ã»ãšãã©èŠã€ãããŸããããJavaèšèªã§æ¢ã«ååšããŠããããšãããããŸãã
ãã®ããããã®ãã¿ãŒã³ã®æ·±ãæ¬è³ªãç解ãããå°ãªããšãç§ãã¡ãåãå·»ãæ¢åã®APIã§ã®ã¢ããã®äœ¿çšäŸãèªèããããšãåŠã¶ããšãéèŠã§ãã å ·äœçãªäŸã§ã¯ãåžžã«1,000ãè¶ ããæœè±¡åãŸãã¯æ¯èŒãè¡ãããŸãã ãã®èšäºã¯ããŸãã«ãã®ãããªã¢ãããŒãã«å°å¿µããŠããŸãã ã«ããŽãªçè«ã¯ååšãããå®éã«ã¯çè«ã¯ãŸã£ããååšããŸããã ã³ãŒãããåŒãè£ãããå®äžçã®ãªããžã§ã¯ããšã®æ¯èŒã¯ãããŸããã ããªãã¿ã®APIã§ã¢ãããæ¢ã«ã©ã®ããã«äœ¿çšãããŠãããã®äŸãããã€ã玹ä»ããèªè ã«ãã®ãã¿ãŒã³ã®äž»ãªå åãã€ããæ©äŒãæäŸããããã«ããŸãã åºæ¬çã«ããã®èšäºã§ã¯Javaã«ã€ããŠèª¬æããŸããæåŸã«ãã¬ã¬ã·ãŒå¶éã®äžçããæãåºãããã«ãScalaã«ã€ããŠå°ã觊ããŸãã
åé¡ïŒæœåšçãªè¡æ¹äžæã®ãªããžã§ã¯ã
次ã®Javaã³ãŒãã®è¡ãèŠãŠãã ããã
return employee.getPerson().getAddress().getStreet();
ã³ã³ããã¹ãã§æ£åžžã«ã³ã³ãã€ã«ãããšä»®å®ãããšãçµéšè±å¯ãªç®ã¯ããã§æ·±å»ãªåé¡ã«æ°ã¥ãã§ããã-åŒã³åºããã§ãŒã³ã«è¿ããããªããžã§ã¯ãã®ãããããååšããªãå¯èœæ§ãããïŒã¡ãœããã¯nullãè¿ããŸãïŒããã®ã³ãŒããå®è¡ããããšç¡æ æ²ãªNullPointerExceptionãã¹ããŒãããŸã 幞ããªããšã«ã次ã®ããã«ããã®è¡ããã€ã§ãäžé£ã®ãã§ãã¯ã§å²ãããšãã§ããŸãã
if (employee != null && employee.getPerson() != null && employee.getPerson().getAddress() != null) { return employee.getPerson().getAddress().getStreet(); } else { return "<>"; }
ããèªäœã¯ããŸãè¯ãèŠããŸããããä»ã®ã³ãŒãã§äœæããã®ã¯ããã«æªãã§ãã ãããŠæãéèŠãªããšã¯ãå°ãªããšã1ã€ã®ãã§ãã¯ãå¿ãããšãå®è¡æã«äŸå€ãçºçããå¯èœæ§ãããããšã§ãã ããã¯ããªããžã§ã¯ãã®æœåšçãªäžåšã«é¢ããæ å ±ãäœããã®åœ¢ã§åºå®ãããŠããããã³ã³ãã€ã©ããšã©ãŒããç§ãã¡ãæãããšããªãããã§ãã ããããçµå±ã®ãšãããåŸæ¥å¡ãã人ãã人ããäœæããäœæããçªå°ãååŸãããšãã3ã€ã®åçŽãªé£ç¶ã¢ã¯ã·ã§ã³ãå®è¡ãããã£ãã ãã§ãã åçŽãªã¿ã¹ã¯ã®ããã«èŠããŸãããã³ãŒãã¯è£å©ãã§ãã¯ã§èšãäžãããå€èªã§ããªããªããŸããã
幞ããJava 8ã§ã¯java.util.Optionalã¿ã€ããå°å ¥ãããŸããã å€ãã®èå³æ·±ãæ¹æ³ããããŸããããããã«ã€ããŠèª¬æããŸãã
public class Optional<T> { public static <T> Optional<T> ofNullable(T value) { } public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { } public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { } }
Optionalã¯ã1ã€ã®èŠçŽ ãå«ãããäœãå«ãŸãªãã³ã³ãããšèŠãªãããšãã§ããŸãã ãã®ã³ã³ããã§mapã¡ãœãããåŒã³åºããããã§å¿åé¢æ°ïŒã©ã ãïŒãŸãã¯ã¡ãœãããžã®åç §ãæž¡ããšãmapã¯Optionalå ã®ãªããžã§ã¯ãã«ãã®é¢æ°ãé©çšããçµæãè¿ããŠãOptionalã§ã©ããããŸãã ãªããžã§ã¯ããå éšã«è¡šç€ºãããªãå Žåããããã¯åçŽã«ç©ºã®ãªãã·ã§ã³ã³ã³ãããŒãè¿ããŸãããåãã©ã¡ãŒã¿ãŒã¯ç°ãªããŸãã
flatMapã¡ãœããã䜿çšãããšãmapã¡ãœãããšåãããšãã§ããŸãããããèªäœãOptionalãè¿ãé¢æ°ãåãå ¥ããŸãããããã®é¢æ°ã䜿çšããçµæã¯ãOptionalã§ããã«ã©ããããããäºéã®ãã¹ãã¯åé¿ãããŸãã
ãã®ãããªãªãã·ã§ã³ã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšãããšãããšãã°æ¬¡ã®ããã«ãåŒã³åºãããã§ãŒã³ã§é 眮ã§ããŸãã
return Optional.ofNullable(employee) .map(Employee::getPerson) .map(Person::getAddress) .map(Address::getStreet) .orElse("<>");
åã®äŸãããå°ãã³ã³ãã¯ãã«èŠããŸãã ããããããã¯ããã§çµããã§ã¯ãããŸããã ãŸããã³ãŒãããç¡é¢ä¿ãªãã¹ãŠã®æ®»ãåé€ããŸãã-åŸæ¥å¡ãªããžã§ã¯ãã§ããã€ãã®ç°¡åãªã¢ã¯ã·ã§ã³ãå®è¡ããã³ãŒãã«äžèŠãªè£å©ã³ãŒããªãã§ããããæ瀺çã«èšè¿°ããŸããã 第äºã«ããã®ãã§ãŒã³ã®ãã¹ã®ã©ããã«ãã«å€ãããå ŽåãNPEããªãããšã確èªã§ããŸã-ãªãã·ã§ã³ã¯ããããç§ãã¡ãæããŸãã 第äžã«ãçµæã®ã³ã³ã¹ãã©ã¯ãã¯åŒã§ããïŒåã®äŸã®ifã³ã³ã¹ãã©ã¯ãã®ãããªã¢ãµãŒã·ã§ã³ã§ã¯ãããŸããïŒãå€ãè¿ãããšãæå³ããŸãããããã£ãŠãä»ã®ã³ãŒãã§äœæããæ¹ãã¯ããã«ç°¡åã§ãã
ããã§ã¯ããªãã·ã§ã³ã¿ã€ãã䜿çšããŠããªããžã§ã¯ãã®æœåšçãªäžåšã®åé¡ãã©ã®ããã«è§£æ±ºããŸãããïŒ
- åé¡ã¯ãªããžã§ã¯ãã¿ã€ãïŒãªãã·ã§ã³ã®<åŸæ¥å¡>ïŒã§æ確ã«ç€ºãããŸããã
- 圌ãã¯ããã®ã¿ã€ãå ã®ãã¹ãŠã®è£å©ã³ãŒãïŒãªããžã§ã¯ãã®äžåšããã§ãã¯ããïŒãé ããŸããã
- åçŽãªäžèŽã¢ã¯ã·ã§ã³ã®ã»ãããåã«æž¡ããŸãã
ããã§ãã¢ã¯ã·ã§ã³ã®äžèŽããšã¯äœãç解ããŠããŸããïŒ æ¬¡ã«ãPerson :: getAddressã¡ãœããããåã®Employee :: getPersonã¡ãœããã®çµæãšããŠåãåã£ãPersonåã®ãªããžã§ã¯ããåãå ¥ããŸãã ããŠãAddress :: getStreetã¡ãœããã¯ãããããåã®ã¢ã¯ã·ã§ã³ïŒPerson :: getAddressã¡ãœããã®åŒã³åºãïŒã®çµæãåãå ¥ããŸãã
ãããŠä»ãäž»ãªãã®ïŒJavaã®ãªãã·ã§ã³ã¯ãã¢ãããã¿ãŒã³ã®å®è£ ã«ãããŸããã
åé¡ïŒå埩
è¿å¹ŽJavaã«ç»å Žãããã¹ãŠã®æ§æç³è¡£ã«ãããããã¯ãã¯ãåé¡ã§ã¯ãªãããã«æãããŸãã ãã ãã次ã®ã³ãŒããèŠãŠãã ããã
List<String> employeeNames = new ArrayList<>(); for (Company company : companies) { for (Department department : company.getDepartments()) { for (Employee employee : department.getEmployees()) { employeeNames.add(employee.getName()); } } }
ããã§ã¯ããã¹ãŠã®éšéãšãã¹ãŠã®äŒæ¥ã®ãã¹ãŠã®åŸæ¥å¡ã®ååãåäžã®ãªã¹ãã«åéããŸãã ååãšããŠãã³ãŒãã®å€èŠ³ã¯ããã»ã©æªããããŸããããemployeeNamesãªã¹ããå€æŽããæç¶ãåã®ã¹ã¿ã€ã«ã¯ãããã°ã©ããŒã®é¡ãããããŸãã ããã«ãã³ãŒãã¯æããã«åé·ãªããã€ãã®ãã¹ããããå埩ãµã€ã¯ã«ã§æ§æãããŠããŸã-ãããã®å©ããåããŠã³ã¬ã¯ã·ã§ã³å埩ã¡ã«ããºã ã説æããŸãããæŠããŠããã¯ç§ãã¡ã«ãšã£ãŠèå³æ·±ããã®ã§ã¯ãããŸãããããã¹ãŠã®äŒæ¥ã®ãã¹ãŠã®éšéãããã¹ãŠã®äººã ãåéããååãååŸãããã ãã§ãã
Java 8ã§ã¯ããŸã£ããæ°ããAPIãå°å ¥ãããŸãããããã«ãããã³ã¬ã¯ã·ã§ã³ã®æäœããã䟿å©ã«ãªããŸãã ãã®APIã®ã¡ã€ã³ã€ã³ã¿ãŒãã§ãŒã¹ã¯java.util.stream.Streamã€ã³ã¿ãŒãã§ãŒã¹ã§ãããã®ã€ã³ã¿ãŒãã§ãŒã¹ã«ã¯ããšããããåã®äŸããããªãã¿ã®ã¡ãœãããå«ãŸããŠããŸãã
public interface Stream<T> extends BaseStream<T, Stream<T>> { <R> Stream<R> map(Function<? super T, ? extends R> mapper); <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); }
å®éããããã¡ãœããã¯ãOptionalã®å Žåã®ããã«ããªããžã§ã¯ããå ¥åãšããŠå€æããã³ã¬ã¯ã·ã§ã³ã®ãã¹ãŠã®èŠçŽ ã«é©çšããåä¿¡ããå€ææžã¿ãªããžã§ã¯ããã次ã®Streamãè¿ãé¢æ°ãåãåããŸãã flatMapã¡ãœããã¯ãããèªäœãStreamãè¿ãé¢æ°ãåãå ¥ããå€æäžã«åä¿¡ãããã¹ãŠã®ã¹ããªãŒã ãåäžã®Streamã«ããŒãžããŸãã
Streams APIã䜿çšããŠãå埩ã³ãŒãã次ã®ããã«æžãæããããšãã§ããŸãã
List<String> streamEmployeeNames = companies.stream() .flatMap(Company::getDepartmentsStream) .flatMap(Department::getEmployeesStream) .map(Employee::getName) .collect(toList());
ããã§ã¯ãJavaã®Streams APIã®å¶éãåé¿ããããã«å°ãããŸãããŸãããæ®å¿µãªãããæ¢åã®ã³ã¬ã¯ã·ã§ã³ã¯çœ®ãæããããŸããããæ©èœã³ã¬ã¯ã·ã§ã³ã®å®å šãªäžŠåãŠãããŒã¹ã§ãããã¹ããªãŒã ïŒïŒã¡ãœããã®ããŒã¿ã«ã§ãã ãããã£ãŠãããŒã¿åŠçäžã«ååŸãããåã³ã¬ã¯ã·ã§ã³ã¯ããã®å®å®ã§ãã³ãå®è¡ããå¿ èŠããããŸãã ãããè¡ãããã«ãã³ã¬ã¯ã·ã§ã³ã®ã²ãã¿ãŒãCompanyã¯ã©ã¹ãšDepartmentã¯ã©ã¹ã«è¿œå ããããããããã«Streamãªããžã§ã¯ãã«å€æããŸãã
static class Company { private List<Department> departments; public Stream<Department> getDepartmentsStream() { return departments.stream(); }
解決çã¯ãããã³ã³ãã¯ãã«èŠããŠãããã»ã©ã§ã¯ãããŸãããããã®å©ç¹ã¯ããã ãã§ã¯ãããŸããã å®éãããã¯ã³ã¬ã¯ã·ã§ã³ãæäœããããã®ä»£æ¿ã¡ã«ããºã ã§ãããããã³ã³ãã¯ãã§ãã¿ã€ãã»ãŒãã§ãæ§æå¯èœã§ããããã®å©ç¹ã¯ã³ãŒãã®éãšè€éããå¢ãã«ã€ããŠæããã«ãªãå§ããŸãã
ãããã£ãŠãã³ã¬ã¯ã·ã§ã³ã®èŠçŽ ã«å¯Ÿããå埩åé¡ã解決ããããã«äœ¿çšãããã¢ãããŒãã¯ããã§ã«ããç¥ãããŠããããã€ãã®ã¹ããŒãã¡ã³ãã®åœ¢åŒã§åã³å®åŒåã§ããŸãã
- åé¡ã¯ããªããžã§ã¯ãã¿ã€ãïŒã¹ããªãŒã <äŒç€Ÿ>ïŒã§æ確ã«ç€ºãããŸããã
- 圌ãã¯ãã®åã®äžã«ãã¹ãŠã®è£å©ã³ãŒããé ããŸããïŒèŠçŽ ãç¹°ãè¿ãããã®äžã§æž¡ãããé¢æ°ãåŒã³åºããŸãïŒã
- ãã®ã¿ã€ãã®ãªããžã§ã¯ãã«äžé£ã®åçŽãªãããã³ã°ã¢ã¯ã·ã§ã³ãæž¡ããŸããã
èŠçŽãããšãJavaã®Streamã€ã³ã¿ãŒãã§ãŒã¹ã¯ã¢ãããã¿ãŒã³ã®å®è£ ã§ãã
åé¡ïŒéåæã³ã³ãã¥ãŒãã£ã³ã°
ãããŸã§è¿°ã¹ãŠããããšãããã¢ãããã¿ãŒã³ã¯ãªããžã§ã¯ãã«å¯Ÿããäœããã®ã©ãããŒã®ååšãæ瀺ããŠããããã«èŠãããããããŸããããããã®ãªããžã§ã¯ãã«ã¯ããããã®ãªããžã§ã¯ããå€æããé¢æ°ãããã³ãããã®äœ¿çšã«é¢é£ãããã¹ãŠã®éå±ã§äžèŠãªã³ãŒããã¹ããŒã§ããŸãé¢æ°ãæœåšçãªãšã©ãŒã®åŠçããã€ãã¹ã¡ã«ããºã -ã©ãããŒå ã®èšè¿°ã ãããå®éã«ã¯ãã¢ããã®é©çšç¯å²ã¯ããã«åºããªã£ãŠããŸãã éåæã³ã³ãã¥ãŒãã£ã³ã°ã®åé¡ãèæ ®ããŠãã ããã
Thread thread1 = new Thread(() -> { String string = "Hello" + " world"; }); Thread thread2 = new Thread(() -> { int count = "Hello world".length(); });
èšç®ãå®è¡ãã2ã€ã®ç¬ç«ããã¹ã¬ããããããthread1ã®èšç®çµæã«å¯ŸããŠthread2ã®èšç®ãå®è¡ããå¿ èŠããããŸãã ããã§ã¯ããã®èšèšãæ©èœãããã¹ã¬ããåæã³ãŒããæäŸããããšã¯ããŸãããå€ãã®ã³ãŒãããããæãéèŠãªããšã¯ããã®ãããªèšç®ãããã¯ãå€æ°ãããšããŸãæ§æãããªãããšã§ãã ãããã次ã®2ã€ã®åçŽãªã¢ã¯ã·ã§ã³ã次ã ã«å®è¡ãããã£ãã ãã§ãããå®è¡ã®éåæã«ããããã¹ãŠã®ã«ãŒããæ··ä¹±ããŸãã
Java 5ã§ãé床ã®è€éããå æããããã«ãFutureãç»å Žãããã«ãã¹ã¬ããèšç®ã®ãããã¯ããã§ãŒã³ã§æŽçã§ããããã«ãªããŸããã æ®å¿µãªããã java.util.concurrent.Futureã¯ã©ã¹ã§ã¯ã銎æã¿ã®ããmapããã³flatMapã¡ãœããã¯èŠã€ãããŸãã-ã¢ãããã¿ãŒã³ãå®è£ ããŠããŸããïŒ CompletableFutureã®å®è£ ã¯ããã«ååã«è¿ãã§ããïŒã ãããã£ãŠãããã§ãå°ãããŒããããŠJavaãè¶ ããŠãèªè ã«Java 8ã§ç»å Žããå Žåã«Futureã€ã³ã¿ãŒãã§ãŒã¹ãã©ã®ããã«ãªããæ³åããè©Šã¿ãæ®ããŸãã Scalaæšæºã©ã€ãã©ãªã®scala.concurrent.Futureãã¬ã€ãã€ã³ã¿ãŒãã§ãŒã¹ãæ€èšããŠãã ããïŒã¡ãœããã·ã°ããã£ã¯å€å°ç°¡ç¥åãããŠããŸãïŒã
trait Future[+T] extends Awaitable[T] { def map[S](f: T => S): Future[S] def flatMap[S](f: T => Future[S]): Future[S] }
ããèŠããšãã¡ãœããã¯éåžžã«ããç¥ãããŠããŸãã mapã¡ãœããã¯ãæž¡ãããé¢æ°ãå°æ¥ã®å®è¡çµæã«é©çšããŸã-ãã®çµæãå©çšå¯èœã«ãªããšãã ããŠãflatMapã¡ãœããã¯ãããèªäœãæªæ¥ãè¿ãé¢æ°ã䜿çšããŸãããããã£ãŠãããã2ã€ã®å ç©ã¯flatMapã䜿çšããŠé£éã§ããŸãã
val f1 = Future { "Hello" + " world" } val f2 = { s: String => Future { s.length() } } Await.ready( f1.flatMap(f2) .map(println), 5.seconds )
ããã§ã¯ãèšç®ã®éåæçžäºäŸåãããã¯ãå®è¡ããåé¡ãã©ã®ããã«è§£æ±ºããŸãããïŒ
- åé¡ã¯ããªããžã§ã¯ãã¿ã€ãïŒå°æ¥[String]ïŒã§æ確ã«ç€ºãããŸããã
- 圌ãã¯ããã®ã¿ã€ãå ã«è£å©ã³ãŒãå šäœïŒåã®ãã§ãŒã³ã®æåŸã§æ¬¡ã®ãã§ãŒã³ãåŒã³åºãïŒãé ããŸããã
- ãã®ã¿ã€ãã®ãªããžã§ã¯ãã«äžé£ã®åçŽãªãããã³ã°ã¢ã¯ã·ã§ã³ãæž¡ããŸããïŒfutur f2ã¯ãã®ã¿ã€ãã®ãªããžã§ã¯ãïŒStringïŒãåãåããfutur f1ãè¿ããŸãïŒã
Future of Scalaãã¢ãããã¿ãŒã³ãå®è£ ããŠãããšèŠçŽã§ããŸãã
ãŸãšã
ã¢ããã¯ãå®å šã§ãªãè£å©ã³ãŒãã®ãã³ã«ãã£ãŠåé¢ãããå¯èœæ§ã®ããã¢ã¯ã·ã§ã³ãç°¡åã«æ§æïŒãã§ãŒã³ïŒã§ããããã«ããæ©èœçãªããã°ã©ãã³ã°ãã¿ãŒã³ã§ãã äžèšã®äŸã«å ããŠãé¢æ°åèšèªã§ã¯ãã¢ããã䜿çšããŠäŸå€çãªç¶æ³ãåŠçããI / OãããŒã¿ããŒã¹ãã¹ããŒã¿ã¹ãªã©ãåŠçããŸãã ã¢ãããã¿ãŒã³ã¯ãé¢æ°ãæåã®ã¯ã©ã¹ã®ãªããžã§ã¯ãã§ããä»»æã®èšèªã§å®è£ ãïŒå€ãšèŠãªããããåŒæ°ãšããŠæž¡ããªã©ïŒãJavaã§ãäžéšã®å Žæã§ééããŸãããäžéšã®å Žæã§ã¯å®è£ ãæãŸããŠããŸãæé«ã
ãã®ãããã¯ãããæ·±ãç解ããã«ã¯ã次ã®ãªãœãŒã¹ããå§ãããŸãã
- Scala MonadsïŒã¢ãããã¶ã€ã³ã§ã³ãŒããæŽçãã
- ãã©ã€ã¢ã³ã»ããã¯ãã³ïŒã¢ãããæããªã
- ããªãªã»ãã¹ã³ ã¢ãããžã£ã