KEMBAR78
Scala is java8.next() | PDF
Scala is Java8.next()
Twitter - @blueiur
La-scala - daewon
// Before Java 8
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});

// Java 8
Collections.sort(strings, (s1, s2) -> s1.compareTo(s2));

Same thing different syntax
Programmer
●

http://office.naver.com
오! 벌써 새벽
3시네, 컴퓨
터 끄고 자야
겠어!

Programmer
●

http://daewon.github.io/
한 시간 후 ...
Overview
●
●

Scala
Java8 features
○
○

lambda
■ benefit of lambda expressions
comparison to Scala
●
●
●

Scalable Language
Born in 2003
Object-Oriented Meets Functional
Martin odersky
●
●

Designed the Scala programming language
Generic Java, and built the current generation of javac, the
Java compiler
Features
●
●
●
●
●
●

SEAMLESS JAVA INTEROP
TYPE INFERENCE
CONCURRENCY & DISTRIBUTION
TRAITS
PATTERN MATCHING
HIGHER-ORDER FUNCTIONS
Scala is used in many worldclass companies
Rod johnson joins typesafe
●
●

Creator of Spring
Keynote at ScalaDays 2013
○ Scala in 2018
●
●
●

Lambda Expressions
Method References
Virtual Extension Methods
●
●
●

Lambda Expressions
Method References
Virtual Extension Methods
Project Lambda - JSR 335
2006 - Gosling: "We will never have closures in Java"
2008 - Reinhold: "We will never have closures in Java"

Project Lambda
2007 - 3 different proposals for closures in Java
2009 - Start of project Lambda (JSR 335)

Project Lambda
JDK 8: General Availability - 2014/04/18
○
○
○
○

2006
2007
2008
2009

-

Gosling: "We will never have closures in Java"
3 different proposals for closures in Java
Reinhold: "We will never have closures in Java"
Start of project Lambda (JSR 335)
Lambda?
●
●
●
●

lambda calculus
anonymous function
function literal
closure
Lambda?
●
●
●
●

lambda calculus
anonymous function
function literal
closure
Anonymous Function
Wikipedia
●

function defined, and possibly called, without being bound
to an identifier.
익명 함수
Wikipedia
●

특정 식별자 없이 정의되거나 호출될 수 있는 함수
익명 함수
Wikipedia
●

특정 식별자 없이 정의되거나 호출될 수 있는 함수
Languages that support anonymous functions
ActionScript
Ada
C
C#
C++
Clojure
Curl
D
Dart
Dylan
Erlang
Elixir
F#
Frink
Go

Gosu
Groovy
Haskell
Java
JavaScript
Lisp
Logtalk
Lua
Mathematica
Maple
Matlab
Maxima
OCaml
Octave
Object Pascal

Objective-C
Pascal
Perl
PHP
Python
R
Racket
Ruby
Scala
Scheme
Smalltalk
Standard ML
TypeScript
Tcl
Vala
Visual Basic .NET
Visual Prolog
Languages that no support anonymous functions
ActionScript
Ada
C
C#
C++
Clojure
Curl
D
Dart
Dylan
Erlang
Elixir
F#
Frink
Go

Gosu
Groovy
Haskell
Java
JavaScript
Lisp
Logtalk
Lua
Mathematica
Maple
Matlab
Maxima
OCaml
Octave
Object Pascal

Objective-C
Pascal
Perl
PHP
Python
R
Racket
Ruby
Scala
Scheme
Smalltalk
Standard ML
TypeScript
Tcl
Vala
Visual Basic .NET
Visual Prolog
Languages that no support anonymous functions
ActionScript
Ada (1977)
C (1969)
C#
C++
Clojure
Curl
D
Dart
Dylan
Erlang
Elixir
F#
Frink
Go

Gosu
Groovy
Haskell
Java
JavaScript
Lisp
Logtalk
Lua
Mathematica
Maple
Matlab
Maxima
OCaml
Octave
Object Pascal

Objective-C
Pascal (1969)
Perl
PHP
Python
R
Racket
Ruby
Scala
Scheme
Smalltalk
Standard ML
TypeScript
Tcl
Vala
Visual Basic .NET
Visual Prolog
Languages that no support anonymous functions
ActionScript
Ada
C
C#
C++
Clojure
Curl
D
Dart
Dylan
Erlang
Elixir
F#
Frink
Go

Gosu
Groovy
Haskell
Java (1995)
JavaScript
Lisp
Logtalk
Lua
Mathematica
Maple
Matlab
Maxima
OCaml
Octave
Object Pascal

Objective-C
Pascal
Perl
PHP
Python
R
Racket
Ruby
Scala
Scheme
Smalltalk
Standard ML
TypeScript
Tcl
Vala
Visual Basic .NET
Visual Prolog
Java8 support Lambda
●

General Availability - 2014/04/18
Lambda syntax
●

(parameters) -> { body }

●

(int x, int y) -> { return x + y; }

Lambda Syntax
Lambda syntax
●
●
●
●

(param) -> {return 100}
(param) -> {100}
(param) -> 100
param -> 100

Lambda Syntax
Lambda syntax
●
●
●
●

(param) -> {return 100}
(param) -> {100}
(param) -> 100
param -> 100

Lambda Syntax
Lambda syntax
●
●
●
●

(param) -> {return 100}
(param) -> {100}
(param) -> 100
param -> 100

Lambda Syntax
Lambda syntax
●
●
●
●

(param) -> {return 100}
(param) -> {100}
(param) -> 100
param -> 100

Lambda Syntax
Lambda syntax
●
●
●
●

(param) -> {return 100}
(param) -> {100}
(param) -> 100
param -> 100

Lambda Syntax
Lambda syntax
●
●
●
●
●
●

x -> x + 1
(x) -> x + 1
(int x) -> x + 1
(int x, int y) -> x + y
(x, y) -> { System.out.println(x + y) }
() -> { System.out.println("runnable!"); }

Lambda Syntax
Storing Lambda
●
●
●

int n = 10;
String name = “daewon”;
? adder = (int x, int y) -> x + y
Storing Lambda
●
●
●

int n = 10;
String name = “daewon”;
? adder = (int x, int y) -> x + y
@Functional Interface
●

Lambda Expression -> Anonymous Inner Class
Replace with Lambda
@FunctionalInterface
interface Adder {
int add(int a, int b);
}

????? func = (int a, int b) -> { return a + b };
Adder shortFunc = (a, b) -> a + b;

Functional Interface
@FunctionalInterface
interface Adder {
int add(int a, int b);
}

Adder func = (int a, int b) -> { return a + b };
Adder shortFunc = (a, b) -> a + b;

Functional Interface
@FunctionalInterface
interface Adder {
int add(int a, int b);
}

Adder func = (int a, int b) -> { return a + b };
Adder shortFunc = (a, b) -> a + b;

Type Inference
Predefined Functional Interfaces
BiConsumer<T,U>
BiFunction<T,U,R>
BinaryOperator<T>
BiPredicate<T,U>
BooleanSupplier
Consumer<T>
DoubleBinaryOperator
DoubleConsumer
DoubleFunction<R>
DoublePredicate
DoubleSupplier
DoubleToIntFunction
DoubleToLongFunction
DoubleUnaryOperator
Function<T,R>
IntBinaryOperator
IntConsumer
IntFunction<R>

IntPredicate
IntSupplier
IntToDoubleFunction
IntToLongFunction
IntUnaryOperator
LongBinaryOperator
LongConsumer
LongFunction<R>
LongPredicate
LongSupplier
LongToDoubleFunction
LongToIntFunction
LongUnaryOperator
ObjDoubleConsumer<T>
ObjIntConsumer<T>
ObjLongConsumer<T>
Predicate<T>
Supplier<T>
Lambda in Java
●
●

anonymous inner class
lambda expressions
// Spring
jdbcTemplate.queryForObject("select * from student where id = ?",
new Object[]{1212l},
new RowMapper() {
public Object mapRow(ResultSet rs, int n) throws SQLException {
return new Student(rs.getString("name"), rs.getInt("age"));
}
});

// Google Guava
Iterables.filter(persons, new Predicate<Person>() {
public boolean apply(Person p) {
return p.getAge() > 18;
}
});
Lambda in Java
// Spring
jdbcTemplate.queryForObject("select * from student where id = ?",
new Object[]{1212l},
new RowMapper() {
public Object mapRow(ResultSet rs, int n) throws SQLException {
return new Student(rs.getString("name"), rs.getInt("age"));
}
});

// Google Guava
Iterables.filter(persons, new Predicate<Person>() {
public boolean apply(Person p) {
return p.getAge() > 18;
}
});
Lambda in Java
// Before Java 8
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});

// Java 8
Collections.sort(strings, (s1, s2) -> s1.compareTo(s2));

Bulky syntax!
// Java 8
Collections.sort(strings, (s1, s2) -> s1.compareTo(s2));

Clear syntax!
// Before Java 8
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});

// Java 8
Collections.sort(strings, (s1, s2) -> s1.compareTo(s2));

Same thing different syntax
Functions are Data
●
●
●

function as parameter
function as return value
lazy eval
함수는 데이터
●
●
●

함수를 다른 함수에 인자로 사용
함수를 함수의 반환 값으로 사용
지연 평가
함수는 데이터
●
●
●

함수를 다른 함수에 인자로 사용
함수를 함수의 반환값으로 사용
지연 평가
Functions as parameter - Loan Pattern
●

scala_for_java_programmer
public void withFile(String fileName) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
Print each line to STDOUT
public void withFile(String fileName) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
DB.store(line);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
Store each line to DB
public void withFile(String fileName) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// insert code at here
}
} catch (IOException ex) {
ex.printStackTrace();
System.out.println(line);
} finally {
if (bufferedReader != null)
DB.store(line);
bufferedReader.close();
}
}
Duplicate and Variation
public void withFile(String fileName, Consumer<String> work) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
work.accept(line);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
Refactoring with Lambda
public void withFile(String fileName, Consumer<String> work) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
work.accept(line);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
Refactoring with Lambda
// print each line to stdout
withFile(filename, line -> System.out.println(line));

// store each line to db
withFile(filename, line -> storeToDb(line));

// print and store each line
withFile(filename, line -> {
System.out.println(line)
storeToDb(line);
});

Refactoring with Lambda
// print each line to stdout
withFile(filename, line -> System.out.println(line));

// store each line to db
withFile(filename, line -> storeToDb(line));

Refactoring with Lambda
// Scala
def withFile(filename: String)(work: String => Unit) {
Source.fromFile(filename).getLines.forEach work
}

Scala
// Scala
def withFile(filename: String)(work: String => Unit) {
Source.fromFile(filename).getLines.forEach work
}

Scala
// Java8 - print each line to stdout
withFile(filename, line -> System.out.println(line));
// Java8 - store each line to db
withFile(filename, line -> storeToDb(line));

// Scala - print each line to stdout
withFile(filename) {
line => println(line)
}
// Scala - store each line to db
withFile(filename) {
line => storeToDb(line)
}
Multiple parameter lists(curried function)
Lambda with Collections
●
●

Imperative - external iteration
Functional - internal iteration
// External Iterator
for (Iterator iter = var.iterator(); iter.hasNext(); ) {
Object obj = iter.next();
// Operate on obj
}

// Internal Iterator
var.each( new Functor() {
public void operate(Object arg) {
arg *= 2;
}
});
Internal iterator? External iterator?
// External Iterator
for (Iterator iter = var.iterator(); iter.hasNext(); ) {
Object obj = iter.next();
// Operate on obj
}

// Internal Iterator
var.each( new Functor() {
public void operate(Object arg) {
arg *= 2;
}
});
When you pass a function object to a method to run over a
collection, that is an internal iterator
// External Iterator
for (Iterator iter = var.iterator(); iter.hasNext(); ) {
Object obj = iter.next();
// Operate on obj
}

// Internal Iterator
var.each( new Functor() {
public void operate(Object arg) {
arg *= 2;
}
});

컬렉션을 순회하는 동안 특정 행동을 하는 함수 객체를 전달하는 방식을
내부 반복자라고 한다
// External Iterator
for (Iterator iter = var.iterator(); iter.hasNext(); ) {
Object obj = iter.next();
// Operate on obj
}

// Internal Iterator
var.each( new Functor() {
public void operate(Object arg) {
arg *= 2;
}
});

컬렉션을 순회하는 동안 특정 행동을 하는 함수 객체를 전달하는 방식을
내부 반복자라고 한다
// Java8:: print each line to stdout
withFile(filename, line -> System.out.println(line));
// Java8 - store each line to db
withFile(filename, line -> storeToDb(line));
// Scala - print each line to stdout
withFile(filename) {
line => println(line)
}
// Scala:: store each line to db
withFile(filename) {
line => storeToDb(line)
}
Internal iterator
// Java8:: print each line to stdout
withFile(filename, line -> System.out.println(line));
// Java8 - store each line to db
withFile(filename, line -> storeToDb(line));
// Scala - print each line to stdout
withFile(filename) {
line => println(line)
}
// Scala:: store each line to db
withFile(filename) {
line => storeToDb(line)
}
Iterator
No more loop with Scala
●
●

Project Lambda J
Google guava-libraries/
case class Person(firstName: String, lastName: String, age:Int, male: Boolean)
case class Sale(buyer: Person, seller: Person, car: Car, cost: Double)
case class Car(brand: String, model: String, year: Int, originalValue: Double)

LambdaJ Demo Data Model
object db {
// car
val sonata = Car("Hyundai", "Sonata", 1982, 30000000)
val santafe = Car("Hyundai", "Santafe", 1990, 50000000)
val k7 = Car("KIA", "K7", 2000, 50000000)
val k9 = Car("KIA", "K9", 2008, 70000000)
val orlando = Car("GM", "Orlando", 2011, 30000000)
val chevrolet = Car("GM", "Chevrolet", 2010, 50000000)
val alpheon = Car("GM", "Alpheon", 2012, 70000000)
def cars = List(sonata, santafe, k7, k9, orlando, chevrolet, alpheon);
// person
val daewon = Person("daewon", "jeong", 31, true)
val youngtek = Person("youngtek", "hong", 32, true)
val jiwong = Person("jiwong", "kang", 34, true)
val taehee = Person("taehee", "kim", 32, false)
def persons = List(youngtek, daewon, jiwong, taehee)
// sales: map person/car
def sales = List(Sale(daewon, taehee, sonata, 30000000),
Sale(daewon, youngtek, santafe, 50000000),
Sale(daewon, jiwong, santafe, 50000000),
Sale(jiwong, taehee, santafe, 50000000),
Sale(taehee, daewon, chevrolet, 50000000),
Sale(youngtek, daewon, chevrolet, 50000000),
Sale(youngtek, taehee, orlando, 30000000),
Sale(taehee, jiwong, chevrolet, 30000000))
}
// Iterative version
List<Sale> salesOfAHyundai = new ArrayList<Sale>();
for (Sale sale : sales) {
if (sale.getCar().getBrand().equals("Hyundai")) {
salesOfAHyundai.add(sale);
}
}
// Functional version
val salesOfHyundai = db.sales.filter(_.car.brand == "Hyundai")

현대차를 판매하는 모든 Sales객체를 선택
// Iterative version
List<Sale> salesOfAHyundai = new ArrayList<Sale>();
for (Sale sale : sales) {
if (sale.getCar().getBrand().equals("Hyundai")) {
salesOfAHyundai.add(sale);
}
}
// Functional version
val salesOfHyundai = db.sales.filter(_.car.brand == "Hyundai")

sales 목록에서 car brand가 Hyundai인 것만 필터링
// Iterative version
List<Sale> salesOfAHyundai = new ArrayList<Sale>();
for (Sale sale : sales) {
if (sale.getCar().getBrand().equals("Hyundai")) {
salesOfAHyundai.add(sale);
}
}
// Functional version
val salesOfHyundai = db.sales.filter(_.car.brand == "Hyundai")

Select all sales of Hyundai
// Iterative version
List<Double> costs = new ArrayList<Double>();
for (Car car : cars) {
costs.add(car.getOriginalValue());
}
// Functional version
val costs = db.cars.map(_.originalValue)

자동차에 Original 가격 목록을 작성
// Iterative version
List<Double> costs = new ArrayList<Double>();
for (Car car : cars) {
costs.add(car.getOriginalValue());
}
// Functional version
val costs = db.cars.map(_.originalValue)

cars 목록으로부터 originalValue를 추출해서 새 목록을 작성
// Iterative version
List<Double> costs = new ArrayList<Double>();
for (Car car : cars) {
costs.add(car.getOriginalValue());
}
// Functional version
val costs = db.cars.map(_.originalValue)

Extract car’s original cost
// Iterative version
double maxCost = 0.0;
for (Sale sale : sales) {
double cost = sale.getCost();
if (cost > maxCost) {
maxCost = cost;
}
}
// Functional version
val maxCost = db.sales.maxBy(_.cost).cost

가장 비싸게 판매한 값은?
// Iterative version
double maxCost = 0.0;
for (Sale sale : sales) {
double cost = sale.getCost();
if (cost > maxCost) {
maxCost = cost;
}
}
// Functional version
val maxCost = db.sales.maxBy(_.cost).cost

Find most costly sale
// Iterative version
// 01. find youngest person in persons
Person youngest = null;
for (Person person : persons){
if (youngest == null || person.getAge() < youngest.getAge()) {
youngest = person;
}
}
// 02. find buyer have age equal to younggest person
List<Sale> buys = new ArrayList<Sale>();
for (Sale sale : sales){
if (sale.getBuyer().equals(youngest)) {
buys.add(sale);
}
}
// Functional version
val youngestPerson = db.persons.minBy( _.age )
val buys = db.sales.filter( _.buyer == youngestPerson )

가장 어린 사람과 나이가 같은 판매자들 찾기
// Iterative version
// 01. find youngest person in persons
Person youngest = null;
for (Person person : persons){
if (youngest == null || person.getAge() < youngest.getAge()) {
youngest = person;
}
}
// 02. find buyer have age equal to younggest person
List<Sale> buys = new ArrayList<Sale>();
for (Sale sale : sales){
if (sale.getBuyer().equals(youngest)) {
buys.add(sale);
}
}
// Functional version
val youngestPerson = db.persons.minBy( _.age )
val buys = db.sales.filter( _.buyer == youngestPerson )

Find buys of youngest person
// 01. 가장 어린 사람을 찾고
val youngestPerson = db.persons.minBy( _.age )
// 02. 가장 어린 사람과 나이가 같은 판매자들을 찾는다.
val buys = db.sales.filter( _.buyer == youngestPerson )

Find buys of youngest person
// Iterative version
Map<String, List<Car>> carsByBrand = new HashMap<>();
for (Car car : db.getCars()) {
List<Car> carList = carsByBrand.get(car);
if (carList == null){
carList = new ArrayList<Car>();
carsByBrand.put(car.getBrand(), carList);
}
carList.add(car);
}
// Functional version
val carsByBrand = db.cars.groupBy(_.brand)

brand 기준으로 car를 그루핑
// Iterative version
Map<String, List<Car>> carsByBrand = new HashMap<>();
for (Car car : db.getCars()) {
List<Car> carList = carsByBrand.get(car);
if (carList == null){
carList = new ArrayList<Car>();
carsByBrand.put(car.getBrand(), carList);
}
carList.add(car);
}
// Functional version
val carsByBrand = db.cars.groupBy(_.brand)

Select * from cars group by brand
// Iterative version
Map<String, List<Car>> carsByBrand = new HashMap<>();
for (Car car : db.getCars()) {
List<Car> carList = carsByBrand.get(car);
if (carList == null){
carList = new ArrayList<Car>();
carsByBrand.put(car.getBrand(), carList);
}
carList.add(car);
}
// Functional version
val carsByBrand = db.cars.groupBy(_.brand)

Index cars by brand
// Iterative version
Map<Car, Integer> carsBought = new HashMap<Car, Integer>();
for (Sale sale : sales) {
Car car = sale.getCar();
int boughtTimes = carsBought.get(car);
carsBought.put(car, boughtTimes == null ? 1 : boughtTimes+1);
}
Car mostBoughtCarIterative = null;
int boughtTimesIterative = 0;
for (Entry<Car, Integer> entry : carsBought.entrySet()) {
if (entry.getValue() > boughtTimesIterative) {
mostBoughtCarIterative = entry.getKey();
boughtTimesIterative = entry.getValue();
}
}

가장 많이 구매한 차
// Functional version
val carsBought = db.sales.groupBy( _.car ).mapValues( _.length )
val mostBoughtCar = carsBought.maxBy {
case (_, boughtCount) => boughtCount
}._1
val boughtTimes = carsBought(mostBoughtCar)

Find most bought car
// Functional version
val carsBought = db.sales.groupBy( _.car ).mapValues( _.length )
val mostBoughtCar = carsBought.maxBy {
case (_, boughtCount) => boughtCount
}._1
val boughtTimes = carsBought(mostBoughtCar)

Find most bought car
// Iterative version
Map<Person,Map<Person,Sale>> map = new HashMap<Person, Map<Person,Sale>>();
for (Sale sale : sales) {
Person buyer = sale.getBuyer();
Map<Person, Sale> buyerMap = map.get(buyer);
if (buyerMap == null) {
buyerMap = new HashMap<Person, Sale>();
map.put(buyer, buyerMap);
}
buyerMap.put(sale.getSeller(), sale);
}
Person youngest = null;
Person oldest = null;
for (Person person : persons) {
if (youngest == null || person.getAge() < youngest.getAge()){
youngest = person;
}
if (oldest == null || person.getAge() > oldest.getAge()) {
oldest = person;
}
}
Group sales by
Sale saleFromYoungestToOldest = map.get(youngest).get(oldest);

buyer and sellers
// Functional version
val map = db.sales.groupBy(_.buyer).mapValues{
ls => ls.groupBy(_.seller).mapValues(_.head)
}
val youngest = db.persons.minBy(_.age)
val oldest = db.persons.maxBy(_.age)
val saleFromYoungestToOldest = map(youngest)(oldest)

Group sales by buyer and sellers
Java8 Streams vs Scala For Comprehension
●
●

streams and sql
○ how-java-emulates-sql
for comprehension
// sql
select sum(salary)
from people
where gender = 'FEMALE'
// Java8 stream with lambda
people.stream()
.filter(p -> p.getGender() == Person.Gender.FEMALE)
.mapToInt(p -> p.getSalary())
.sum();

모든 여성의 급여의 합
// sql
select sum(salary)
from people
where gender = 'FEMALE'
// scala for comprehension
(for (p <- people;
(if p.gender == Person.Gender.FEMALE))
yield p.salary).sum()

Find the sum of all the salaries of all the females.
// sql
select sum(salary)
from people
where gender = 'FEMALE'
// scala for comprehension
(for (p <- people;
(if p.gender == Person.Gender.FEMALE))
yield p.salary).sum()

Find the sum of all the salaries of all the females.
// sql
select distinct(firstName)
from people
where gender = 'MALE'
// Java8 stream with lambda
people.stream()
.filter(p -> p.getGender() == Person.Gender.MALE)
.map(p -> p.getFirstName())
.distinct()

중복을 제거한 모든 남성의 이름
// sql
select distinct(firstName)
from people
where gender = 'MALE'
// scala for comprehension
(for (p <- people;
if (p.getGender == Person.Gender.MALE))
yield p.firstName).distinct

Prepare a list of all (distinct) first names of the males
// sql
select distinct(firstName)
from people
where gender = 'MALE'
// scala for comprehension
(for (p <- people;
if (p.getGender == Person.Gender.MALE))
yield p.firstName).distinct

Prepare a list of all (distinct) first names of the males
// sql
나이가 가장 많은 남자들
select *
from
people
where age =
(select max(age) from people where gender ='MALE' )
and
gender ='MALE'
// Java8
int maxAge = people.stream().max(
(p1, p2) -> p1.getAge() - p2.getAge()).get());
people.stream()
.filter(p -> p.getGender() == Person.Gender.MALE
&& p.getAge() == max_age)
.collect(Collections.toList()));
// scala for comprehension
for {
maxAge <- Seq(person.maxBy(_.age));
p <- people;
if (p.age == maxAge && p.gender == Person.Gender.MALE)
} yield p
Is Java8 a functional language?
●

What is Functional Programming?
○ Immutable state
○ Functions as first class citizens
○ Persistent data structure
Immutable
●
●

No setter
Variable must be final

final int i = 0;
while(i < 5) {
System.out.println("compile error!");
i++;
}
Persistent Data Structure
Java8
●
●
●

Immutable state
Functions as first class citizens
Persistent data structure

Scala
●
●
●

Immutable state
Functions as first class citizens
Persistent data structure
Java8 is not a functional language.
●
●
●

So what?

Real-world programming isn't always perfectly functional
Java is steel the most popular language in the world
Functional programming is not a silver bullet
자바는 함수형 언어가 아닙니다.
●
●
●

그래서요?

Real-world 문제가 항상 함수형에 적합하지는 않습니다
자바는 여전히 세계에서 가장 많이 쓰이고 있는 언어입니다
함수형 언어는 은탄환이 아닙니다
Java8 is Good!
Scala is Best!
One more thing
●

Lambda? Closure?
Lambda? Closure?
// lambda is just an anonymous function
Collection.filter(lists, e ‑> e.length() >= 5)

// closure is function that closes over the environment it was defined
int min = 5;
Collection.filter(lists, e -> e.length() >= min);
Lambda? Closure?
// lambda is just an anonymous function
Collection.filter(lists, e ‑> e.length() >= 5)

// closure is function that closes over the environment it was defined
int min = 5;
Collection.filter(lists, e -> e.length() >= min);
Lazy eval -

Better logging with Lambda
// log message only debug mode
public void debug(String message) {
if (log.isDebugEnabled()) {
log.log(message);
}
}

debug(some.expensive("operation"));

log expensive operation
// log message only debug mode
public void debug(String message) {
if (log.isDebugEnabled()) {
log.log(message);
}
}

debug(some.expensive("operation"));

log expensive operation
// log message only debug mode
public void debug(Consumer<String> consumer) {
if (log.isDebugEnabled()) {
log.log(consumer.accept());
}
}

debug(() -> some.expensive("operation"));

log expensive operation with Lambda
// log message only debug mode
public void debug(Consumer<String> consumer) {
if (log.isDebugEnabled()) {
log.log(consumer.accept());
}
}

debug(() -> some.expensive("operation"));

log expensive operation with Lambda
// without Lambda
debug(some.expensive("operation"));

// with Lambda
debug(() -> some.expensive("operation"));

bulk syntax!
// Scala
def debug(message: => String) {
if (log.isDebugEnabled) log.log(message)
}
debug(some.expensive("operation"))

Lazy eval in Scala
// Scala
def debug(message: => String) {
if (log.isDebugEnabled) log.log(message)
}
debug(some.expensive("operation"))

Lazy eval in Scala
// Java:: Eager eval
debug(some.expensive("operation"));
// Java8:: Lazy eval
debug(() -> some.expensive("operation"));
// scala:: Lazy eval
debug(some.expensive("operation"))
Question => Answer
// quiz
Lambda를 저장시 사용되는 인터페이스에 사용되는 Annotation은?

경품!

Scala is java8.next()

  • 1.
    Scala is Java8.next() Twitter- @blueiur La-scala - daewon
  • 2.
    // Before Java8 Collections.sort(strings, new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.compareTo(s2); } }); // Java 8 Collections.sort(strings, (s1, s2) -> s1.compareTo(s2)); Same thing different syntax
  • 3.
  • 4.
    오! 벌써 새벽 3시네,컴퓨 터 끄고 자야 겠어! Programmer ● http://daewon.github.io/ 한 시간 후 ...
  • 5.
  • 6.
    ● ● ● Scalable Language Born in2003 Object-Oriented Meets Functional
  • 7.
    Martin odersky ● ● Designed theScala programming language Generic Java, and built the current generation of javac, the Java compiler
  • 8.
    Features ● ● ● ● ● ● SEAMLESS JAVA INTEROP TYPEINFERENCE CONCURRENCY & DISTRIBUTION TRAITS PATTERN MATCHING HIGHER-ORDER FUNCTIONS
  • 9.
    Scala is usedin many worldclass companies
  • 10.
    Rod johnson joinstypesafe ● ● Creator of Spring Keynote at ScalaDays 2013 ○ Scala in 2018
  • 11.
  • 12.
  • 13.
  • 14.
    2006 - Gosling:"We will never have closures in Java" 2008 - Reinhold: "We will never have closures in Java" Project Lambda
  • 15.
    2007 - 3different proposals for closures in Java 2009 - Start of project Lambda (JSR 335) Project Lambda
  • 16.
    JDK 8: GeneralAvailability - 2014/04/18 ○ ○ ○ ○ 2006 2007 2008 2009 - Gosling: "We will never have closures in Java" 3 different proposals for closures in Java Reinhold: "We will never have closures in Java" Start of project Lambda (JSR 335)
  • 17.
  • 18.
  • 19.
    Anonymous Function Wikipedia ● function defined,and possibly called, without being bound to an identifier.
  • 20.
    익명 함수 Wikipedia ● 특정 식별자없이 정의되거나 호출될 수 있는 함수
  • 21.
    익명 함수 Wikipedia ● 특정 식별자없이 정의되거나 호출될 수 있는 함수
  • 22.
    Languages that supportanonymous functions ActionScript Ada C C# C++ Clojure Curl D Dart Dylan Erlang Elixir F# Frink Go Gosu Groovy Haskell Java JavaScript Lisp Logtalk Lua Mathematica Maple Matlab Maxima OCaml Octave Object Pascal Objective-C Pascal Perl PHP Python R Racket Ruby Scala Scheme Smalltalk Standard ML TypeScript Tcl Vala Visual Basic .NET Visual Prolog
  • 23.
    Languages that nosupport anonymous functions ActionScript Ada C C# C++ Clojure Curl D Dart Dylan Erlang Elixir F# Frink Go Gosu Groovy Haskell Java JavaScript Lisp Logtalk Lua Mathematica Maple Matlab Maxima OCaml Octave Object Pascal Objective-C Pascal Perl PHP Python R Racket Ruby Scala Scheme Smalltalk Standard ML TypeScript Tcl Vala Visual Basic .NET Visual Prolog
  • 24.
    Languages that nosupport anonymous functions ActionScript Ada (1977) C (1969) C# C++ Clojure Curl D Dart Dylan Erlang Elixir F# Frink Go Gosu Groovy Haskell Java JavaScript Lisp Logtalk Lua Mathematica Maple Matlab Maxima OCaml Octave Object Pascal Objective-C Pascal (1969) Perl PHP Python R Racket Ruby Scala Scheme Smalltalk Standard ML TypeScript Tcl Vala Visual Basic .NET Visual Prolog
  • 25.
    Languages that nosupport anonymous functions ActionScript Ada C C# C++ Clojure Curl D Dart Dylan Erlang Elixir F# Frink Go Gosu Groovy Haskell Java (1995) JavaScript Lisp Logtalk Lua Mathematica Maple Matlab Maxima OCaml Octave Object Pascal Objective-C Pascal Perl PHP Python R Racket Ruby Scala Scheme Smalltalk Standard ML TypeScript Tcl Vala Visual Basic .NET Visual Prolog
  • 26.
    Java8 support Lambda ● GeneralAvailability - 2014/04/18
  • 27.
    Lambda syntax ● (parameters) ->{ body } ● (int x, int y) -> { return x + y; } Lambda Syntax
  • 28.
    Lambda syntax ● ● ● ● (param) ->{return 100} (param) -> {100} (param) -> 100 param -> 100 Lambda Syntax
  • 29.
    Lambda syntax ● ● ● ● (param) ->{return 100} (param) -> {100} (param) -> 100 param -> 100 Lambda Syntax
  • 30.
    Lambda syntax ● ● ● ● (param) ->{return 100} (param) -> {100} (param) -> 100 param -> 100 Lambda Syntax
  • 31.
    Lambda syntax ● ● ● ● (param) ->{return 100} (param) -> {100} (param) -> 100 param -> 100 Lambda Syntax
  • 32.
    Lambda syntax ● ● ● ● (param) ->{return 100} (param) -> {100} (param) -> 100 param -> 100 Lambda Syntax
  • 33.
    Lambda syntax ● ● ● ● ● ● x ->x + 1 (x) -> x + 1 (int x) -> x + 1 (int x, int y) -> x + y (x, y) -> { System.out.println(x + y) } () -> { System.out.println("runnable!"); } Lambda Syntax
  • 34.
    Storing Lambda ● ● ● int n= 10; String name = “daewon”; ? adder = (int x, int y) -> x + y
  • 35.
    Storing Lambda ● ● ● int n= 10; String name = “daewon”; ? adder = (int x, int y) -> x + y
  • 36.
  • 37.
  • 38.
    @FunctionalInterface interface Adder { intadd(int a, int b); } ????? func = (int a, int b) -> { return a + b }; Adder shortFunc = (a, b) -> a + b; Functional Interface
  • 39.
    @FunctionalInterface interface Adder { intadd(int a, int b); } Adder func = (int a, int b) -> { return a + b }; Adder shortFunc = (a, b) -> a + b; Functional Interface
  • 40.
    @FunctionalInterface interface Adder { intadd(int a, int b); } Adder func = (int a, int b) -> { return a + b }; Adder shortFunc = (a, b) -> a + b; Type Inference
  • 41.
  • 43.
    Lambda in Java ● ● anonymousinner class lambda expressions
  • 44.
    // Spring jdbcTemplate.queryForObject("select *from student where id = ?", new Object[]{1212l}, new RowMapper() { public Object mapRow(ResultSet rs, int n) throws SQLException { return new Student(rs.getString("name"), rs.getInt("age")); } }); // Google Guava Iterables.filter(persons, new Predicate<Person>() { public boolean apply(Person p) { return p.getAge() > 18; } }); Lambda in Java
  • 45.
    // Spring jdbcTemplate.queryForObject("select *from student where id = ?", new Object[]{1212l}, new RowMapper() { public Object mapRow(ResultSet rs, int n) throws SQLException { return new Student(rs.getString("name"), rs.getInt("age")); } }); // Google Guava Iterables.filter(persons, new Predicate<Person>() { public boolean apply(Person p) { return p.getAge() > 18; } }); Lambda in Java
  • 46.
    // Before Java8 Collections.sort(strings, new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.compareTo(s2); } }); // Java 8 Collections.sort(strings, (s1, s2) -> s1.compareTo(s2)); Bulky syntax!
  • 47.
    // Java 8 Collections.sort(strings,(s1, s2) -> s1.compareTo(s2)); Clear syntax!
  • 48.
    // Before Java8 Collections.sort(strings, new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.compareTo(s2); } }); // Java 8 Collections.sort(strings, (s1, s2) -> s1.compareTo(s2)); Same thing different syntax
  • 49.
    Functions are Data ● ● ● functionas parameter function as return value lazy eval
  • 50.
    함수는 데이터 ● ● ● 함수를 다른함수에 인자로 사용 함수를 함수의 반환 값으로 사용 지연 평가
  • 51.
    함수는 데이터 ● ● ● 함수를 다른함수에 인자로 사용 함수를 함수의 반환값으로 사용 지연 평가
  • 52.
    Functions as parameter- Loan Pattern ● scala_for_java_programmer
  • 53.
    public void withFile(StringfileName) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } Print each line to STDOUT
  • 54.
    public void withFile(StringfileName) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { DB.store(line); } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } Store each line to DB
  • 55.
    public void withFile(StringfileName) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { // insert code at here } } catch (IOException ex) { ex.printStackTrace(); System.out.println(line); } finally { if (bufferedReader != null) DB.store(line); bufferedReader.close(); } } Duplicate and Variation
  • 56.
    public void withFile(StringfileName, Consumer<String> work) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { work.accept(line); } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } Refactoring with Lambda
  • 57.
    public void withFile(StringfileName, Consumer<String> work) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { work.accept(line); } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } Refactoring with Lambda
  • 58.
    // print eachline to stdout withFile(filename, line -> System.out.println(line)); // store each line to db withFile(filename, line -> storeToDb(line)); // print and store each line withFile(filename, line -> { System.out.println(line) storeToDb(line); }); Refactoring with Lambda
  • 59.
    // print eachline to stdout withFile(filename, line -> System.out.println(line)); // store each line to db withFile(filename, line -> storeToDb(line)); Refactoring with Lambda
  • 60.
    // Scala def withFile(filename:String)(work: String => Unit) { Source.fromFile(filename).getLines.forEach work } Scala
  • 61.
    // Scala def withFile(filename:String)(work: String => Unit) { Source.fromFile(filename).getLines.forEach work } Scala
  • 62.
    // Java8 -print each line to stdout withFile(filename, line -> System.out.println(line)); // Java8 - store each line to db withFile(filename, line -> storeToDb(line)); // Scala - print each line to stdout withFile(filename) { line => println(line) } // Scala - store each line to db withFile(filename) { line => storeToDb(line) } Multiple parameter lists(curried function)
  • 63.
    Lambda with Collections ● ● Imperative- external iteration Functional - internal iteration
  • 64.
    // External Iterator for(Iterator iter = var.iterator(); iter.hasNext(); ) { Object obj = iter.next(); // Operate on obj } // Internal Iterator var.each( new Functor() { public void operate(Object arg) { arg *= 2; } }); Internal iterator? External iterator?
  • 65.
    // External Iterator for(Iterator iter = var.iterator(); iter.hasNext(); ) { Object obj = iter.next(); // Operate on obj } // Internal Iterator var.each( new Functor() { public void operate(Object arg) { arg *= 2; } }); When you pass a function object to a method to run over a collection, that is an internal iterator
  • 66.
    // External Iterator for(Iterator iter = var.iterator(); iter.hasNext(); ) { Object obj = iter.next(); // Operate on obj } // Internal Iterator var.each( new Functor() { public void operate(Object arg) { arg *= 2; } }); 컬렉션을 순회하는 동안 특정 행동을 하는 함수 객체를 전달하는 방식을 내부 반복자라고 한다
  • 67.
    // External Iterator for(Iterator iter = var.iterator(); iter.hasNext(); ) { Object obj = iter.next(); // Operate on obj } // Internal Iterator var.each( new Functor() { public void operate(Object arg) { arg *= 2; } }); 컬렉션을 순회하는 동안 특정 행동을 하는 함수 객체를 전달하는 방식을 내부 반복자라고 한다
  • 68.
    // Java8:: printeach line to stdout withFile(filename, line -> System.out.println(line)); // Java8 - store each line to db withFile(filename, line -> storeToDb(line)); // Scala - print each line to stdout withFile(filename) { line => println(line) } // Scala:: store each line to db withFile(filename) { line => storeToDb(line) } Internal iterator
  • 69.
    // Java8:: printeach line to stdout withFile(filename, line -> System.out.println(line)); // Java8 - store each line to db withFile(filename, line -> storeToDb(line)); // Scala - print each line to stdout withFile(filename) { line => println(line) } // Scala:: store each line to db withFile(filename) { line => storeToDb(line) } Iterator
  • 70.
    No more loopwith Scala ● ● Project Lambda J Google guava-libraries/
  • 71.
    case class Person(firstName:String, lastName: String, age:Int, male: Boolean) case class Sale(buyer: Person, seller: Person, car: Car, cost: Double) case class Car(brand: String, model: String, year: Int, originalValue: Double) LambdaJ Demo Data Model
  • 72.
    object db { //car val sonata = Car("Hyundai", "Sonata", 1982, 30000000) val santafe = Car("Hyundai", "Santafe", 1990, 50000000) val k7 = Car("KIA", "K7", 2000, 50000000) val k9 = Car("KIA", "K9", 2008, 70000000) val orlando = Car("GM", "Orlando", 2011, 30000000) val chevrolet = Car("GM", "Chevrolet", 2010, 50000000) val alpheon = Car("GM", "Alpheon", 2012, 70000000) def cars = List(sonata, santafe, k7, k9, orlando, chevrolet, alpheon); // person val daewon = Person("daewon", "jeong", 31, true) val youngtek = Person("youngtek", "hong", 32, true) val jiwong = Person("jiwong", "kang", 34, true) val taehee = Person("taehee", "kim", 32, false) def persons = List(youngtek, daewon, jiwong, taehee) // sales: map person/car def sales = List(Sale(daewon, taehee, sonata, 30000000), Sale(daewon, youngtek, santafe, 50000000), Sale(daewon, jiwong, santafe, 50000000), Sale(jiwong, taehee, santafe, 50000000), Sale(taehee, daewon, chevrolet, 50000000), Sale(youngtek, daewon, chevrolet, 50000000), Sale(youngtek, taehee, orlando, 30000000), Sale(taehee, jiwong, chevrolet, 30000000)) }
  • 73.
    // Iterative version List<Sale>salesOfAHyundai = new ArrayList<Sale>(); for (Sale sale : sales) { if (sale.getCar().getBrand().equals("Hyundai")) { salesOfAHyundai.add(sale); } } // Functional version val salesOfHyundai = db.sales.filter(_.car.brand == "Hyundai") 현대차를 판매하는 모든 Sales객체를 선택
  • 74.
    // Iterative version List<Sale>salesOfAHyundai = new ArrayList<Sale>(); for (Sale sale : sales) { if (sale.getCar().getBrand().equals("Hyundai")) { salesOfAHyundai.add(sale); } } // Functional version val salesOfHyundai = db.sales.filter(_.car.brand == "Hyundai") sales 목록에서 car brand가 Hyundai인 것만 필터링
  • 75.
    // Iterative version List<Sale>salesOfAHyundai = new ArrayList<Sale>(); for (Sale sale : sales) { if (sale.getCar().getBrand().equals("Hyundai")) { salesOfAHyundai.add(sale); } } // Functional version val salesOfHyundai = db.sales.filter(_.car.brand == "Hyundai") Select all sales of Hyundai
  • 76.
    // Iterative version List<Double>costs = new ArrayList<Double>(); for (Car car : cars) { costs.add(car.getOriginalValue()); } // Functional version val costs = db.cars.map(_.originalValue) 자동차에 Original 가격 목록을 작성
  • 77.
    // Iterative version List<Double>costs = new ArrayList<Double>(); for (Car car : cars) { costs.add(car.getOriginalValue()); } // Functional version val costs = db.cars.map(_.originalValue) cars 목록으로부터 originalValue를 추출해서 새 목록을 작성
  • 78.
    // Iterative version List<Double>costs = new ArrayList<Double>(); for (Car car : cars) { costs.add(car.getOriginalValue()); } // Functional version val costs = db.cars.map(_.originalValue) Extract car’s original cost
  • 79.
    // Iterative version doublemaxCost = 0.0; for (Sale sale : sales) { double cost = sale.getCost(); if (cost > maxCost) { maxCost = cost; } } // Functional version val maxCost = db.sales.maxBy(_.cost).cost 가장 비싸게 판매한 값은?
  • 80.
    // Iterative version doublemaxCost = 0.0; for (Sale sale : sales) { double cost = sale.getCost(); if (cost > maxCost) { maxCost = cost; } } // Functional version val maxCost = db.sales.maxBy(_.cost).cost Find most costly sale
  • 81.
    // Iterative version //01. find youngest person in persons Person youngest = null; for (Person person : persons){ if (youngest == null || person.getAge() < youngest.getAge()) { youngest = person; } } // 02. find buyer have age equal to younggest person List<Sale> buys = new ArrayList<Sale>(); for (Sale sale : sales){ if (sale.getBuyer().equals(youngest)) { buys.add(sale); } } // Functional version val youngestPerson = db.persons.minBy( _.age ) val buys = db.sales.filter( _.buyer == youngestPerson ) 가장 어린 사람과 나이가 같은 판매자들 찾기
  • 82.
    // Iterative version //01. find youngest person in persons Person youngest = null; for (Person person : persons){ if (youngest == null || person.getAge() < youngest.getAge()) { youngest = person; } } // 02. find buyer have age equal to younggest person List<Sale> buys = new ArrayList<Sale>(); for (Sale sale : sales){ if (sale.getBuyer().equals(youngest)) { buys.add(sale); } } // Functional version val youngestPerson = db.persons.minBy( _.age ) val buys = db.sales.filter( _.buyer == youngestPerson ) Find buys of youngest person
  • 83.
    // 01. 가장어린 사람을 찾고 val youngestPerson = db.persons.minBy( _.age ) // 02. 가장 어린 사람과 나이가 같은 판매자들을 찾는다. val buys = db.sales.filter( _.buyer == youngestPerson ) Find buys of youngest person
  • 84.
    // Iterative version Map<String,List<Car>> carsByBrand = new HashMap<>(); for (Car car : db.getCars()) { List<Car> carList = carsByBrand.get(car); if (carList == null){ carList = new ArrayList<Car>(); carsByBrand.put(car.getBrand(), carList); } carList.add(car); } // Functional version val carsByBrand = db.cars.groupBy(_.brand) brand 기준으로 car를 그루핑
  • 85.
    // Iterative version Map<String,List<Car>> carsByBrand = new HashMap<>(); for (Car car : db.getCars()) { List<Car> carList = carsByBrand.get(car); if (carList == null){ carList = new ArrayList<Car>(); carsByBrand.put(car.getBrand(), carList); } carList.add(car); } // Functional version val carsByBrand = db.cars.groupBy(_.brand) Select * from cars group by brand
  • 86.
    // Iterative version Map<String,List<Car>> carsByBrand = new HashMap<>(); for (Car car : db.getCars()) { List<Car> carList = carsByBrand.get(car); if (carList == null){ carList = new ArrayList<Car>(); carsByBrand.put(car.getBrand(), carList); } carList.add(car); } // Functional version val carsByBrand = db.cars.groupBy(_.brand) Index cars by brand
  • 87.
    // Iterative version Map<Car,Integer> carsBought = new HashMap<Car, Integer>(); for (Sale sale : sales) { Car car = sale.getCar(); int boughtTimes = carsBought.get(car); carsBought.put(car, boughtTimes == null ? 1 : boughtTimes+1); } Car mostBoughtCarIterative = null; int boughtTimesIterative = 0; for (Entry<Car, Integer> entry : carsBought.entrySet()) { if (entry.getValue() > boughtTimesIterative) { mostBoughtCarIterative = entry.getKey(); boughtTimesIterative = entry.getValue(); } } 가장 많이 구매한 차
  • 88.
    // Functional version valcarsBought = db.sales.groupBy( _.car ).mapValues( _.length ) val mostBoughtCar = carsBought.maxBy { case (_, boughtCount) => boughtCount }._1 val boughtTimes = carsBought(mostBoughtCar) Find most bought car
  • 89.
    // Functional version valcarsBought = db.sales.groupBy( _.car ).mapValues( _.length ) val mostBoughtCar = carsBought.maxBy { case (_, boughtCount) => boughtCount }._1 val boughtTimes = carsBought(mostBoughtCar) Find most bought car
  • 90.
    // Iterative version Map<Person,Map<Person,Sale>>map = new HashMap<Person, Map<Person,Sale>>(); for (Sale sale : sales) { Person buyer = sale.getBuyer(); Map<Person, Sale> buyerMap = map.get(buyer); if (buyerMap == null) { buyerMap = new HashMap<Person, Sale>(); map.put(buyer, buyerMap); } buyerMap.put(sale.getSeller(), sale); } Person youngest = null; Person oldest = null; for (Person person : persons) { if (youngest == null || person.getAge() < youngest.getAge()){ youngest = person; } if (oldest == null || person.getAge() > oldest.getAge()) { oldest = person; } } Group sales by Sale saleFromYoungestToOldest = map.get(youngest).get(oldest); buyer and sellers
  • 91.
    // Functional version valmap = db.sales.groupBy(_.buyer).mapValues{ ls => ls.groupBy(_.seller).mapValues(_.head) } val youngest = db.persons.minBy(_.age) val oldest = db.persons.maxBy(_.age) val saleFromYoungestToOldest = map(youngest)(oldest) Group sales by buyer and sellers
  • 92.
    Java8 Streams vsScala For Comprehension ● ● streams and sql ○ how-java-emulates-sql for comprehension
  • 94.
    // sql select sum(salary) frompeople where gender = 'FEMALE' // Java8 stream with lambda people.stream() .filter(p -> p.getGender() == Person.Gender.FEMALE) .mapToInt(p -> p.getSalary()) .sum(); 모든 여성의 급여의 합
  • 95.
    // sql select sum(salary) frompeople where gender = 'FEMALE' // scala for comprehension (for (p <- people; (if p.gender == Person.Gender.FEMALE)) yield p.salary).sum() Find the sum of all the salaries of all the females.
  • 96.
    // sql select sum(salary) frompeople where gender = 'FEMALE' // scala for comprehension (for (p <- people; (if p.gender == Person.Gender.FEMALE)) yield p.salary).sum() Find the sum of all the salaries of all the females.
  • 97.
    // sql select distinct(firstName) frompeople where gender = 'MALE' // Java8 stream with lambda people.stream() .filter(p -> p.getGender() == Person.Gender.MALE) .map(p -> p.getFirstName()) .distinct() 중복을 제거한 모든 남성의 이름
  • 98.
    // sql select distinct(firstName) frompeople where gender = 'MALE' // scala for comprehension (for (p <- people; if (p.getGender == Person.Gender.MALE)) yield p.firstName).distinct Prepare a list of all (distinct) first names of the males
  • 99.
    // sql select distinct(firstName) frompeople where gender = 'MALE' // scala for comprehension (for (p <- people; if (p.getGender == Person.Gender.MALE)) yield p.firstName).distinct Prepare a list of all (distinct) first names of the males
  • 100.
    // sql 나이가 가장많은 남자들 select * from people where age = (select max(age) from people where gender ='MALE' ) and gender ='MALE' // Java8 int maxAge = people.stream().max( (p1, p2) -> p1.getAge() - p2.getAge()).get()); people.stream() .filter(p -> p.getGender() == Person.Gender.MALE && p.getAge() == max_age) .collect(Collections.toList())); // scala for comprehension for { maxAge <- Seq(person.maxBy(_.age)); p <- people; if (p.age == maxAge && p.gender == Person.Gender.MALE) } yield p
  • 102.
    Is Java8 afunctional language? ● What is Functional Programming? ○ Immutable state ○ Functions as first class citizens ○ Persistent data structure
  • 103.
    Immutable ● ● No setter Variable mustbe final final int i = 0; while(i < 5) { System.out.println("compile error!"); i++; }
  • 104.
  • 105.
    Java8 ● ● ● Immutable state Functions asfirst class citizens Persistent data structure Scala ● ● ● Immutable state Functions as first class citizens Persistent data structure
  • 106.
    Java8 is nota functional language. ● ● ● So what? Real-world programming isn't always perfectly functional Java is steel the most popular language in the world Functional programming is not a silver bullet
  • 107.
    자바는 함수형 언어가아닙니다. ● ● ● 그래서요? Real-world 문제가 항상 함수형에 적합하지는 않습니다 자바는 여전히 세계에서 가장 많이 쓰이고 있는 언어입니다 함수형 언어는 은탄환이 아닙니다
  • 108.
  • 109.
  • 110.
    Lambda? Closure? // lambdais just an anonymous function Collection.filter(lists, e ‑> e.length() >= 5) // closure is function that closes over the environment it was defined int min = 5; Collection.filter(lists, e -> e.length() >= min);
  • 111.
    Lambda? Closure? // lambdais just an anonymous function Collection.filter(lists, e ‑> e.length() >= 5) // closure is function that closes over the environment it was defined int min = 5; Collection.filter(lists, e -> e.length() >= min);
  • 112.
    Lazy eval - Betterlogging with Lambda
  • 113.
    // log messageonly debug mode public void debug(String message) { if (log.isDebugEnabled()) { log.log(message); } } debug(some.expensive("operation")); log expensive operation
  • 114.
    // log messageonly debug mode public void debug(String message) { if (log.isDebugEnabled()) { log.log(message); } } debug(some.expensive("operation")); log expensive operation
  • 115.
    // log messageonly debug mode public void debug(Consumer<String> consumer) { if (log.isDebugEnabled()) { log.log(consumer.accept()); } } debug(() -> some.expensive("operation")); log expensive operation with Lambda
  • 116.
    // log messageonly debug mode public void debug(Consumer<String> consumer) { if (log.isDebugEnabled()) { log.log(consumer.accept()); } } debug(() -> some.expensive("operation")); log expensive operation with Lambda
  • 117.
    // without Lambda debug(some.expensive("operation")); //with Lambda debug(() -> some.expensive("operation")); bulk syntax!
  • 118.
    // Scala def debug(message:=> String) { if (log.isDebugEnabled) log.log(message) } debug(some.expensive("operation")) Lazy eval in Scala
  • 119.
    // Scala def debug(message:=> String) { if (log.isDebugEnabled) log.log(message) } debug(some.expensive("operation")) Lazy eval in Scala
  • 120.
    // Java:: Eagereval debug(some.expensive("operation")); // Java8:: Lazy eval debug(() -> some.expensive("operation")); // scala:: Lazy eval debug(some.expensive("operation"))
  • 121.
  • 122.
    // quiz Lambda를 저장시사용되는 인터페이스에 사용되는 Annotation은? 경품!