Skip to content

Commit 661a278

Browse files
author
Abhishek Prasad Gupta
committed
add try util
1 parent d6bdd8e commit 661a278

9 files changed

Lines changed: 572 additions & 73 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
.vscode
22

3-
target
3+
target

README.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Try Utility Library (io.github.abhipdgupta.tryutil)
2+
3+
The Try utility is a functional-style container designed to manage and compose operations that may result in exceptions (Throwable). It promotes declarative, type-safe error handling by eliminating verbose try-catch blocks.
4+
5+
Inspired by Vavr, a Try is either a **Success** (containing a result value of type T) or a **Failure** (containing a Throwable cause).
6+
7+
---
8+
9+
## 1. Core Classes and State
10+
11+
| Class | Description |
12+
|---------------|-------------------------------------------------------------------|
13+
| `Try<T>` | The abstract base container (Success or Failure). |
14+
| `Success<T>` | Holds the result value. |
15+
| `Failure<T>` | Holds the Throwable cause. |
16+
| `TryException`| A RuntimeException thrown by `get()` to wrap the underlying cause. |
17+
18+
---
19+
20+
## 2. Creation
21+
22+
The primary entry point is wrapping a Supplier that might throw an exception.
23+
24+
### of (Supplier)
25+
26+
Wraps a computation, yielding a Success on normal completion or a Failure if any Throwable is caught.
27+
28+
```java
29+
// Creates Success("10")
30+
Try<String> success = Try.of(() -> String.valueOf(10));
31+
32+
// Creates Failure(ArithmeticException)
33+
Try<Integer> failure = Try.of(() -> 10 / 0);
34+
```
35+
36+
---
37+
38+
## 3. Transformations and Composition
39+
40+
These methods enable safe chaining. They only execute on Success; if a Failure is encountered, the chain skips the transformation methods and preserves the Failure. Any exception thrown inside map or flatMap results in a new Failure.
41+
42+
### map (Function)
43+
44+
Transforms the successful value T into a new value U.
45+
46+
### flatMap (Function)
47+
48+
Transforms the successful value T into a new Try\<U\>, used for sequencing Try-returning operations (monadic bind).
49+
50+
```java
51+
Try<Integer> result = Try.of(() -> "100")
52+
.map(Integer::parseInt)
53+
.flatMap(i -> Try.of(() -> String.format("%d squared is %d", i, i * i)));
54+
```
55+
56+
57+
## 4. Error Handling and Recovery
58+
59+
### getOrElse (T other)
60+
61+
Returns the value if Success, otherwise returns a default value.
62+
63+
### recover (Function<Throwable, T>)
64+
65+
Recovers from **any** Failure by applying the function to the Throwable, yielding a new Success with the recovery value.
66+
67+
### recover (Class<E>, Function<E, T>)
68+
69+
Recovers selectively from a **specific Exception type**. Non-matching Failures are passed through.
70+
71+
```java
72+
// 1. Fallback value
73+
int value = Try.of(() -> 1 / 0).getOrElse(-1); // -1
74+
75+
// 2. General recovery
76+
Try<String> recovered = Try.of(() -> apiCall())
77+
.recover(t -> "Fallback Data"); // Success("Fallback Data")
78+
79+
// 3. Selective recovery
80+
Try<String> result = Try.of(() -> { throw new TimeoutException(); })
81+
.recover(IOException.class, e -> "IO Error Fallback") // Skipped
82+
.recover(TimeoutException.class, e -> "Timeout Fallback"); // Success("Timeout Fallback")
83+
```
84+
85+
---
86+
87+
## 5. Side Effects and Unwrapping
88+
89+
### onSuccess (Consumer<T>)
90+
91+
Performs a side-effect action on the value if Success. Returns this.
92+
93+
### onFailure (Consumer<Throwable>)
94+
95+
Performs a side-effect action on the Throwable if Failure. Returns this.
96+
97+
### getOrElseThrow ()
98+
99+
Returns the value if Success, otherwise throws the **original Throwable**.
100+
101+
### getOrElseThrow (Function<Throwable, X>)
102+
103+
Returns the value if Success, otherwise throws a custom Exception (X) mapped from the original Throwable.
104+
105+
```java
106+
// Log and then throw if failed
107+
String data = Try.of(() -> executeTask())
108+
.onFailure(t -> System.err.println("Task failed: " + t.getMessage()))
109+
.getOrElseThrow(cause -> new TaskException("Critical failure", cause));
110+
111+
// Simple unwrap (must handle the checked exception)
112+
String content = Try.of(() -> readFile()).getOrElseThrow();
113+
```

pom.xml

Lines changed: 90 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,91 @@
1-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3-
<modelVersion>4.0.0</modelVersion>
4-
<groupId>io.github.abhipdgupta</groupId>
5-
<artifactId>try-util</artifactId>
6-
<packaging>jar</packaging>
7-
<version>1.0-SNAPSHOT</version>
8-
<name>try-util</name>
9-
<url>http://maven.apache.org</url>
10-
<properties>
11-
<spotless.version>3.1.0</spotless.version>
12-
</properties>
13-
<dependencies>
14-
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
15-
<dependency>
16-
<groupId>org.junit.jupiter</groupId>
17-
<artifactId>junit-jupiter-api</artifactId>
18-
<version>6.0.1</version>
19-
<scope>test</scope>
20-
</dependency>
21-
</dependencies>
22-
<build>
23-
<plugins>
24-
<plugin>
25-
<groupId>com.diffplug.spotless</groupId>
26-
<artifactId>spotless-maven-plugin</artifactId>
27-
<version>${spotless.version}</version>
28-
<configuration>
29-
<ratchetFrom>origin/main</ratchetFrom>
30-
<formats>
31-
<format>
32-
<includes>
33-
<include>.gitattributes</include>
34-
<include>.gitignore</include>
35-
</includes>
36-
<trimTrailingWhitespace/>
37-
<endWithNewline/>
38-
<indent>
39-
<tabs>true</tabs>
40-
<spacesPerTab>4</spacesPerTab>
41-
</indent>
42-
</format>
43-
</formats>
44-
<java>
45-
<googleJavaFormat>
46-
<version>1.8</version>
47-
<style>AOSP</style>
48-
<reflowLongStrings>true</reflowLongStrings>
49-
<formatJavadoc>false</formatJavadoc>
50-
</googleJavaFormat>
51-
52-
<licenseHeader>
53-
<content>/* (C)$YEAR */</content>
54-
</licenseHeader>
55-
</java>
56-
</configuration>
57-
</plugin>
58-
</plugins>
59-
</build>
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>io.github.abhipdgupta</groupId>
5+
<artifactId>try-util</artifactId>
6+
<version>1.0.0</version>
7+
<packaging>jar</packaging>
8+
<name>try-util</name>
9+
<url>http://maven.apache.org</url>
10+
<distributionManagement>
11+
<repository>
12+
<id>github</id>
13+
<name>GitHub Packages</name>
14+
<url>https://maven.pkg.github.com/abhipdgupta/try-util-java</url>
15+
</repository>
16+
</distributionManagement>
17+
<properties>
18+
<maven.compiler.release>21</maven.compiler.release>
19+
<spotless.version>3.1.0</spotless.version>
20+
</properties>
21+
<dependencies>
22+
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
23+
<dependency>
24+
<groupId>org.junit.jupiter</groupId>
25+
<artifactId>junit-jupiter-api</artifactId>
26+
<version>6.0.1</version>
27+
<scope>test</scope>
28+
</dependency>
29+
</dependencies>
30+
<build>
31+
<plugins>
32+
<plugin>
33+
<groupId>com.diffplug.spotless</groupId>
34+
<artifactId>spotless-maven-plugin</artifactId>
35+
<version>${spotless.version}</version>
36+
<configuration>
37+
<formats>
38+
<format>
39+
<includes>
40+
<include>.gitattributes</include>
41+
<include>.gitignore</include>
42+
</includes>
43+
<trimTrailingWhitespace />
44+
<endWithNewline />
45+
<indent>
46+
<tabs>true</tabs>
47+
<spacesPerTab>4</spacesPerTab>
48+
</indent>
49+
</format>
50+
</formats>
51+
<java>
52+
<googleJavaFormat>
53+
<version>1.33.0</version>
54+
<style>AOSP</style>
55+
<reflowLongStrings>true</reflowLongStrings>
56+
<formatJavadoc>false</formatJavadoc>
57+
</googleJavaFormat>
58+
<licenseHeader>
59+
<content>/* (C)$YEAR */</content>
60+
</licenseHeader>
61+
</java>
62+
<pom>
63+
<includes>
64+
<include>pom.xml</include>
65+
</includes>
66+
<sortPom>
67+
<encoding>UTF-8</encoding>
68+
<lineSeparator>\n</lineSeparator>
69+
<expandEmptyElements>false</expandEmptyElements>
70+
<spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement>
71+
<keepBlankLines>true</keepBlankLines>
72+
<nrOfIndentSpace>4</nrOfIndentSpace>
73+
<indentBlankLines>false</indentBlankLines>
74+
<sortDependencies>scope,groupId,artifactId</sortDependencies>
75+
<sortPlugins>groupId,artifactId</sortPlugins>
76+
<sortProperties>true</sortProperties>
77+
</sortPom>
78+
</pom>
79+
</configuration>
80+
<executions>
81+
<execution>
82+
<goals>
83+
<goal>apply</goal>
84+
</goals>
85+
<phase>compile</phase>
86+
</execution>
87+
</executions>
88+
</plugin>
89+
</plugins>
90+
</build>
6091
</project>

src/main/java/io/github/abhipdgupta/App.java

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* (C)2025 */
2+
package io.github.abhipdgupta.tryutil;
3+
4+
import java.util.function.Consumer;
5+
import java.util.function.Function;
6+
7+
final class Failure<T> extends Try<T> {
8+
private final Throwable cause;
9+
10+
Failure(Throwable cause) {
11+
this.cause = cause;
12+
}
13+
14+
@Override
15+
public boolean isSuccess() {
16+
return false;
17+
}
18+
19+
@Override
20+
public boolean isFailure() {
21+
return true;
22+
}
23+
24+
@Override
25+
public T get() throws TryException {
26+
throw new TryException(cause);
27+
}
28+
29+
@Override
30+
public Throwable getCause() {
31+
return cause;
32+
}
33+
34+
@Override
35+
public <U> Try<U> map(Function<? super T, ? extends U> mapper) {
36+
return new Failure<>(cause);
37+
}
38+
39+
@Override
40+
public <U> Try<U> flatMap(Function<? super T, Try<U>> mapper) {
41+
return new Failure<>(cause);
42+
}
43+
44+
@Override
45+
public T getOrElse(T other) {
46+
return other;
47+
}
48+
49+
@Override
50+
public Try<T> recover(Function<Throwable, ? extends T> recoverFunc) {
51+
try {
52+
return new Success<>(recoverFunc.apply(cause));
53+
} catch (Throwable t) {
54+
return new Failure<>(t);
55+
}
56+
}
57+
58+
@Override
59+
public <E extends Throwable> Try<T> recover(
60+
Class<E> exClass, Function<? super E, ? extends T> recoverFunc) {
61+
if (exClass.isInstance(cause)) {
62+
try {
63+
return new Success<>(recoverFunc.apply(exClass.cast(cause)));
64+
} catch (Throwable t) {
65+
return new Failure<>(t);
66+
}
67+
}
68+
return this;
69+
}
70+
71+
@Override
72+
public Try<T> onSuccess(Consumer<? super T> action) {
73+
return this;
74+
}
75+
76+
@Override
77+
public Try<T> onFailure(Consumer<? super Throwable> action) {
78+
action.accept(cause);
79+
return this;
80+
}
81+
82+
@Override
83+
public String toString() {
84+
return "Failure(" + cause + ")";
85+
}
86+
}

0 commit comments

Comments
 (0)