mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-10-13 08:15:38 +00:00
docs: update mute idiom
This commit is contained in:
1 parent
6cc4525bc1
commit
10cb8c0c09
3 files changed
+86
-58
No files matched your search
+82
-55
@@ -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
|
// ...
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
We then run our office's daily routine, which involves purchasing items
|
|
||||||
from the vending machine with the company card, using the mute pattern to ignore the exceptions that can't be thrown
|
|
||||||
```java
|
|
||||||
package com.iluwatar.mute;
|
|
||||||
|
|
||||||
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 useOfLoggedMute() {
|
||||||
|
Optional<Resource> resource = Optional.empty();
|
||||||
|
try {
|
||||||
|
resource = Optional.of(acquireResource());
|
||||||
|
utilizeResource(resource.get());
|
||||||
|
} finally {
|
||||||
|
resource.ifPresent(App::closeResource);
|
||||||
}
|
}
|
||||||
public void dailyRoutine() {
|
}
|
||||||
Mute.mute(() -> {
|
|
||||||
officeVendingMachine.purchaseItem(1,companyCard);
|
|
||||||
officeVendingMachine.purchaseItem(1,companyCard);
|
|
||||||
officeVendingMachine.purchaseItem(1,companyCard);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class App {
|
||||||
|
// ...
|
||||||
|
|
||||||
|
private static void closeResource(Resource resource) {
|
||||||
|
Mute.loggedMute(resource::close);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||

|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## 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");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user