java - A better approach to handling exceptions in a functional way -


exceptions, checked ones, can severely interrupt flow of program logic when fp idiom used in java 8. here arbitrary example:

string s1 = "oeu", s2 = "2"; stream.of(s1, s2).foreach(s ->      system.out.println(optional.of(s).map(integer::parseint).get())); 

the above code breaks when there's exception unparseable string. want replace default value, can optional:

stream.of(s1, s2).foreach(s ->     system.out.println(optional.of(s)                               .map(integer::parseint)                               .orelse(-1))); 

of course, still fails because optional handles nulls. follows:

stream.of(s1, s2).foreach(s ->     system.out.println(         exceptional.of(s)                    .map(integer::parseint)                    .handle(numberformatexception.class, swallow())                    .orelse(-1))); 

note: self-answered question.

presented below full code of exceptional class. has quite large api pure extension of optional api can drop-in replacement in existing code—except isn't subtype of final optional class. class can seen being in same relationship try monad optional maybe monad: draws inspiration it, adapted java idiom (such throwing exceptions, non-terminal operations).

these key guidelines followed class:

  • as opposed monadic approach, doesn't ignore java's exception mechanism;

  • instead relieves impedance mismatch between exceptions , higher-order functions;

  • exception handling not statically typesafe (due sneaky throwing), safe @ runtime (never swallows exception except on explicit request).

the class tries cover typical ways handle exception:

  • recover handling code provides substitute value;
  • flatrecover which, analogous flatmap, allows return new exceptional instance unwrapped , state of current instance suitably updated;
  • propagate exception, throwing exceptional expression , making propagate call declare exception type;
  • propagate after wrapping exception (translate it);
  • handle it, resulting in empty exceptional;
  • as special case of handling, swallow empty handler block.

the propagate approach allows 1 selectively pick checked exceptions wants expose code. exceptions remain unhandled @ time terminal operation called (like get) sneakily thrown without declaration. considered advanced , dangerous approach, nevertheless employed way alleviate nuisance of checked exceptions in combination lambda shapes not declare them. exceptional class hopes offer cleaner , more selective alternative sneaky throw.


/*  * copyright (c) 2015, marko topolnik. rights reserved.  *  * licensed under apache license, version 2.0 (the "license");  * may not use file except in compliance license.  * may obtain copy of license @  *  * http://www.apache.org/licenses/license-2.0  *  * unless required applicable law or agreed in writing, software  * distributed under license distributed on "as is" basis,  * without warranties or conditions of kind, either express or implied.  * see license specific language governing permissions ,  * limitations under license.  */ import java.util.nosuchelementexception; import java.util.objects; import java.util.function.consumer; import java.util.function.function; import java.util.function.predicate; import java.util.function.supplier;  public final class exceptional<t> {   private final t value;   private final throwable exception;    private exceptional(t value, throwable exc) {     this.value = value;     this.exception = exc;   }    public static <t> exceptional<t> empty() {     return new exceptional<>(null, null);   }    public static <t> exceptional<t> ofnullable(t value) {     return value != null ? of(value) : empty();   }    public static <t> exceptional<t> of(t value) {     return new exceptional<>(objects.requirenonnull(value), null);   }    public static <t> exceptional<t> ofnullableexception(throwable exception) {     return exception != null? new exceptional<>(null, exception) : empty();   }    public static <t> exceptional<t> ofexception(throwable exception) {     return new exceptional<>(null, objects.requirenonnull(exception));   }    public static <t> exceptional<t> from(trysupplier<t> supplier) {     try {       return ofnullable(supplier.tryget());     } catch (throwable t) {       return new exceptional<>(null, t);     }   }    public static exceptional<void> fromvoid(tryrunnable task) {     try {       task.run();       return new exceptional<>(null, null);     } catch (throwable t) {       return new exceptional<>(null, t);     }   }    public static <e extends throwable> consumer<? super e> swallow() {     return e -> {};   }    public t get() {     if (value != null) return value;     if (exception != null) sneakythrow(exception);     throw new nosuchelementexception("no value present");   }    public t orelse(t other) {     if (value != null) return value;     if (exception != null) sneakythrow(exception);     return other;   }    public t orelseget(supplier<? extends t> other) {     if (value != null) return value;     if (exception != null) sneakythrow(exception);     return other.get();   }    public<u> exceptional<u> map(function<? super t, ? extends u> mapper) {     objects.requirenonnull(mapper);     if (value == null) return new exceptional<>(null, exception);     final u u;     try {       u = mapper.apply(value);     } catch (throwable exc) {       return new exceptional<>(null, exc);     }     return ofnullable(u);   }    public<u> exceptional<u> flatmap(function<? super t, exceptional<u>> mapper) {     objects.requirenonnull(mapper);     return value != null ? objects.requirenonnull(mapper.apply(value)) : empty();   }    public exceptional<t> filter(predicate<? super t> predicate) {     objects.requirenonnull(predicate);     if (value == null) return this;     final boolean b;     try {       b = predicate.test(value);     } catch (throwable t) {       return ofexception(t);     }     return b ? : empty();   }    public <x extends throwable> exceptional<t> recover(       class<? extends x> exctype, function<? super x, t> mapper)   {     objects.requirenonnull(mapper);     return exctype.isinstance(exception) ? ofnullable(mapper.apply(exctype.cast(exception))) : this;   }    public <x extends throwable> exceptional<t> recover(       iterable<class<? extends x>> exctypes, function<? super x, t> mapper)   {     objects.requirenonnull(mapper);     (class<? extends x> exctype : exctypes)       if (exctype.isinstance(exception))         return ofnullable(mapper.apply(exctype.cast(exception)));     return this;   }    public <x extends throwable> exceptional<t> flatrecover(       class<? extends x> exctype, function<? super x, exceptional<t>> mapper)   {     objects.requirenonnull(mapper);     return exctype.isinstance(exception) ? objects.requirenonnull(mapper.apply(exctype.cast(exception))) : this;   }    public <x extends throwable> exceptional<t> flatrecover(       iterable<class<? extends x>> exctypes, function<? super x, exceptional<t>> mapper)   {     objects.requirenonnull(mapper);     (class<? extends x> c : exctypes)       if (c.isinstance(exception))         return objects.requirenonnull(mapper.apply(c.cast(exception)));     return this;   }    public <e extends throwable> exceptional<t> propagate(class<e> exctype) throws e {     if (exctype.isinstance(exception))       throw exctype.cast(exception);     return this;   }    public <e extends throwable> exceptional<t> propagate(iterable<class<? extends e>> exctypes) throws e {     (class<? extends e> exctype : exctypes)       if (exctype.isinstance(exception))         throw exctype.cast(exception);     return this;   }    public <e extends throwable, f extends throwable> exceptional<t> propagate(       class<e> exctype, function<? super e, ? extends f> translator)   throws f   {     if (exctype.isinstance(exception))       throw translator.apply(exctype.cast(exception));     return this;   }    public <e extends throwable, f extends throwable> exceptional<t> propagate(       iterable<class<e>> exctypes, function<? super e, ? extends f> translator)   throws f   {     (class<? extends e> exctype : exctypes)       if (exctype.isinstance(exception))         throw translator.apply(exctype.cast(exception));     return this;   }    public <e extends throwable> exceptional<t> handle(class<e> exctype, consumer<? super e> action) {     if (exctype.isinstance(exception)) {       action.accept(exctype.cast(exception));       return empty();     }     return this;   }    public <e extends throwable> exceptional<t> handle(iterable<class<e>> exctypes, consumer<? super e> action) {     (class<? extends e> exctype : exctypes)       if (exctype.isinstance(exception)) {         action.accept(exctype.cast(exception));         return empty();       }     return this;   }    public <x extends throwable> t orelsethrow(supplier<? extends x> exceptionsupplier) throws x {     if (value != null) return value;     if (exception != null) sneakythrow(exception);     throw exceptionsupplier.get();   }    public boolean ispresent() {     return value != null;   }    public void ifpresent(consumer<? super t> consumer) {     if (value != null)       consumer.accept(value);     if (exception != null) sneakythrow(exception);   }    public boolean isexception() {     return exception != null;   }    @override   public boolean equals(object obj) {     if (this == obj) return true;     return obj instanceof exceptional && objects.equals(value, ((exceptional)obj).value);   }    @override   public int hashcode() {     return objects.hashcode(value);   }    @suppresswarnings("unchecked")   private static <t extends throwable> void sneakythrow(throwable t) throws t {     throw (t) t;   } } 

@functionalinterface public interface trysupplier<t> {   t tryget() throws throwable; } 

@functionalinterface public interface tryrunnable {   void run() throws throwable; } 

Comments

Popular posts from this blog

How to provide Authorization & Authentication using Asp.net, C#? -

toolbar - How to add link to user registration inside toobar in admin joomla 3 custom component -

How to use Authorization & Authentication in Asp.net, C#? -