SlideShare una empresa de Scribd logo
1 de 80
Descargar para leer sin conexión
DRYing to Monads
in
Java8
dhaval.dalal@software-artisan.com
@softwareartisan
class User {
private final String id;
private final String name;
User(final String id, final String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
Setting the context…
class Authenticator {
public User login(String id, String pwd) throws Exception {
// throw new Exception("password mismatch");
return new User(id, "Dhaval");
}
public User gmailLogin(String id, String pwd) throws Exception {
// throw new IOException("some problem");
return new User(id, "Dhaval");
}
public void twoFactor(User user, long pwd) {
// throw new RuntimeException("twoFactor Incorrect key");
}
}
class Dispatcher {
static void redirect(URL target) {
System.out.println("Going to => " + target);
}
}
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
TheHappyPath
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Do this first
TheHappyPath
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Do this first
Do this Second
TheHappyPath
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Do this first
Do this Second
Do this Third
TheHappyPath
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Modifies user that got
declared outside the
block scope of try.
Modifies target that
got declared outside the
block scope
of the try-catch
Pattern of Repeated
Behaviour
• Consume some data, return a result and pass it
to the next function for its consumption.
user = authenticator.login(userid, pwd);
• This is a very common pattern, where we mutate
a temp variable, only to be passed to the next
function in chain.
authenticator.twoFactor(user, twoFactorPwd);
Can we chain the two
try blocks and pass
data around implicitly?
But before chaining, we need to start with what is near
to us.
We have these functions wrapped in try blocks.
So thats our starting-point (near to us).
Ability to chain the functions wrapped in try blocks is
our goal and is far.
“From Near to Far”
• From Near to Far.
• That which is obvious and close to us now is the starting
point, a.k.a the inflection point.
• That which is far, and can be abstract is our goal.
• Take baby steps.
General Principles in
Refactoring
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
TheHappyPath
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
1
Essential code
wrapped in try
boiler-plate
TheHappyPath
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
1
Essential code
wrapped in try
boiler-plate
2
Essential Code
wrapped in try
boiler-plate
TheHappyPath
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
1
Essential code
wrapped in try
boiler-plate
2
Essential Code
wrapped in try
boiler-plate
3
Eventually
TheHappyPath
DRYing Boiler-plate
• Create a method that takes in different code blocks for try.
• Use lambda to wrap each code block and defer evaluation.
• As checked exception is thrown in the first try block, a regular
Java8 Supplier<T> will not work
• Instead pass the code block using exceptional Supplier<T>
- lets call it SupplierThrowsException<T>
• Exceptional SAM wraps the code that throws exception in a
lambda, catches it and returns T.
• We can do the same for the next try computation executed on
success.
Tiding up…
@FunctionalInterface
interface SupplierThrowsException<T, E extends Exception> {
T get() throws E;
}
class Test {
static <T, E extends Exception>
T tryWith(SupplierThrowsException<T, E> s) {
try {
return s.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception { … }
}
Tidingup…
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = Test.tryWith(() -> authenticator.login(userid, pwd));
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = Test.tryWith(() -> authenticator.gmailLogin(userid, pwd));
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
target = Test.tryWith(() -> {
authenticator.twoFactor(user, twoFactorPwd);
return dashboard;
});
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Tidingup…
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = Test.tryWith(() -> authenticator.login(userid, pwd));
} catch (Exception es) {
try {
user = Test.tryWith(() -> authenticator.gmailLogin(userid, pwd));
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
target = Test.tryWith(() -> {
authenticator.twoFactor(user, twoFactorPwd);
return dashboard;
});
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Compilation Error!!
“local variables referenced
from a lambda expression
must be final or effectively
final”
authenticator.twoFactor(user, twoFactorPwd);
Lets Pause and Reflect…
• Can we contain the user in a CUSTOM
CONTAINER, so that we can pass it to the next
computation in sequence, without needing to
reach outside the block scope of try-catch?
• Yes, that will solve the problem of declaring a user
outside.
• The container will hold the user within it (implicit data) and
pass it to the next computation in sequence.
Create a
Try<T> Container
Checked or
Unchecked
Exception.
Success
Failure
Value
Input(s)
Computation
It holds either the success value or the exception
resulting from the executing computation.
class Test {
static <T, E extends Exception>
T tryWith(SupplierThrowsException<T, E> s) {
try {
return s.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception { … }
}
IntroducingTry<T>
class Test {
static <T, E extends Exception>
T tryWith(SupplierThrowsException<T, E> s) {
try {
return s.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception { … }
}
IntroducingTry<T> class Try<T> {
static <T, E extends Exception>
T with(SupplierThrowsException<T, E> s) {
try {
return s.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Introduce Polymorphic
variants of Try<T>
• Success<T> - holds successful result of
computation.
• Failure<T> - holds exception from
computation.
VariantsofTry<T> class Try<T> {
static <T, E extends Exception>
Try<T> with(SupplierThrowsException<T, E> s) {
try {
return new Success<>(s.get());
return s.get();
} catch (Exception e) {
return new Failure<>(e);
throw new RuntimeException(e);
}
}
}
class Success<T> extends Try<T> {
private final T value;
Success(T value) { this.value = value; }
}
class Failure<T> extends Try<T> {
private final Exception e;
Failure(Exception e) { this.e = e; }
}
ApplyingTry<T>
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
Try<User> user;
Authenticator authenticator = new Authenticator();
try {
user = Try.with(() -> authenticator.login(userid, pwd));
} catch (Exception es) {
try {
user = Try.with(() -> authenticator.gmailLogin(userid, pwd));
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
Try<URL> target;
try {
long twoFactorPwd = 167840;
target = Try.with(() -> {
authenticator.twoFactor(user, twoFactorPwd);
return dashboard;
});
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
Try<User> user;
Authenticator authenticator = new Authenticator();
try {
user = Try.with(() -> authenticator.login(userid, pwd));
} catch (Exception es) {
try {
user = Try.with(() -> authenticator.gmailLogin(userid, pwd));
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
Try<URL> target;
try {
long twoFactorPwd = 167840;
target = Try.with(() -> {
authenticator.twoFactor(user, twoFactorPwd);
return dashboard;
});
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Compilation Error
“Incompatible types: Try<User>
cannot be converted to
User”
authenticator.twoFactor(user, twoFactorPwd);
ApplyingTry<T>
Time to address the
question:
How can we chain
the next try block?
Introducing chain
• Allows us to chain the two try blocks.
• Facilitate passing result/exception of earlier
computation on left (which is this) to the one
on right.
// (LEFT) returns Try<User>
Try.with(() -> authenticator.login(userid, pwd));
// (RIGHT) returns Try<URL>
Try.with(() -> {
authenticator.twoFactor(user, twoFactorPwd);
return dashboard;
});
Signature of chain
• Consumes a function that goes from: User -> Try<URL>
• Generically, a function from T -> Try<U>
• Produces Try<URL>
• Generically Try<U>
• Try<U> chain(Function<T, Try<U>> f)
Try.with(() -> authenticator.login(userid, pwd))
.chain(user -> Try.with(() -> {
authenticator.twoFactor(user, twoFactorPwd);
return dashboard;
}); // returns Try<URL>
Addingchain abstract class Try<T> {
static <T, E extends Exception>
Try<T> with(SupplierThrowsException<T, E> s) { … }
public abstract <U> Try<U> chain(Function<T, Try<U>> f);
}
class Success<T> extends Try<T> {
private final T value;
Success(T value) { this.value = value; }
public <U> Try<U> chain(Function<T, Try<U>> f) {
try { return f.apply(value); }
catch (Exception e) { return new Failure<U>(e); }
}
}
class Failure<T> extends Try<T> {
private final Exception e;
Failure(Exception e) { this.e = e; }
public <U> Try<U> chain(Function<T, Try<U>> f) {
return (Try<U>) this;
}
}
class Test {
public static void main(String[] args) throws Exception {
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}));
Dispatcher.redirect(target);
}
}
Applying chain
class Test {
public static void main(String[] args) throws Exception {
URL loginPage = new URL("http://login");
String userid = "softwareartisan";
String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}));
Dispatcher.redirect(target);
}
}
Applying chain
Compilation Error
“Incompatible types: Try<URL>
cannot be converted to
URL”
Dispatcher.redirect(target);
Addingget()
abstract class Try<T> {
static <T, E extends Exception>
Try<T> with(SupplierThrowsException<T, E> s) {
try { return new Success<>(s.get()); }
catch (Exception e) { return new Failure<>(e); }
}
public abstract <U> Try<U> chain(Function<T, Try<U>> f);
public abstract T get();
}
class Success<T> extends Try<T> {
private final T value;
Success(T value) { this.value = value; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() { return value; }
}
class Failure<T> extends Try<T> {
private final Exception e;
Failure(Exception e) { this.e = e; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() {
throw new RuntimeException("Failure cannot return", e);
}
}
class Test {
public static void main(String[] args) throws Exception {
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}));
Dispatcher.redirect(target.get());
}
}
Applying get
Visualizing the pipes
so far…
Try.with (system login)
chain (two factor authentication)
URL
Unhandled
Errors
Dashboard
class Test {
public static void main(String[] args) throws Exception {
URL loginPage = new URL("http://login");
String userid = "softwareartisan";
String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}));
Dispatcher.redirect(target.get());
}
}
// We have yet to tackle:
// 1. Recovery using gmailLogin
// 2. What about failure?
// 3. What about redirection to login URL upon failure (because
// of either login, or gmailLogin or twoFactor).
PendingItems
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
FailureRecovery
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
Try this first
FailureRecovery
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
Try this first
FailureRecovery
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
Try this first
FailureRecovery
In case of failure,
recover with
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
Try this first
Do this Second
FailureRecovery
In case of failure,
recover with
Introducing recoverWith
• Inside a Try<T> if the computation throws an
exception, we need to give it a chance to recover
from failure.
• Create a method recoverWith on Try<T> that
allows us to chain the code block inside catch.
• What will recoverWith’s signature look like?
• Consumes a function that goes from Throwable ->
Try<User>, generically, a function from Throwable ->
Try<U>
• Produces Try<User>, generically Try<U>
AddingrecoverWith
abstract class Try<T> {
static <T, E extends Exception>
Try<T> with(SupplierThrowsException<T, E> s) { … }
public abstract <U> Try<U> chain(Function<T, Try<U>> f);
public abstract T get();
public abstract <U> Try<U> recoverWith(Function<Exception, Try<U>> f);
}
class Success<T> extends Try<T> {
private final T value;
Success(T value) { this.value = value; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() { return value; }
public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) {
return (Try<U>) this;
}
}
class Failure<T> extends Try<T> {
private final Exception e;
Failure(Exception e) { this.e = e; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() { … }
public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) {
try { return f.apply(e); }
catch (Exception e) { return new Failure<U>(e); }
}
}
Applying recoverWith
class Test {
public static void main(String[] args) throws Exception {
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.recoverWith(e -> Try.with(() ->
authenticator.gmailLogin(userid, pwd)))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}))
Dispatcher.redirect(target.get());
}
}
Visualizing the pipes
again…
Try.with (System login)
recoverWith (gmail login)
URL
Unhandled
Errors
chain (two factor authentication)
Dashboard
PendingItemsclass Test {
public static void main(String[] args) throws Exception {
URL loginPage = new URL("http://login");
String userid = "softwareartisan";
String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.recoverWith(e -> Try.with(() ->
authenticator.gmailLogin(userid, pwd)))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}))
Dispatcher.redirect(target.get());
}
}
// We have yet to tackle:
// 1. Recovery using gmailLogin
// 2. What about failure?
// 3. What about the login URL redirection upon failure due to
// either login, or gmailLogin or twoFactor.
class Test {
public static void main(String[] args) throws Exception {
URL dashboard = new URL("http://dashboard");
URL loginPage = new URL("http://login");
String userid = "softwareartisan";
String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
IfRecoveryfails…
class Test {
public static void main(String[] args) throws Exception {
URL dashboard = new URL("http://dashboard");
URL loginPage = new URL("http://login");
String userid = "softwareartisan";
String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
IfRecoveryfails…
class Test {
public static void main(String[] args) throws Exception {
URL dashboard = new URL("http://dashboard");
URL loginPage = new URL("http://login");
String userid = "softwareartisan";
String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
IfRecoveryfails…
If recovery fails,
then do this and
go back
class Test {
public static void main(String[] args) throws Exception {
URL dashboard = new URL("http://dashboard");
URL loginPage = new URL("http://login");
String userid = "softwareartisan";
String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
IfRecoveryfails…
If recovery fails,
then do this and
go back
Don’t execute
this at all
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
IftwoFactorfails…
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
IftwoFactorfails…
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
IftwoFactorfails…
If twoFactor
fails, set target
to loginPage
Introducing orElse
• If recovery fails or if the next computation in the chain fails.
What do we do?
• Can we attach handlers as in the Chain of Responsibility
pattern?
• Create a method orElse on Try<T> that allows us to set-
up a handler chain.
• What will orElse’ signature look like?
• Consumes a Try<URL>,
• Generically, a Try<U>
• Produces Try<URL>, generically Try<U>
AddingorElse abstract class Try<T> {
static <T, E extends Exception>
Try<T> with(SupplierThrowsException<T, E> s) { … }
public abstract <U> Try<U> chain(Function<T, Try<U>> f);
public abstract T get();
public abstract <U> Try<U> recoverWith(Function<Exception, Try<U>> f);
public abstract Try<T> orElse(Try<T> other);
}
class Success<T> extends Try<T> {
private final T value;
Success(T value) { this.value = value; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() { return value; }
public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … }
public Try<T> orElse(Try<T> other) { return this; }
}
class Failure<T> extends Try<T> {
private final Exception e;
Failure(Exception e) { this.e = e; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() { … }
public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … }
public Try<T> orElse(Try<T> other) { return other; }
}
Applying orElse
class Test {
public static void main(String[] args) {
final String userid = "softwareartisan";
final String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.recoverWith(e -> Try.with(() ->
authenticator.gmailLogin(userid, pwd)))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}))
.orElse(Try.with(() -> new URL("http://login"))
Dispatcher.redirect(target.get());
}
}
Visualizing the pipes
again…Try.with (System login)
recoverWith (gmail login)
URL
Unhandled
Errors
chain (two factor authentication)
Dashboard
orElse (login URL)
PendingItems class Test {
public static void main(String[] args) {
final String userid = "softwareartisan";
final String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try<URL> target = Try.with(() -> authenticator.login(userid, pwd))
.recoverWith(e -> Try.with(() ->
authenticator.gmailLogin(userid, pwd)))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}))
.orElse(Try.with(() -> new URL("http://login"))
Dispatcher.redirect(target.get());
}
}
// We have yet to tackle:
// 1. Recovery using gmailLogin
// 2. What about failure?
// 3. What about the login URL redirection upon failure due to
// either login, or gmailLogin or twoFactor.
Getting from get is
Dangerous
• For Success, we get the actual value.
• For Failure, it throws.
• To do something useful with Success, we
consume its value.
• Whereas upon Failure, we have nothing to
consume.
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Aftergettingvalue…
were-direct
class Test {
public static void main(String[] args) throws Exception {
final URL dashboard = new URL("http://dashboard");
final URL loginPage = new URL("http://login");
final String userid = "softwareartisan";
final String pwd = "1234";
User user;
Authenticator authenticator = new Authenticator();
try {
user = authenticator.login(userid, pwd);
} catch (Exception es) {
try {
user = authenticator.gmailLogin(userid, pwd);
} catch(Exception eg) {
Dispatcher.redirect(loginPage);
return;
}
}
URL target;
try {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
target = dashboard;
} catch (Exception tfe) {
target = loginPage;
}
Dispatcher.redirect(target);
}
}
Perform
Side-effect
Aftergettingvalue…
were-direct
Introducing forEach
• What will forEach’s signature look like?
• Consumes a function that goes from URL -> (),
• Generically, a function from T -> (), this is our friendly
Java8 Consumer<T>
• Produces nothing - void
AddingforEach
abstract class Try<T> {
static <T, E extends Exception>
Try<T> with(SupplierThrowsException<T, E> s) { … }
public abstract <U> Try<U> chain(Function<T, Try<U>> f);
public abstract T get();
public abstract <U> Try<U> recoverWith(Function<Exception, Try<U>> f);
public abstract Try<T> orElse(Try<T> defaultValue);
public abstract void forEach(Consumer<T> c);
}
class Success<T> extends Try<T> {
private final T value;
Success(T value) { this.value = value; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() { return value; }
public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … }
public Try<T> orElse(Try<T> defaultValue) { return this; }
public void forEach(Consumer<T> c) { c.accept(value); }
}
class Failure<T> extends Try<T> {
private final Exception e;
Failure(Exception e) { this.e = e; }
public <U> Try<U> chain(Function<T, Try<U>> f) { … }
public T get() { … }
public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … }
public Try<T> orElse(Try<T> defaultValue) { return defaultValue; }
public void forEach(Consumer<T> c) { }
}
Applying forEach
class Test {
public static void main(String[] args) {
final String userid = "softwareartisan";
final String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try.with(() -> authenticator.login(userid, pwd))
.recoverWith(e -> Try.with(() ->
authenticator.gmailLogin(userid, pwd)))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}))
.orElse(Try.with(() -> new URL("http://login"))
.forEach(target -> Dispatcher.redirect(target));
}
}
Finally we are here!
class Test {
public static void main(String[] args) {
final String userid = "softwareartisan";
final String pwd = "1234";
Authenticator authenticator = new Authenticator();
Try.with(() -> authenticator.login(userid, pwd))
.recoverWith(e -> Try.with(() ->
authenticator.gmailLogin(userid, pwd)))
.chain(user -> Try.with(() -> {
long twoFactorPwd = 167840;
authenticator.twoFactor(user, twoFactorPwd);
return new URL("http://dashboard");
}))
.orElse(Try.with(() -> new URL("http://login"))
.forEach(Dispatcher::redirect);
}
}
Implementation available
on
http://dhavaldalal.github.io/Java8-Try
Monad
• One can view a Monad as representing a context and
we want to do computations within that context.
• chain - chains output of one function into the input of
the other, i.e., transform a function into composable
form
• inject - to inject a regular value in to the chain
• For Try<T> the value is a code block and, inject == with.
• chain + inject - these core functions define a
Monad.
Notions of Chaining and
Injection (Getting inside the Chain)
Observations
• Monad functions run the code in the context of
the monad itself by unwrapping the result.
• These functions let us use the value from its
monadic wrapper.
• Monad controls what happens inside it and what
gets out.
Essence of Try<T>
• Bring catching exceptions (a side-effect) under
control using compositionality.
• Pass the result of computation to a subsequent
computation in the chain.
• By-pass the chain of evaluation in case a
computation fails.
• Recover with other computation or a value and if
everything fails, resort to default handler in the
chain of responsibility.
Monad Laws
• Left Unit
• inject(x).chain(f) == f(x)
• Right Unit
• M.chain(inject) == M
• Associative
• (M.chain(f)).chain(g) == M.chain((x -> f(x)).chain(g))
with
Try
Practical Interpretation of
Monad Laws
• Left Unit: inject(x).chain(f) == f(x)
• Don’t complicate un-necessarily, if you know you can use f(x)
• The long form is identical in its effect to the short form.
• Right Unit: M.chain(inject) == M
• Again, the long form is identical in its effect to the short form.
• Associative: (M.chain(f)).chain(g) == M.chain((x ->
f(x)).chain(g))
• Refactor or Break up big computations in to smaller ones, and re-group
(compose) to create new computations while preserving their ordering.
Monad Laws
• Left Unit fails for Try<T>. Why?
• Try.with(expr).chain(f) != f(expr)
Monad Laws
• Left Unit fails for Try<T>. Why?
• Try.with(expr).chain(f) != f(expr)
x
LHS will
never raise
an exception
RHS will raise
an exception
thrown by f
or by expr
Monad Laws
• Left Unit fails for Try<T>. Why?
• Try.with(expr).chain(f) != f(expr)
x
LHS will
never raise
an exception
RHS will raise
an exception
thrown by f
or by expr
• Right Unit and Associative laws hold for Try.
• For practical purposes, you can still treat it as a Monad
Essence of Monads
• Bring the world of side-effects under control using
compositionality. (Brian Beckman)
• Compositionality is the way to control Complexity.
(Brian Beckman)
• Monads are commonly used to order sequences of
computation, but are not about ordering or sequencing.
(Haskell Wiki)
• Monads capture a -- very specific -- relationship
between values of a specific domain into a common
abstraction. (Haskell Wiki)
• Monadic structures are very common in our day-to-day
programming.
Language chain is a.k.a…
Scala flatMap or map and flatten
Java8 flatMap
C# SelectMany
Clojure mapcat
Haskell bind or >>=
Ruby flat_map
Groovy collect and flatten
Different names but are the same
References
• Real world Haskell
• Bryan O’ Sullivan, John Goerzen & Don Stewart.
• Don’t fear the Monad! - Channel 9
• Brian Beckman
• Principles of Reactive Programming - Coursera Course.
• Martin Odersky, Eric Meijer and Roland Kuhn
• Integral Education
• Sri Aurobindo’s Work and Sraddhalu Ranade’s talk.
Thank-you!

Más contenido relacionado

La actualidad más candente

Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Mario Fusco
 
Functional Javascript
Functional JavascriptFunctional Javascript
Functional Javascriptguest4d57e6
 
Jumping-with-java8
Jumping-with-java8Jumping-with-java8
Jumping-with-java8Dhaval Dalal
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: FunctionsAdam Crabtree
 
Java script advance-auroskills (2)
Java script advance-auroskills (2)Java script advance-auroskills (2)
Java script advance-auroskills (2)BoneyGawande
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife SpringMario Fusco
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8RichardWarburton
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)BoneyGawande
 
Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Trisha Gee
 
Leveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyDavid Gómez García
 
Booting into functional programming
Booting into functional programmingBooting into functional programming
Booting into functional programmingDhaval Dalal
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadJava9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadDavid Gómez García
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1José Paumard
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardMario Fusco
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript FunctionsBrian Moschel
 

La actualidad más candente (20)

Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
Functional Javascript
Functional JavascriptFunctional Javascript
Functional Javascript
 
Jumping-with-java8
Jumping-with-java8Jumping-with-java8
Jumping-with-java8
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: Functions
 
Java script advance-auroskills (2)
Java script advance-auroskills (2)Java script advance-auroskills (2)
Java script advance-auroskills (2)
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
 
Clean code slide
Clean code slideClean code slide
Clean code slide
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)
 
Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)
 
Leveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results Asynchrhonously
 
Booting into functional programming
Booting into functional programmingBooting into functional programming
Booting into functional programming
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadJava9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidad
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forward
 
Clean code
Clean codeClean code
Clean code
 
Ad java prac sol set
Ad java prac sol setAd java prac sol set
Ad java prac sol set
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
 

Similar a DRYing to Monad in Java8

Testing in android
Testing in androidTesting in android
Testing in androidjtrindade
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented NetworkingMostafa Amer
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeDaniel Wellman
 
Android Testing
Android TestingAndroid Testing
Android TestingEvan Lin
 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETtdc-globalcode
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
The definitive guide to java agents
The definitive guide to java agentsThe definitive guide to java agents
The definitive guide to java agentsRafael Winterhalter
 
Laporan multiclient chatting client server
Laporan multiclient chatting client serverLaporan multiclient chatting client server
Laporan multiclient chatting client servertrilestari08
 
Client server part 12
Client server part 12Client server part 12
Client server part 12fadlihulopi
 
Code generation for alternative languages
Code generation for alternative languagesCode generation for alternative languages
Code generation for alternative languagesRafael Winterhalter
 
Android ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAndroid ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAravindharamanan S
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsYakov Fain
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection apiMatthieu Aubry
 
Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Julien Truffaut
 

Similar a DRYing to Monad in Java8 (20)

Testing in android
Testing in androidTesting in android
Testing in android
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
Android Testing
Android TestingAndroid Testing
Android Testing
 
Week 12 code
Week 12 codeWeek 12 code
Week 12 code
 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
The definitive guide to java agents
The definitive guide to java agentsThe definitive guide to java agents
The definitive guide to java agents
 
JDK Power Tools
JDK Power ToolsJDK Power Tools
JDK Power Tools
 
Laporan multiclient chatting client server
Laporan multiclient chatting client serverLaporan multiclient chatting client server
Laporan multiclient chatting client server
 
Client server part 12
Client server part 12Client server part 12
Client server part 12
 
Testing in JavaScript
Testing in JavaScriptTesting in JavaScript
Testing in JavaScript
 
Code generation for alternative languages
Code generation for alternative languagesCode generation for alternative languages
Code generation for alternative languages
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Android ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAndroid ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codes
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSockets
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection api
 
Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!
 
Java objects on steroids
Java objects on steroidsJava objects on steroids
Java objects on steroids
 

Más de Dhaval Dalal

Test Pyramid in Microservices Context
Test Pyramid in Microservices ContextTest Pyramid in Microservices Context
Test Pyramid in Microservices ContextDhaval Dalal
 
Json Viewer Stories
Json Viewer StoriesJson Viewer Stories
Json Viewer StoriesDhaval Dalal
 
Mars rover-extension
Mars rover-extensionMars rover-extension
Mars rover-extensionDhaval Dalal
 
How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?Dhaval Dalal
 
Approaching ATDD/BDD
Approaching ATDD/BDDApproaching ATDD/BDD
Approaching ATDD/BDDDhaval Dalal
 
Paradigms Code jugalbandi
Paradigms Code jugalbandiParadigms Code jugalbandi
Paradigms Code jugalbandiDhaval Dalal
 
Data Reconciliation
Data ReconciliationData Reconciliation
Data ReconciliationDhaval Dalal
 
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr20154-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015Dhaval Dalal
 
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar20153-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015Dhaval Dalal
 
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015Dhaval Dalal
 
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueCodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueDhaval Dalal
 
The tao-of-transformation-workshop
The tao-of-transformation-workshopThe tao-of-transformation-workshop
The tao-of-transformation-workshopDhaval Dalal
 
Grooming with Groovy
Grooming with GroovyGrooming with Groovy
Grooming with GroovyDhaval Dalal
 
Language portfolio
Language portfolioLanguage portfolio
Language portfolioDhaval Dalal
 
A case-for-graph-db
A case-for-graph-dbA case-for-graph-db
A case-for-graph-dbDhaval Dalal
 
Transition contours
Transition contoursTransition contours
Transition contoursDhaval Dalal
 

Más de Dhaval Dalal (20)

Test Pyramid in Microservices Context
Test Pyramid in Microservices ContextTest Pyramid in Microservices Context
Test Pyramid in Microservices Context
 
Code Retreat
Code RetreatCode Retreat
Code Retreat
 
Json Viewer Stories
Json Viewer StoriesJson Viewer Stories
Json Viewer Stories
 
Value Objects
Value ObjectsValue Objects
Value Objects
 
Mars rover-extension
Mars rover-extensionMars rover-extension
Mars rover-extension
 
How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?
 
Approaching ATDD/BDD
Approaching ATDD/BDDApproaching ATDD/BDD
Approaching ATDD/BDD
 
Paradigms Code jugalbandi
Paradigms Code jugalbandiParadigms Code jugalbandi
Paradigms Code jugalbandi
 
Data Reconciliation
Data ReconciliationData Reconciliation
Data Reconciliation
 
CodeRetreat
CodeRetreatCodeRetreat
CodeRetreat
 
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr20154-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
 
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar20153-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
 
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
 
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueCodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
 
The tao-of-transformation-workshop
The tao-of-transformation-workshopThe tao-of-transformation-workshop
The tao-of-transformation-workshop
 
Grooming with Groovy
Grooming with GroovyGrooming with Groovy
Grooming with Groovy
 
Language portfolio
Language portfolioLanguage portfolio
Language portfolio
 
Code jugalbandi
Code jugalbandiCode jugalbandi
Code jugalbandi
 
A case-for-graph-db
A case-for-graph-dbA case-for-graph-db
A case-for-graph-db
 
Transition contours
Transition contoursTransition contours
Transition contours
 

Último

A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 

Último (20)

A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 

DRYing to Monad in Java8

  • 2. class User { private final String id; private final String name; User(final String id, final String name) { this.id = id; this.name = name; } public String getName() { return name; } public String getId() { return id; } } Setting the context…
  • 3. class Authenticator { public User login(String id, String pwd) throws Exception { // throw new Exception("password mismatch"); return new User(id, "Dhaval"); } public User gmailLogin(String id, String pwd) throws Exception { // throw new IOException("some problem"); return new User(id, "Dhaval"); } public void twoFactor(User user, long pwd) { // throw new RuntimeException("twoFactor Incorrect key"); } } class Dispatcher { static void redirect(URL target) { System.out.println("Going to => " + target); } }
  • 4. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } TheHappyPath
  • 5. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Do this first TheHappyPath
  • 6. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Do this first Do this Second TheHappyPath
  • 7. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Do this first Do this Second Do this Third TheHappyPath
  • 8. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Modifies user that got declared outside the block scope of try. Modifies target that got declared outside the block scope of the try-catch
  • 9. Pattern of Repeated Behaviour • Consume some data, return a result and pass it to the next function for its consumption. user = authenticator.login(userid, pwd); • This is a very common pattern, where we mutate a temp variable, only to be passed to the next function in chain. authenticator.twoFactor(user, twoFactorPwd);
  • 10. Can we chain the two try blocks and pass data around implicitly?
  • 11. But before chaining, we need to start with what is near to us. We have these functions wrapped in try blocks. So thats our starting-point (near to us). Ability to chain the functions wrapped in try blocks is our goal and is far. “From Near to Far”
  • 12. • From Near to Far. • That which is obvious and close to us now is the starting point, a.k.a the inflection point. • That which is far, and can be abstract is our goal. • Take baby steps. General Principles in Refactoring
  • 13. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } TheHappyPath
  • 14. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } 1 Essential code wrapped in try boiler-plate TheHappyPath
  • 15. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } 1 Essential code wrapped in try boiler-plate 2 Essential Code wrapped in try boiler-plate TheHappyPath
  • 16. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } 1 Essential code wrapped in try boiler-plate 2 Essential Code wrapped in try boiler-plate 3 Eventually TheHappyPath
  • 17. DRYing Boiler-plate • Create a method that takes in different code blocks for try. • Use lambda to wrap each code block and defer evaluation. • As checked exception is thrown in the first try block, a regular Java8 Supplier<T> will not work • Instead pass the code block using exceptional Supplier<T> - lets call it SupplierThrowsException<T> • Exceptional SAM wraps the code that throws exception in a lambda, catches it and returns T. • We can do the same for the next try computation executed on success.
  • 18. Tiding up… @FunctionalInterface interface SupplierThrowsException<T, E extends Exception> { T get() throws E; } class Test { static <T, E extends Exception> T tryWith(SupplierThrowsException<T, E> s) { try { return s.get(); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { … } }
  • 19. Tidingup… class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = Test.tryWith(() -> authenticator.login(userid, pwd)); user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = Test.tryWith(() -> authenticator.gmailLogin(userid, pwd)); user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; target = Test.tryWith(() -> { authenticator.twoFactor(user, twoFactorPwd); return dashboard; }); authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; }
  • 20. Tidingup… class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = Test.tryWith(() -> authenticator.login(userid, pwd)); } catch (Exception es) { try { user = Test.tryWith(() -> authenticator.gmailLogin(userid, pwd)); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; target = Test.tryWith(() -> { authenticator.twoFactor(user, twoFactorPwd); return dashboard; }); } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Compilation Error!! “local variables referenced from a lambda expression must be final or effectively final” authenticator.twoFactor(user, twoFactorPwd);
  • 21. Lets Pause and Reflect… • Can we contain the user in a CUSTOM CONTAINER, so that we can pass it to the next computation in sequence, without needing to reach outside the block scope of try-catch? • Yes, that will solve the problem of declaring a user outside. • The container will hold the user within it (implicit data) and pass it to the next computation in sequence.
  • 22. Create a Try<T> Container Checked or Unchecked Exception. Success Failure Value Input(s) Computation It holds either the success value or the exception resulting from the executing computation.
  • 23. class Test { static <T, E extends Exception> T tryWith(SupplierThrowsException<T, E> s) { try { return s.get(); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { … } } IntroducingTry<T>
  • 24. class Test { static <T, E extends Exception> T tryWith(SupplierThrowsException<T, E> s) { try { return s.get(); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { … } } IntroducingTry<T> class Try<T> { static <T, E extends Exception> T with(SupplierThrowsException<T, E> s) { try { return s.get(); } catch (Exception e) { throw new RuntimeException(e); } } }
  • 25. Introduce Polymorphic variants of Try<T> • Success<T> - holds successful result of computation. • Failure<T> - holds exception from computation.
  • 26. VariantsofTry<T> class Try<T> { static <T, E extends Exception> Try<T> with(SupplierThrowsException<T, E> s) { try { return new Success<>(s.get()); return s.get(); } catch (Exception e) { return new Failure<>(e); throw new RuntimeException(e); } } } class Success<T> extends Try<T> { private final T value; Success(T value) { this.value = value; } } class Failure<T> extends Try<T> { private final Exception e; Failure(Exception e) { this.e = e; } }
  • 27. ApplyingTry<T> class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; Try<User> user; Authenticator authenticator = new Authenticator(); try { user = Try.with(() -> authenticator.login(userid, pwd)); } catch (Exception es) { try { user = Try.with(() -> authenticator.gmailLogin(userid, pwd)); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } Try<URL> target; try { long twoFactorPwd = 167840; target = Try.with(() -> { authenticator.twoFactor(user, twoFactorPwd); return dashboard; }); } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } }
  • 28. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; Try<User> user; Authenticator authenticator = new Authenticator(); try { user = Try.with(() -> authenticator.login(userid, pwd)); } catch (Exception es) { try { user = Try.with(() -> authenticator.gmailLogin(userid, pwd)); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } Try<URL> target; try { long twoFactorPwd = 167840; target = Try.with(() -> { authenticator.twoFactor(user, twoFactorPwd); return dashboard; }); } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Compilation Error “Incompatible types: Try<User> cannot be converted to User” authenticator.twoFactor(user, twoFactorPwd); ApplyingTry<T>
  • 29. Time to address the question: How can we chain the next try block?
  • 30. Introducing chain • Allows us to chain the two try blocks. • Facilitate passing result/exception of earlier computation on left (which is this) to the one on right. // (LEFT) returns Try<User> Try.with(() -> authenticator.login(userid, pwd)); // (RIGHT) returns Try<URL> Try.with(() -> { authenticator.twoFactor(user, twoFactorPwd); return dashboard; });
  • 31. Signature of chain • Consumes a function that goes from: User -> Try<URL> • Generically, a function from T -> Try<U> • Produces Try<URL> • Generically Try<U> • Try<U> chain(Function<T, Try<U>> f) Try.with(() -> authenticator.login(userid, pwd)) .chain(user -> Try.with(() -> { authenticator.twoFactor(user, twoFactorPwd); return dashboard; }); // returns Try<URL>
  • 32. Addingchain abstract class Try<T> { static <T, E extends Exception> Try<T> with(SupplierThrowsException<T, E> s) { … } public abstract <U> Try<U> chain(Function<T, Try<U>> f); } class Success<T> extends Try<T> { private final T value; Success(T value) { this.value = value; } public <U> Try<U> chain(Function<T, Try<U>> f) { try { return f.apply(value); } catch (Exception e) { return new Failure<U>(e); } } } class Failure<T> extends Try<T> { private final Exception e; Failure(Exception e) { this.e = e; } public <U> Try<U> chain(Function<T, Try<U>> f) { return (Try<U>) this; } }
  • 33. class Test { public static void main(String[] args) throws Exception { final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })); Dispatcher.redirect(target); } } Applying chain
  • 34. class Test { public static void main(String[] args) throws Exception { URL loginPage = new URL("http://login"); String userid = "softwareartisan"; String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })); Dispatcher.redirect(target); } } Applying chain Compilation Error “Incompatible types: Try<URL> cannot be converted to URL” Dispatcher.redirect(target);
  • 35. Addingget() abstract class Try<T> { static <T, E extends Exception> Try<T> with(SupplierThrowsException<T, E> s) { try { return new Success<>(s.get()); } catch (Exception e) { return new Failure<>(e); } } public abstract <U> Try<U> chain(Function<T, Try<U>> f); public abstract T get(); } class Success<T> extends Try<T> { private final T value; Success(T value) { this.value = value; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { return value; } } class Failure<T> extends Try<T> { private final Exception e; Failure(Exception e) { this.e = e; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { throw new RuntimeException("Failure cannot return", e); } }
  • 36. class Test { public static void main(String[] args) throws Exception { final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })); Dispatcher.redirect(target.get()); } } Applying get
  • 37. Visualizing the pipes so far… Try.with (system login) chain (two factor authentication) URL Unhandled Errors Dashboard
  • 38. class Test { public static void main(String[] args) throws Exception { URL loginPage = new URL("http://login"); String userid = "softwareartisan"; String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })); Dispatcher.redirect(target.get()); } } // We have yet to tackle: // 1. Recovery using gmailLogin // 2. What about failure? // 3. What about redirection to login URL upon failure (because // of either login, or gmailLogin or twoFactor). PendingItems
  • 39. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } FailureRecovery
  • 40. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } Try this first FailureRecovery
  • 41. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } Try this first FailureRecovery
  • 42. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } Try this first FailureRecovery In case of failure, recover with
  • 43. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } Try this first Do this Second FailureRecovery In case of failure, recover with
  • 44. Introducing recoverWith • Inside a Try<T> if the computation throws an exception, we need to give it a chance to recover from failure. • Create a method recoverWith on Try<T> that allows us to chain the code block inside catch. • What will recoverWith’s signature look like? • Consumes a function that goes from Throwable -> Try<User>, generically, a function from Throwable -> Try<U> • Produces Try<User>, generically Try<U>
  • 45. AddingrecoverWith abstract class Try<T> { static <T, E extends Exception> Try<T> with(SupplierThrowsException<T, E> s) { … } public abstract <U> Try<U> chain(Function<T, Try<U>> f); public abstract T get(); public abstract <U> Try<U> recoverWith(Function<Exception, Try<U>> f); } class Success<T> extends Try<T> { private final T value; Success(T value) { this.value = value; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { return value; } public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { return (Try<U>) this; } } class Failure<T> extends Try<T> { private final Exception e; Failure(Exception e) { this.e = e; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { … } public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { try { return f.apply(e); } catch (Exception e) { return new Failure<U>(e); } } }
  • 46. Applying recoverWith class Test { public static void main(String[] args) throws Exception { final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .recoverWith(e -> Try.with(() -> authenticator.gmailLogin(userid, pwd))) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })) Dispatcher.redirect(target.get()); } }
  • 47. Visualizing the pipes again… Try.with (System login) recoverWith (gmail login) URL Unhandled Errors chain (two factor authentication) Dashboard
  • 48. PendingItemsclass Test { public static void main(String[] args) throws Exception { URL loginPage = new URL("http://login"); String userid = "softwareartisan"; String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .recoverWith(e -> Try.with(() -> authenticator.gmailLogin(userid, pwd))) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })) Dispatcher.redirect(target.get()); } } // We have yet to tackle: // 1. Recovery using gmailLogin // 2. What about failure? // 3. What about the login URL redirection upon failure due to // either login, or gmailLogin or twoFactor.
  • 49. class Test { public static void main(String[] args) throws Exception { URL dashboard = new URL("http://dashboard"); URL loginPage = new URL("http://login"); String userid = "softwareartisan"; String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } IfRecoveryfails…
  • 50. class Test { public static void main(String[] args) throws Exception { URL dashboard = new URL("http://dashboard"); URL loginPage = new URL("http://login"); String userid = "softwareartisan"; String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } IfRecoveryfails…
  • 51. class Test { public static void main(String[] args) throws Exception { URL dashboard = new URL("http://dashboard"); URL loginPage = new URL("http://login"); String userid = "softwareartisan"; String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } IfRecoveryfails… If recovery fails, then do this and go back
  • 52. class Test { public static void main(String[] args) throws Exception { URL dashboard = new URL("http://dashboard"); URL loginPage = new URL("http://login"); String userid = "softwareartisan"; String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } IfRecoveryfails… If recovery fails, then do this and go back Don’t execute this at all
  • 53. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } IftwoFactorfails…
  • 54. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } IftwoFactorfails…
  • 55. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } IftwoFactorfails… If twoFactor fails, set target to loginPage
  • 56. Introducing orElse • If recovery fails or if the next computation in the chain fails. What do we do? • Can we attach handlers as in the Chain of Responsibility pattern? • Create a method orElse on Try<T> that allows us to set- up a handler chain. • What will orElse’ signature look like? • Consumes a Try<URL>, • Generically, a Try<U> • Produces Try<URL>, generically Try<U>
  • 57. AddingorElse abstract class Try<T> { static <T, E extends Exception> Try<T> with(SupplierThrowsException<T, E> s) { … } public abstract <U> Try<U> chain(Function<T, Try<U>> f); public abstract T get(); public abstract <U> Try<U> recoverWith(Function<Exception, Try<U>> f); public abstract Try<T> orElse(Try<T> other); } class Success<T> extends Try<T> { private final T value; Success(T value) { this.value = value; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { return value; } public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … } public Try<T> orElse(Try<T> other) { return this; } } class Failure<T> extends Try<T> { private final Exception e; Failure(Exception e) { this.e = e; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { … } public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … } public Try<T> orElse(Try<T> other) { return other; } }
  • 58. Applying orElse class Test { public static void main(String[] args) { final String userid = "softwareartisan"; final String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .recoverWith(e -> Try.with(() -> authenticator.gmailLogin(userid, pwd))) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })) .orElse(Try.with(() -> new URL("http://login")) Dispatcher.redirect(target.get()); } }
  • 59. Visualizing the pipes again…Try.with (System login) recoverWith (gmail login) URL Unhandled Errors chain (two factor authentication) Dashboard orElse (login URL)
  • 60. PendingItems class Test { public static void main(String[] args) { final String userid = "softwareartisan"; final String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try<URL> target = Try.with(() -> authenticator.login(userid, pwd)) .recoverWith(e -> Try.with(() -> authenticator.gmailLogin(userid, pwd))) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })) .orElse(Try.with(() -> new URL("http://login")) Dispatcher.redirect(target.get()); } } // We have yet to tackle: // 1. Recovery using gmailLogin // 2. What about failure? // 3. What about the login URL redirection upon failure due to // either login, or gmailLogin or twoFactor.
  • 61. Getting from get is Dangerous • For Success, we get the actual value. • For Failure, it throws. • To do something useful with Success, we consume its value. • Whereas upon Failure, we have nothing to consume.
  • 62. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Aftergettingvalue… were-direct
  • 63. class Test { public static void main(String[] args) throws Exception { final URL dashboard = new URL("http://dashboard"); final URL loginPage = new URL("http://login"); final String userid = "softwareartisan"; final String pwd = "1234"; User user; Authenticator authenticator = new Authenticator(); try { user = authenticator.login(userid, pwd); } catch (Exception es) { try { user = authenticator.gmailLogin(userid, pwd); } catch(Exception eg) { Dispatcher.redirect(loginPage); return; } } URL target; try { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); target = dashboard; } catch (Exception tfe) { target = loginPage; } Dispatcher.redirect(target); } } Perform Side-effect Aftergettingvalue… were-direct
  • 64. Introducing forEach • What will forEach’s signature look like? • Consumes a function that goes from URL -> (), • Generically, a function from T -> (), this is our friendly Java8 Consumer<T> • Produces nothing - void
  • 65. AddingforEach abstract class Try<T> { static <T, E extends Exception> Try<T> with(SupplierThrowsException<T, E> s) { … } public abstract <U> Try<U> chain(Function<T, Try<U>> f); public abstract T get(); public abstract <U> Try<U> recoverWith(Function<Exception, Try<U>> f); public abstract Try<T> orElse(Try<T> defaultValue); public abstract void forEach(Consumer<T> c); } class Success<T> extends Try<T> { private final T value; Success(T value) { this.value = value; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { return value; } public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … } public Try<T> orElse(Try<T> defaultValue) { return this; } public void forEach(Consumer<T> c) { c.accept(value); } } class Failure<T> extends Try<T> { private final Exception e; Failure(Exception e) { this.e = e; } public <U> Try<U> chain(Function<T, Try<U>> f) { … } public T get() { … } public <U> Try<U> recoverWith(Function<Exception, Try<U>> f) { … } public Try<T> orElse(Try<T> defaultValue) { return defaultValue; } public void forEach(Consumer<T> c) { } }
  • 66. Applying forEach class Test { public static void main(String[] args) { final String userid = "softwareartisan"; final String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try.with(() -> authenticator.login(userid, pwd)) .recoverWith(e -> Try.with(() -> authenticator.gmailLogin(userid, pwd))) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })) .orElse(Try.with(() -> new URL("http://login")) .forEach(target -> Dispatcher.redirect(target)); } }
  • 67. Finally we are here! class Test { public static void main(String[] args) { final String userid = "softwareartisan"; final String pwd = "1234"; Authenticator authenticator = new Authenticator(); Try.with(() -> authenticator.login(userid, pwd)) .recoverWith(e -> Try.with(() -> authenticator.gmailLogin(userid, pwd))) .chain(user -> Try.with(() -> { long twoFactorPwd = 167840; authenticator.twoFactor(user, twoFactorPwd); return new URL("http://dashboard"); })) .orElse(Try.with(() -> new URL("http://login")) .forEach(Dispatcher::redirect); } }
  • 69. Monad • One can view a Monad as representing a context and we want to do computations within that context. • chain - chains output of one function into the input of the other, i.e., transform a function into composable form • inject - to inject a regular value in to the chain • For Try<T> the value is a code block and, inject == with. • chain + inject - these core functions define a Monad. Notions of Chaining and Injection (Getting inside the Chain)
  • 70. Observations • Monad functions run the code in the context of the monad itself by unwrapping the result. • These functions let us use the value from its monadic wrapper. • Monad controls what happens inside it and what gets out.
  • 71. Essence of Try<T> • Bring catching exceptions (a side-effect) under control using compositionality. • Pass the result of computation to a subsequent computation in the chain. • By-pass the chain of evaluation in case a computation fails. • Recover with other computation or a value and if everything fails, resort to default handler in the chain of responsibility.
  • 72. Monad Laws • Left Unit • inject(x).chain(f) == f(x) • Right Unit • M.chain(inject) == M • Associative • (M.chain(f)).chain(g) == M.chain((x -> f(x)).chain(g)) with Try
  • 73. Practical Interpretation of Monad Laws • Left Unit: inject(x).chain(f) == f(x) • Don’t complicate un-necessarily, if you know you can use f(x) • The long form is identical in its effect to the short form. • Right Unit: M.chain(inject) == M • Again, the long form is identical in its effect to the short form. • Associative: (M.chain(f)).chain(g) == M.chain((x -> f(x)).chain(g)) • Refactor or Break up big computations in to smaller ones, and re-group (compose) to create new computations while preserving their ordering.
  • 74. Monad Laws • Left Unit fails for Try<T>. Why? • Try.with(expr).chain(f) != f(expr)
  • 75. Monad Laws • Left Unit fails for Try<T>. Why? • Try.with(expr).chain(f) != f(expr) x LHS will never raise an exception RHS will raise an exception thrown by f or by expr
  • 76. Monad Laws • Left Unit fails for Try<T>. Why? • Try.with(expr).chain(f) != f(expr) x LHS will never raise an exception RHS will raise an exception thrown by f or by expr • Right Unit and Associative laws hold for Try. • For practical purposes, you can still treat it as a Monad
  • 77. Essence of Monads • Bring the world of side-effects under control using compositionality. (Brian Beckman) • Compositionality is the way to control Complexity. (Brian Beckman) • Monads are commonly used to order sequences of computation, but are not about ordering or sequencing. (Haskell Wiki) • Monads capture a -- very specific -- relationship between values of a specific domain into a common abstraction. (Haskell Wiki) • Monadic structures are very common in our day-to-day programming.
  • 78. Language chain is a.k.a… Scala flatMap or map and flatten Java8 flatMap C# SelectMany Clojure mapcat Haskell bind or >>= Ruby flat_map Groovy collect and flatten Different names but are the same
  • 79. References • Real world Haskell • Bryan O’ Sullivan, John Goerzen & Don Stewart. • Don’t fear the Monad! - Channel 9 • Brian Beckman • Principles of Reactive Programming - Coursera Course. • Martin Odersky, Eric Meijer and Roland Kuhn • Integral Education • Sri Aurobindo’s Work and Sraddhalu Ranade’s talk.