docs: update mute idiom

This commit is contained in:
Ilkka Seppälä committed 2024-05-09 14:03:39 +03:00
1 parent 6cc4525bc1
commit 10cb8c0c09
3 files changed
+82 -54

No files matched your search

+78 -51
View File
@@ -1,95 +1,122 @@
--- ---
title: Mute Idiom title: Mute Idiom
category: Idiom category: Behavioral
language: en language: en
tag: tag:
- Decoupling - Context
- Decoupling
- Idiom
- Error handling
- Synchronization
- Thread management
--- ---
## Intent ## Intent
Provide a template to suppress any exceptions that either are declared but cannot occur or should only be logged;
while executing some business logic. The template removes the need to write repeated `try-catch` blocks.
The Mute Idiom is designed to simplify error handling by muting exceptions that are deemed non-critical or expected in specific contexts, especially within multithreaded or complex control flow environments.
## Explanation ## Explanation
Real World Example Real World Example
> The vending machine contained in your office displays a warning when making a transaction. The issue occurs when the > The vending machine contained in your office displays a warning when making a transaction. The issue occurs when the
> customer decides to pay with physical money that is not recognized by the system. However, you and everyone in the office
> only pays with the company credit card and will never encounter this issue.
In plain words In plain words
> The Mute Idiom design pattern is used to reduce the requirement of catching exceptions when they cannot be thrown or > The Mute Idiom design pattern is used to reduce the requirement of catching exceptions when they cannot be thrown or
> should be ignored when thrown. This applies in cases such as API functions, where the underlying code cannot be changed
> to include individual use cases.
Programmatic Example **Programmatic Example**
Converting the real-world example into a programmatic representation, we represent an API function as the Sure, here's a programmatic example of the Mute Idiom design pattern based on the code in the module:
office Vending machine
## Explanation
The Mute Idiom is a design pattern that is used to simplify error handling by muting exceptions that are deemed non-critical or expected in specific contexts. This pattern is particularly useful in multithreaded or complex control flow environments.
## Programmatic Example
We have a `Resource` interface that has a `close` method which throws an `IOException`.
```java ```java
public interface Resource extends AutoCloseable {
public class VendingMachine { @Override
public void purchaseItem(int itemID, PaymentMethod paymentMethod) throws Exception { void close() throws IOException;
if (paymentMethod == PaymentMethod.Cash) {
throw new Exception();
}
else {
System.out.println("Here is your item");
}
}
} }
``` ```
We also have an `App` class that uses this `Resource`. In the `App` class, we have a `useOfLoggedMute` method that demonstrates the use of the Mute Idiom. Here, we acquire a `Resource`, utilize it, and then attempt to close it. The closing of the resource is done in a `finally` block to ensure that it is executed regardless of whether an exception is thrown or not.
```java ```java
public enum PaymentMethod { public class App {
Card,Cash // ...
private static void useOfLoggedMute() {
Optional<Resource> resource = Optional.empty();
try {
resource = Optional.of(acquireResource());
utilizeResource(resource.get());
} finally {
resource.ifPresent(App::closeResource);
}
}
// ...
} }
``` ```
We then run our office's daily routine, which involves purchasing items The `closeResource` method is where the Mute Idiom is applied. We use the `Mute.loggedMute` method to suppress any `IOException` that might be thrown when closing the resource. This is done because the failure to close a resource is considered a non-critical issue that does not affect the overall logic or outcome of the program.
from the vending machine with the company card, using the mute pattern to ignore the exceptions that can't be thrown
```java ```java
package com.iluwatar.mute; public class App {
// ...
public class Office {
private PaymentMethod companyCard = PaymentMethod.Card;
private VendingMachine officeVendingMachine = new VendingMachine();
public static void main(String[] args) {
Office office = new Office();
office.dailyRoutine();
private static void closeResource(Resource resource) {
Mute.loggedMute(resource::close);
} }
public void dailyRoutine() {
Mute.mute(() -> { // ...
officeVendingMachine.purchaseItem(1,companyCard);
officeVendingMachine.purchaseItem(1,companyCard);
officeVendingMachine.purchaseItem(1,companyCard);
});
}
} }
``` ```
In this way, the Mute Idiom allows us to simplify error handling by reducing boilerplate code for expected exceptions, enhancing code readability and maintainability, and allowing uninterrupted execution for non-critical exceptions.
## Class diagram ## Class diagram
![alt text](./etc/mute-idiom.png "Mute Idiom")
![Mute Idiom](./etc/mute-idiom.png "Mute Idiom")
## Applicability ## Applicability
Use this idiom when
* an API declares some exception but can never throw that exception eg. ByteArrayOutputStream bulk write method.
* you need to suppress some exception just by logging it, such as closing a resource.
* Useful in scenarios where certain exceptions are predictable and do not affect the overall logic or outcome.
* Commonly used in logging, cleanup operations, or when working with APIs that signal non-critical issues via exceptions.
## Tutorials
## Credits
* [JOOQ: Mute Design Pattern](http://blog.jooq.org/2016/02/18/the-mute-design-pattern/) * [JOOQ: Mute Design Pattern](http://blog.jooq.org/2016/02/18/the-mute-design-pattern/)
## Known Uses
* Muting exceptions in background tasks or threads where interruption is expected.
* Handling known issues in third-party libraries where exceptions can be safely ignored.
## Consequences
Benefits:
* Simplifies error handling by reducing boilerplate code for expected exceptions.
* Enhances code readability and maintainability.
* Allows uninterrupted execution for non-critical exceptions.
Trade-offs:
* Can lead to missed critical issues if overused or misapplied.
* Makes debugging harder if exceptions are muted indiscriminately.
## Related Patterns
* [Null Object](https://java-design-patterns.com/patterns/null-object/): Both aim to simplify error handling; Null Object avoids null checks while Mute Idiom avoids exception handling complexities.
* [Decorator](https://java-design-patterns.com/patterns/decorator/): Can be used to wrap functionality with additional error handling or muting behaviors.
## Credits
* [Effective Java](https://amzn.to/4cGk2Jz)
* [Java Concurrency in Practice](https://amzn.to/4aRMruW)
@@ -26,10 +26,12 @@ package com.iluwatar.mute;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
/** /**
* A utility class that allows you to utilize mute idiom. * A utility class that allows you to utilize mute idiom.
*/ */
@Slf4j
public final class Mute { public final class Mute {
// The constructor is never meant to be called. // The constructor is never meant to be called.
@@ -40,7 +42,7 @@ public final class Mute {
* Executes the <code>runnable</code> and throws the exception occurred within a {@link * Executes the <code>runnable</code> and throws the exception occurred within a {@link
* AssertionError}. This method should be utilized to mute the operations that are guaranteed not * AssertionError}. This method should be utilized to mute the operations that are guaranteed not
* to throw an exception. For instance {@link ByteArrayOutputStream#write(byte[])} declares in * to throw an exception. For instance {@link ByteArrayOutputStream#write(byte[])} declares in
* it's signature that it can throw an {@link IOException}, but in reality it cannot. This is * its signature that it can throw an {@link IOException}, but in reality it cannot. This is
* because the bulk write method is not overridden in {@link ByteArrayOutputStream}. * because the bulk write method is not overridden in {@link ByteArrayOutputStream}.
* *
* @param runnable a runnable that should never throw an exception on execution. * @param runnable a runnable that should never throw an exception on execution.
@@ -63,10 +63,9 @@ class MuteTest {
Mute.loggedMute(this::methodThrowingException); Mute.loggedMute(this::methodThrowingException);
assertTrue(new String(stream.toByteArray()).contains(MESSAGE)); assertTrue(stream.toString().contains(MESSAGE));
} }
private void methodNotThrowingAnyException() { private void methodNotThrowingAnyException() {
LOGGER.info("Executed successfully"); LOGGER.info("Executed successfully");
} }