View
112
Download
0
Category
Preview:
Citation preview
Poly-paradigm Java
Speaker
@pavletkopav@p12v.comPavel Tcholakov
Poly-what?
Programming styles• Imperative
• Object-oriented
• Aspect-oriented
• Functional
• Concurrent
• Actor
• Message-passing
• Logic, or rule-based
Lambda expressions(Pojo p) -> { return p.getProperty();}
Streams
IntStream.range(0, 100) .filter(i -> i % 2 == 0) .map(i -> i * i) .sum();
Longest string’s length
public int longestStringLength(List<String> strings) { return strings.stream() .mapToInt(String::length) .max() .getAsInt();}
Longest string’s length
public String longestString(List<String> strings) { return strings.stream() .mapToInt(String::length) .max() // Ehh, now what???}
Longest string’s length
public String longestString(List<String> strings) { final String[] maxString = {null};
strings.stream() .forEach(s -> { if (s.length() > maxString[0].length()) { maxString[0] = s; } });
return maxString[0];}
Longest string
public String longestString(List<String> strings) { return strings.stream() .reduce((s1, s2) -> s1.length() > s2.length() ? s1 : s2) .get();}
Longest string
public String longestString(List<String> strings) { return strings.stream() .max(Comparator.comparingInt(s -> s.length())) .get();}
Streams and functions
public List<String> findAllPalindromes(List<String> strings) { return strings.stream() .filter(s -> Objects.equals(s, StringUtils.reverse(s))) .collect(Collectors.toList());}
Functions, continued
public List<String> findAllPalindromes(List<String> strings) { return strings.stream() .filter(s -> Objects.equals(s, StringUtils.reverse(s))) .collect(Collectors.toList());}
Higher order functionpublic List<String> findUnchangedStrings( List<String> strings, Function<String, String> transformation) {
return strings.stream() .filter(s -> Objects.equals(s, transformation.apply(s))) .collect(Collectors.toList());}
Higher order, continued
public List<String> palindromes(List<String> strings) { return findUnchangedThings(strings, StringUtils::reverse);}
public List<String> findShouting(List<String> strings) { return findUnchangedThings(strings, StringUtils::capitalize);}
Generic enough?public List<String> findUnchangedStrings( List<String> strings, Function<String, String> transformation) {
return strings.stream() .filter(s -> Objects.equals(s, transformation.apply(s))) .collect(Collectors.toList());}
Type parameterspublic <T> List<T> findUnchangedThings( List<? extends T> things, Function<? super T, ? extends T> transformation) {
return things.stream() .filter(t -> Objects.equals(t, transformation.apply(t))) .collect(Collectors.toList());}
public List<String> palindromes(List<String> strings) { return findUnchangedThings(strings, StringUtils::reverse);}
public List<String> findShouting(List<String> strings) { return findUnchangedThings(strings, StringUtils::capitalize);}
public List<Integer> nonNegative(List<Integer> ints) { return findUnchangedThings(ints, Math::abs);}
public <T> List<T> findUnchangedThings( List<? extends T> things, Function<? super T, ? extends T> transformation) {
return things.stream() .filter(t -> Objects.equals(t, transformation.apply(t))) .collect(Collectors.toList());}
Monads?
Internal DSLs
Vagrant.configure("2") do |config| config.vm.box = "hashicorp/precise64" config.vm.provision :shell, path: "bootstrap.sh" config.vm.network :forwarded_port, guest: 80, host: 4567end
JavaSlang pattern matching
Stream.of(0, 1, 2, 3, 13, 14, null, -1) .peek(n -> out.print(format("%d -> ", n))) .map(Match.as(Object.class) .when(Objects::isNull).then("!") .whenIs(0).then("zero") .whenIsIn(1, 13, 14).then(i -> "first digit 1: " + i) .whenType(Double.class).then(d -> "Found a double: " + d) .whenApplicable((Number num) -> "number: " + num).thenApply() .otherwise(() -> "no match")) .map(Object::toString)
Actor model
Concurrency-oriented programming
• We identify all the truly concurrent activities in our real world activity.
• We identify all message channels between the concurrent activities.
• We write down all the messages which can flow on the different message channels.
— Joe Armstrong
Akka actor in Javapublic class Greeter extends AbstractActor {
String greeting = "";
public Greeter() {
receive(ReceiveBuilder. match(WhoToGreet.class, message -> greeting = "hello, " + message.who). match(Greet.class, message -> sender() .tell(new Greeting(greeting), self())). build()); }}
Logic programming
Prologfact.another_fact.
jug(jozi_jug).jug(virtual_jug).
java_meetup(java_day).
attendee(pavel, java_day).attendee(nitsan, java_day).attendee(richard, linux_meetup).
interested(java, Who) :- attendee(Who, Meetup), java_meetup(Meetup).
Demo
N-queens in Prologsolution([]).solution([X/Y|Others]) :- solution(Others), member(Y, [1,2,3,4,5,6,7,8]), noattack(X/Y, Others).
noattack(_, []).noattack(X/Y, [X1/Y1|Others]) :- Y =\= Y1, Y1 - Y =\= X1 - X, Y1 - Y =\= X - X1, noattack(X/Y,Others).
Sudoku in Clojure core.logic
(defn sudokufd [hints] (let [vars (repeatedly 81 lvar) rows (->> vars (partition 9) (map vec) (into [])) cols (apply map vector rows) sqs (for [x (range 0 9 3) y (range 0 9 3)] (get-square rows x y))] (run 1 [q] (== q vars) (everyg #(fd/in % (fd/domain 1 2 3 4 5 6 7 8 9)) vars) (init vars hints) (everyg fd/distinct rows) (everyg fd/distinct cols) (everyg fd/distinct sqs))))
Ok, how about some Java?
Rule-driven DCFT pattern
public interface Task {
boolean isInGoalState();
void handleEvents(Set<Event> events);
void applyRules(Consumer<Event> bus);
}
public boolean isInGoalState() { return state == MemberState.FOLLOWER && lastHeartbeat.plus(ELECTION_TIMEOUT).isAfter(clock.now());}
public void handleEvents(Set<Event> events) { for (Event evt : events) { if (evt instanceof AppendEntriesRpcReceived) { lastHeartbeat = clock.now(); } }}
public void applyRules(Consumer<Event> eventBus) { if (state == MemberState.FOLLOWER) { if (lastHeartbeat.plus(ELECTION_TIMEOUT).isAfter(clock.now())) { state = MemberState.CANDIDATE; eventBus.accept(new MemberStateChange(state)); eventBus.accept(new LeaderVote(serverId)); } else { // keep calm and carry on } } else { // nothing to do in other states }}
Causes of complexity
• State
• Control
• Code volume
• Others: complexity breeds complexity
FRP architecture• Essential State
➡ A Relational definition of the stateful components of the system
• Essential Logic
➡ Derived-relation definitions, integrity constraints and (pure) functions
• Accidental State and Control
➡ A declarative specification of a set of performance optimisations for the system
for (int i = 1; i <= 100; i++) {
if (i % 15 == 0) { out.println("FizzBuzz"); } else if (i % 3 == 0) { out.println("Fizz"); } else if (i % 5 == 0) { out.println("Buzz"); } else { out.println(i); }}
for (int i = 1; i <= 100; i++) {
if (i % 15 == 0) { out.println("FizzBuzz"); } else if (i % 3 == 0) { out.println("Fizz"); } else if (i % 5 == 0) { out.println("Buzz"); } else { out.println(i); }}
static Predicate<Integer> divisibleBy(Integer div) { return (i) -> i % div == 0;}
class Replacement { final Predicate<Integer> when; final String output;
public Replacement(Predicate<Integer> when, String output) { this.when = when; this.output = output; }}
List<Replacement> fizzAndOrBuzz = Collections.unmodifiableList(Arrays.asList( new Replacement(divisibleBy(3), "Fizz"), new Replacement(divisibleBy(5), "Buzz")));
static String replace(Integer i, List<Replacement> rules) { return rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output) .reduce(String::concat) .orElse(i.toString());}
static String replace(Integer i, List<Replacement> rules) { return rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output) .reduce(String::concat) .orElse(i.toString());}
static String replace(Integer i, List<Replacement> rules) { Stream<String> applicableReplacements = rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output);
return applicableReplacements .reduce(String::concat) .orElse(i.toString());}
static String fizzBuzz(Integer i) { return replace(i, fizzAndOrBuzz);}
// …
IntStream.rangeClosed(1, 100) .mapToObj(FizzBuzz::fizzBuzz) .forEach(out::println);
static Stream<String> fizzBuzz(IntStream intStream) { return intStream.mapToObj(FizzBuzz::fizzBuzz);}
// …
IntStream infiniteInts = IntStream.iterate(1, i -> i + 1);fizzBuzz(infiniteInts) .limit(100) .forEach(out::println);
public interface FizzBuzz {
class Replacement { final Predicate<Integer> when; final String output; … }
static Predicate<Integer> divisibleBy(Integer d) { return i -> i % d == 0; }
List<Replacement> fizzBuzzRules = unmodifiableList(asList( new Replacement(divisibleBy(3), "Fizz"), new Replacement(divisibleBy(5), "Buzz")));
static String replace(Integer i, List<Replacement> rules) { return rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output) .reduce(String::concat) .orElse(i.toString()); }
static void main(String... args) { IntStream.rangeClosed(1, 100) .mapToObj(i -> replace(i, fizzBuzzRules)) .forEach(out::println); }
}
PerformanceBenchmark Mode Cnt Score Error UnitsFizzBenchmark.functionalSolution avgt 5 13.122 ± 4.030 us/opFizzBenchmark.functionalSolution2 avgt 5 16.922 ± 2.558 us/opFizzBenchmark.imperativeSolution avgt 5 1.579 ± 0.142 us/op
2015 MacBook Pro 15”, i7 2.2GHz
Conclusions
Questions?
Feedback
@pavletkopav@p12v.comPavel Tcholakov
“Simplicity can only be attained if it is recognised, sought and prized.”
— Excerpt From: Ben Moseley, “Out of the Tar Pit.”
Thank you!
Recommended