Skip to content

LeakyAbstractions/result-api

Repository files navigation

Build Status Quality Gate Status Maven Central Javadoc Benchmark Report

Result Library for Java

A Java library to handle success and failure without exceptions

Result Library for Java

The purpose of this library is to provide a type-safe encapsulation of operation results that may have succeeded or failed, instead of throwing exceptions.

If you like Optional but feel that it sometimes falls too short, you'll love Result.

The best way to think of Result is as a super-powered version of Optional. The only difference is that whereas Optional may contain a successful value or express the absence of a value, Result contains either a successful value or a failure value that explains what went wrong.

Result objects have methods equivalent to those in Optional, plus a few more to handle failure values.
Optional Result
isPresent hasSuccess
isEmpty hasFailure
get getSuccess
getFailure
orElse orElse
orElseGet orElseMap
orElseThrow
stream streamSuccess
streamFailure
ifPresent ifSuccess
ifFailure
ifPresentOrElse ifSuccessOrElse
filter filter
recover
map mapSuccess
mapFailure
map
flatMap flatMapSuccess
or flatMapFailure
flatMap

Result Library in a Nutshell

Before Result, we would wrap exception-throwing foobar method invocation inside a try block so that errors can be handled inside a catch block.

public int getFoobarLength() {
    int length;
    try {
        final String result = foobar();
        this.commit(result);
        length = result.length();
    } catch(SomeException problem) {
        this.rollback(problem);
        length = -1;
    }
    return length;
}

This approach is lengthy, and that's not the only problem -- it's also very slow. Conventional wisdom says that exceptional logic shouldn't be used for normal program flow. Result makes us deal with expected, non-exceptional error situations explicitly as a way of enforcing good programming practices.

Let's now look at how the above code could be refactored if method foobar returned a Result object instead of throwing an exception:

public int getFoobarLength() {
    final Result<String, SomeFailure> result = foobar();
    result.ifSuccessOrElse(this::commit, this::rollback);
    final Result<Integer, SomeFailure> resultLength = result.mapSuccess(String::length);
    return resultLength.orElse(-1);
}

In the above example, we use only four lines of code to replace the ten that worked in the first example. But we can make it even shorter by chaining methods in typical functional programming style:

public int getFoobarLength() {
    return foobar().ifSuccessOrElse(this::commit, this::rollback).mapSuccess(String::length).orElse(-1);
}

In fact, since we are using -1 here just to signal that the underlying operation failed, we'd be better off returning a Result object upstream:

public Result<Integer, SomeFailure> getFoobarLength() {
    return foobar().ifSuccessOrElse(this::commit, this::rollback).mapSuccess(String::length);
}

This allows others to easily compose operations on top of ours, just like we did with foobar.

Getting Started

Please read the Quick Guide to know how to add this library to your build.

Releases

This library adheres to Pragmatic Versioning.

Artifacts are available in Maven Central.

Javadoc

Here you can find the full Javadoc documentation.

Benchmarks

You may want to visualize the latest benchmark report.

Looking for Support?

We'd love to help. Check out the support guidelines.

Contributions Welcome

If you'd like to contribute to this project, please start here.

Code of Conduct

This project is governed by the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.

Author

Copyright 2024 Guillermo Calvo.

License

This library is licensed under the Apache License, Version 2.0 (the "License"); you may not use it except in compliance with the License.

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and limitations under the License.

Permitted:

  • Commercial Use: You may use this library and derivatives for commercial purposes.
  • Modification: You may modify this library.
  • Distribution: You may distribute this library.
  • Patent Use: This license provides an express grant of patent rights from contributors.
  • Private Use: You may use and modify this library without distributing it.

Required:

  • License and Copyright Notice: If you distribute this library you must include a copy of the license and copyright notice.
  • State Changes: If you modify and distribute this library you must document changes made to this library.

Forbidden:

  • Trademark use: This license does not grant any trademark rights.
  • Liability: The library author cannot be held liable for damages.
  • Warranty: This library is provided without any warranty.