Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
cbrt-x committed Apr 23, 2022
0 parents commit a31f764
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
.idea/
54 changes: 54 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.github.jadefalke</groupId>
<artifactId>Try-Catch</artifactId>
<version>0.0.1-alpha</version>
<packaging>jar</packaging>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/libs
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
149 changes: 149 additions & 0 deletions src/main/java/io/github/jadefalke2/Try.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package io.github.jadefalke2;

import io.github.jadefalke2.exceptions.CatchBlockAlreadyExistsException;
import io.github.jadefalke2.interfaces.UnsafeRunnable;
import io.github.jadefalke2.interfaces.UnsafeSupplier;
import lombok.NonNull;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

/**
* This class describes a wrapper around a try-catch-finally block.
* @param <T> the return type of this try-catch-finally block
*/
public class Try <T> {

private final UnsafeSupplier<T> attempt;
private final Map<Class<? extends Exception>, Consumer<? super Exception>> catchClauses;
private Runnable onFinally;

/**
* Constructs a new Try-catch-builder with the given Exception-throwing supplier as the code to execute
* @param attempt the code to run inside the try-block
*/
private Try (UnsafeSupplier<T> attempt) {
this.attempt = attempt;
catchClauses = new HashMap<>();
}

/**
* Factory method for a try without a return type
* @param runnable the code to be executed
* @return the newly constructed try
*/
public static Try<Void> attempt (@NonNull UnsafeRunnable runnable) {
return attempt(() -> {
runnable.run();
return null;
});
}

/**
* Factory method for a try
* @param supplier the code to run and return a value inside the try
* @param <T> the type to be returned
* @return the newly constructed try
*/
public static <T> Try<T> attempt (@NonNull UnsafeSupplier<T> supplier) {
return new Try<>(supplier);
}

/**
* Appends a catch-block with the given type
* @param exceptionType the type of exception
* @param onCatch the code to run when this catch block is executed
* @return the try instance
*/
@SuppressWarnings("unchecked")
public <E extends Exception> Try<T> onCatch (@NonNull Class<E> exceptionType, @NonNull Consumer<? super E> onCatch) {
if (catchClauses.containsKey(exceptionType))
throw new CatchBlockAlreadyExistsException();

catchClauses.put(exceptionType, (Consumer<? super Exception>) onCatch);
return this;
}

/**
* Appends a catch-block with the Exception type
* @param onCatch the code to run when this catch block is executed
* @return the try instance
*/
public Try<T> onCatch (@NonNull Consumer<? super Exception> onCatch) {
return onCatch(Exception.class, onCatch);
}

/**
* Appends a finally-block
* @param onFinally the code run to run in the finally-block
* @return the try instance
*/
public Try<T> onFinally (@NonNull Runnable onFinally) {
this.onFinally = onFinally;
return this;
}

/**
* Executes the code in the try-block, catching with the respective catch-block in case an Exception.
* Finally, whatever branch is executed prior the finally-block will be executed.
*/
public void run () {
get();
}

/**
* Executes the code in the try-block, catching with the respective catch-block in case an Exception.
* Finally, whatever branch is executed prior the finally-block will be executed.
* @return the Optional describing the value obtained within the try-catch block
*/
public Optional<T> get () {
Optional<T> val = Optional.empty();
try {
val = Optional.ofNullable(attempt.supply());
} catch (Exception e) {
getCatchClause(e.getClass())
.ifPresent(exConsumer -> exConsumer.accept(e));
} finally {
if (onFinally != null)
onFinally.run();
}
return val;
}

/**
* Executes the code in the try-block, catching with the respective catch-block in case an Exception.
* Finally, whatever branch is executed prior the finally-block will be executed.
* @return the value obtained by the computation
*/
public T getOrThrow () {
return get().orElseThrow();
}

/**
* Executes the code in the try-block, catching with the respective catch-block in case an Exception.
* Finally, whatever branch is executed prior the finally-block will be executed.
* @param val the value to be returned if the value obtained in the try catch block is null
* @return the value obtained
*/
public T getOrElse (T val) {
return get().orElse(val);
}

/**
* Gets the correct catch clause for the given class
* @param c the Exception class
* @return the optional Exception from the map
*/
private Optional<Consumer<? super Exception>> getCatchClause (Class<?> c) {
if (catchClauses.containsKey(c)) {
return Optional.of(catchClauses.get(c));
} else {
if (c.getSuperclass().equals(Exception.class) || catchClauses.isEmpty()) {
return Optional.empty();
}
return getCatchClause(c.getSuperclass());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.jadefalke2.exceptions;

public class CatchBlockAlreadyExistsException extends RuntimeException {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.jadefalke2.interfaces;

public interface UnsafeRunnable {
void run () throws Exception;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.jadefalke2.interfaces;

public interface UnsafeSupplier<T> {
T supply() throws Exception;
}
65 changes: 65 additions & 0 deletions src/test/java/APITest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import io.github.jadefalke2.Try;
import io.github.jadefalke2.exceptions.CatchBlockAlreadyExistsException;
import io.github.jadefalke2.interfaces.UnsafeSupplier;
import org.junit.Test;

import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.junit.Assert.*;

public class APITest {

@Test
public void testMultipleCatchBlocks () {
assertThrows(CatchBlockAlreadyExistsException.class,
() -> Try.attempt(() -> System.out.println("Test"))
.onCatch(RuntimeException.class, Throwable::printStackTrace)
.onCatch(RuntimeException.class, e -> System.out.println(e.getMessage()))
);
}

@Test
public void testCorrectCatchClause () {
Try.attempt(() -> {throw new IOException();})
.onCatch(IOException.class, e -> {})
.onCatch(Exception.class, e -> fail())
.run();

Try.attempt(() -> {throw new Exception();})
.onCatch(Exception.class, e -> {})
.onCatch(IOException.class, e -> fail());

AtomicBoolean done = new AtomicBoolean(false);
Try.attempt(() -> {throw new Exception();})
.onCatch(e -> done.set(true))
.run();
assertTrue(done.get());
}

@Test
public void testSuccessfulRun () {
AtomicBoolean done = new AtomicBoolean(false);
Try.attempt(() -> done.set(true))
.onCatch(e -> fail())
.run();
assertTrue(done.get());
}

@Test
public void testReturnValue () {
assertEquals(Integer.valueOf(5),
Try.attempt(() -> 5).getOrThrow());

assertEquals(10, Try.attempt(() -> {throw new IOException();})
.getOrElse(10));

assertThrows(NoSuchElementException.class, () ->
Try.attempt(() -> null).getOrThrow());

assertThrows(NoSuchElementException.class, () ->
Try.attempt((UnsafeSupplier<?>) () -> {throw new Exception();}).getOrThrow());
}

}

0 comments on commit a31f764

Please sign in to comment.