In this post I will try to borrow one of the Scala nice related computation models into the Java language.
It is about the Try/Success/Failure computation model implemented by the Scala libraries.
In Scala the Try type represents a computation that may either result in an exception, or return a successfully computed value.
More details could be found here:
http://www.scala-lang.org/files/archive/nightly/docs/library/index.html#scala.util.Try
In the following chunks of code I will not use any functional capabilities of the JDK 1.8.
The whole point is to be able to chain more computations which result could be either a success or a failure. At the first apparition of the failure in any of the computations the remained computations will not be applied anymore and the failure will be propagated to the caller.
Please look at the following code snippet :
ComputationlResult<String> res = ComputationalTry.initComputation("1").bind(t0).bind(t1).getResult();
Here we pass an argument in our case the string "1" that will be processed one by one by the transformer "t0" and "t1".
We get the result of the chained computations stored in the "res" variable.
We can check if the chained computations were all successfully executed or if one of them failed. We can also extract the computed value or the cause of failure from the result.
Note also the "ITransformer" interface which presence here is needed when we do not use a functional approach.
Its only method "transform" is passed in the argument of generic type T and its function would be to apply a transformation on this argument and return the result.
Some would say that this is a monad based computation type. I wont go that far, so please regard this like a different way of chaining computations.
If you want a nice description of a monad which by the way is a simple structure and it should not be that hard to be comprehended please watch the first lectures given by Martin Odersky on Coursera.
[It might be just a coincidence, but for some reason after Martin's lecture on monads it seems that some light was shed on this topic]
Here is the link: Principles of Reactive Programming
And here is the whole code:
public class ComputationalTry<T> {
final private ComputationlResult<T> result;
static public <P> ComputationalTry<P> initComputation(P argument)
{
return new ComputationalTry<P>(argument);
}
private ComputationalTry(T param)
{
this.result = new ComputationalSuccess<T>(param);
}
private ComputationalTry(ComputationlResult<T> result)
{
this.result= result;
}
private ComputationlResult<T> applyTransformer(T t, ITransformer<T> transformer) {
try
{
return new ComputationalSuccess<T>(transformer.transform(t));
}
catch (Exception throwable)
{
return new ComputationalFailure<T, Exception>(throwable);
}
}
public ComputationalTry<T> bind(ITransformer<T> transformer)
{
if (result.isSuccess())
{
ComputationlResult<T> resultAfterTransf = this.applyTransformer(result.getResult(), transformer);
return new ComputationalTry<T>(resultAfterTransf);
}
else
{
return new ComputationalTry<T>(result);
}
}
public ComputationlResult<T> getResult()
{
return this.result;
}
}
public class ComputationalFailure<T, E extends Throwable> implements ComputationlResult<T> {
public ComputationalFailure(E exception)
{
this.exception = exception;
}
final private E exception;
@Override
public T getResult() {
return null;
}
@Override
public E getError() {
return exception;
}
@Override
public boolean isSuccess() {
return false;
}
}
public class ComputationalSuccess<T> implements ComputationlResult<T> {
public ComputationalSuccess(T result)
{
this.result = result;
}
final private T result;
@Override
public T getResult() {
return result;
}
@Override
public Throwable getError() {
return null;
}
@Override
public boolean isSuccess() {
return true;
}
}
public interface ComputationlResult<T> {
T getResult();
<E extends Throwable> E getError();
boolean isSuccess();
}
public interface ITransformer<T> {
public T transform(T t);
}
public class Test {
public static void main(String[] args) {
ITransformer<String> t0 = new ITransformer<String>() {
@Override
public String transform(String t) {
//return t + t;
throw new RuntimeException("some exception 1");
}
};
ITransformer<String> t1 = new ITransformer<String>() {
@Override
public String transform(String t) {
return "<" + t + ">";
//throw new RuntimeException("some exception 2");
}
};
ComputationlResult<String> res = ComputationalTry.initComputation("1").bind(t0).bind(t1).getResult();
System.out.println(res);
if (res.isSuccess())
{
System.out.println(res.getResult());
}
else
{
System.out.println(res.getError());
}
}
}
Thank you for bearing with me. Any suggestions are much appreciated.
public class ComputationalTry<T> {
final private ComputationlResult<T> result;
static public <P> ComputationalTry<P> initComputation(P argument)
{
return new ComputationalTry<P>(argument);
}
private ComputationalTry(T param)
{
this.result = new ComputationalSuccess<T>(param);
}
private ComputationalTry(ComputationlResult<T> result)
{
this.result= result;
}
private ComputationlResult<T> applyTransformer(T t, ITransformer<T> transformer) {
try
{
return new ComputationalSuccess<T>(transformer.transform(t));
}
catch (Exception throwable)
{
return new ComputationalFailure<T, Exception>(throwable);
}
}
public ComputationalTry<T> bind(ITransformer<T> transformer)
{
if (result.isSuccess())
{
ComputationlResult<T> resultAfterTransf = this.applyTransformer(result.getResult(), transformer);
return new ComputationalTry<T>(resultAfterTransf);
}
else
{
return new ComputationalTry<T>(result);
}
}
public ComputationlResult<T> getResult()
{
return this.result;
}
}
public class ComputationalFailure<T, E extends Throwable> implements ComputationlResult<T> {
public ComputationalFailure(E exception)
{
this.exception = exception;
}
final private E exception;
@Override
public T getResult() {
return null;
}
@Override
public E getError() {
return exception;
}
@Override
public boolean isSuccess() {
return false;
}
}
public class ComputationalSuccess<T> implements ComputationlResult<T> {
public ComputationalSuccess(T result)
{
this.result = result;
}
final private T result;
@Override
public T getResult() {
return result;
}
@Override
public Throwable getError() {
return null;
}
@Override
public boolean isSuccess() {
return true;
}
}
public interface ComputationlResult<T> {
T getResult();
<E extends Throwable> E getError();
boolean isSuccess();
}
public interface ITransformer<T> {
public T transform(T t);
}
public class Test {
public static void main(String[] args) {
ITransformer<String> t0 = new ITransformer<String>() {
@Override
public String transform(String t) {
//return t + t;
throw new RuntimeException("some exception 1");
}
};
ITransformer<String> t1 = new ITransformer<String>() {
@Override
public String transform(String t) {
return "<" + t + ">";
//throw new RuntimeException("some exception 2");
}
};
ComputationlResult<String> res = ComputationalTry.initComputation("1").bind(t0).bind(t1).getResult();
System.out.println(res);
if (res.isSuccess())
{
System.out.println(res.getResult());
}
else
{
System.out.println(res.getError());
}
}
}
Thank you for bearing with me. Any suggestions are much appreciated.