Transforming Results

How to transform values wrapped inside Results

Transforming result objects is a key feature that enables you to compose complex operations in a clean and functional style. There are two primary techniques used for these transformations.

Mapping Results

Mapping involves applying a function to the value inside a result to produce a new result object.

Mapping Success Values

We can use Result::mapSuccess to apply a function to the success value of a result, transforming it into a new success value. If the result is a failure, it remains unchanged.

@Test
void testMapSuccess() {
  // Given
  Result<String, ?> result = success("HELLO");
  // When
  Result<Integer, ?> mapped = result.mapSuccess(String::length);
  // Then
  assertEquals(5, mapped.orElse(null));
}

In this example, we wrap a String inside a Result object and invoke mapSuccess to calculate its length and wrap it inside a new Result object.

Mapping Failure Values

Next up, we can use Result::mapFailure to apply a function to the failure value, transforming it into a new one. If the result is a success, it remains unchanged.

Here, we invoke mapFailure to transform the failure type of the result from String to Boolean for demonstration purposes.

Mapping Both Success and Failure

The Result::map method simultaneously handles both success and failure cases by applying two separate functions: one for transforming the success value and one for transforming the failure value.

Flat-Mapping Results

Flat-mapping is used to chain operations that return results themselves, flattening the nested structures into a single result object. This allows you to transform a success into a failure, or a failure into a success.

To illustrate flat-mapping concepts, the next examples will follow a familiar "pet store" theme. This involves three Java types: Pet, PetError, and PetStore. These types will help us demonstrate the effective use of flat-mapping methods.

With these types defined, we'll explore how to use various flat-mapping methods to transform result objects and manage pet-related operations in our imaginary pet store.

Flat-Mapping Successful Results

Use Result::flatMapSuccess to chain an operation that returns a result object. This method applies a mapping function to the success value, replacing the original result with the new one returned by the function. If the result is a failure, it remains unchanged.

This example starts with a successful result containing a wrong pet ID (not found in the pet store). When we flat-map it with the store's find method reference, the final result contains a pet error.

Flat-Mapping Failed Results

Use Result::flatMapFailure to chain a result-bearing operation. This method also replaces the original result with the new one returned by the mapping function. If the result is a success, it remains unchanged.

Here we start with a failed result containing a pet error. When we flat-map it with the store's getDefaultPetId method reference, the final result contains the ID of the default pet in the store.

Flat-Mapping Both Success and Failure

The Result::flatMap method handles both success and failure cases by applying the appropriate function based on the status of the original result.

This example starts with a successful result containing a wrong pet ID (not found in the pet store). When we flat-map it with the store's find method reference, the final result contains a pet error.

Here we start with a failed result containing a pet error. When we flat-map it with the store's getDefaultPetId method reference, the final result contains the ID of the default pet in the store.

Conclusion

We demonstrated how to transform results in a concise and functional manner, enhancing the clarity and flexibility of your error-handling and data-processing logic.

Last updated

Was this helpful?