0
# Resource Management
1
2
Utilities for automatic resource management using the `Using` API, enabling safe handling of resources that need to be closed after use.
3
4
## Core Imports
5
6
```scala
7
import scala.util.Using
8
```
9
10
## Using Object
11
12
```scala { .api }
13
object Using {
14
def apply[R: Releasable, A](resource: => R)(f: R => A): Try[A]
15
16
object Manager {
17
def apply[A](f: Manager => A): Try[A]
18
}
19
}
20
21
trait Releasable[-R] {
22
def release(resource: R): Unit
23
}
24
```
25
26
## Basic Resource Management
27
28
### Single Resource Management
29
30
Automatically manages a single resource using `Using.apply`.
31
32
```scala { .api }
33
def apply[R: Releasable, A](resource: => R)(f: R => A): Try[A]
34
```
35
36
**Usage Example:**
37
```scala
38
import java.io.{BufferedReader, FileReader}
39
import scala.util.{Try, Using}
40
41
val lines: Try[Seq[String]] =
42
Using(new BufferedReader(new FileReader("file.txt"))) { reader =>
43
Iterator.continually(reader.readLine()).takeWhile(_ != null).toSeq
44
}
45
```
46
47
### Multiple Resource Management
48
49
For managing multiple resources simultaneously, use `Using.Manager`.
50
51
```scala { .api }
52
object Manager {
53
def apply[A](f: Manager => A): Try[A]
54
55
trait Manager {
56
def apply[R: Releasable](resource: R): R
57
}
58
}
59
```
60
61
**Usage Example:**
62
```scala
63
import java.io.{BufferedReader, FileReader}
64
import scala.util.{Try, Using}
65
66
val lines: Try[Seq[String]] = Using.Manager { use =>
67
val r1 = use(new BufferedReader(new FileReader("file1.txt")))
68
val r2 = use(new BufferedReader(new FileReader("file2.txt")))
69
val lines1 = Iterator.continually(r1.readLine()).takeWhile(_ != null).toSeq
70
val lines2 = Iterator.continually(r2.readLine()).takeWhile(_ != null).toSeq
71
lines1 ++ lines2
72
}
73
```
74
75
## Releasable Trait
76
77
The `Releasable` type class defines how resources should be released.
78
79
```scala { .api }
80
trait Releasable[-R] {
81
def release(resource: R): Unit
82
}
83
```
84
85
**Built-in Instances:**
86
- `AutoCloseable` (Java resources like streams, readers, writers)
87
- Custom releasable instances can be defined implicitly
88
89
**Custom Releasable Example:**
90
```scala
91
case class DatabaseConnection(url: String) {
92
def close(): Unit = println(s"Closing connection to $url")
93
}
94
95
implicit val dbReleasable: Releasable[DatabaseConnection] =
96
(resource: DatabaseConnection) => resource.close()
97
98
val result: Try[String] = Using(DatabaseConnection("jdbc:...")) { conn =>
99
"Query result"
100
}
101
```
102
103
## Error Handling
104
105
The `Using` utilities wrap all operations in `Try`, providing safe error handling:
106
107
- **Success**: Resource is used and properly released
108
- **Failure**: Captures both operation failures and resource release failures
109
- **Exception Handling**: Ensures resources are released even if exceptions occur
110
111
```scala
112
import java.io.FileInputStream
113
import scala.util.{Try, Success, Failure}
114
115
val result: Try[Int] = Using(new FileInputStream("data.txt")) { stream =>
116
stream.available()
117
}
118
119
result match {
120
case Success(size) => println(s"File size: $size bytes")
121
case Failure(exception) => println(s"Error: ${exception.getMessage}")
122
}
123
```
124
125
## Resource Release Order
126
127
When using `Using.Manager`, resources are released in reverse order of acquisition:
128
129
```scala
130
Using.Manager { use =>
131
val resource1 = use(openResource1()) // Released last
132
val resource2 = use(openResource2()) // Released second
133
val resource3 = use(openResource3()) // Released first
134
// ... use resources
135
}
136
```
137
138
## Availability
139
140
**Note**: The `Using` utility is only available in the Scala 2.11 compatibility version. In Scala 2.12+ and 2.13+, it's part of the standard library.
141
142
## Complete Example
143
144
```scala
145
import java.io.{FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream}
146
import scala.util.{Try, Using}
147
148
def copyFile(source: String, dest: String): Try[Unit] = Using.Manager { use =>
149
val input = use(new BufferedInputStream(new FileInputStream(source)))
150
val output = use(new BufferedOutputStream(new FileOutputStream(dest)))
151
152
val buffer = new Array[Byte](8192)
153
var bytesRead = 0
154
155
while ({
156
bytesRead = input.read(buffer)
157
bytesRead != -1
158
}) {
159
output.write(buffer, 0, bytesRead)
160
}
161
162
output.flush()
163
}
164
```