or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotation-backports.mdbackported-collections.mdcollection-extensions.mdcollection-factories.mdindex.mditerator-size-ops.mdjava-interop.mdmap-extensions.mdmethod-chaining.mdoption-converters.mdresource-management.mdstring-parsing.md

java-interop.mddocs/

0

# Java Collection Interoperability

1

2

Seamless bidirectional conversion between Scala and Java collections, enabling smooth interoperation with Java libraries and frameworks.

3

4

## CollectionConverters Object

5

6

```scala { .api }

7

object CollectionConverters extends DecorateAsJava with DecorateAsScala

8

```

9

10

The main entry point for collection conversions, combining Java-to-Scala and Scala-to-Java conversion capabilities.

11

12

## Core Import

13

14

```scala

15

import scala.jdk.CollectionConverters._

16

```

17

18

This import provides implicit extension methods for converting between Scala and Java collection types.

19

20

## Scala to Java Conversions

21

22

### DecorateAsJava Conversions

23

24

The following extension methods are available on Scala collections:

25

26

#### Iterable Conversions

27

28

```scala { .api }

29

// Extension methods added by DecorateAsJava

30

implicit class IterableHasAsJava[A](it: Iterable[A]) {

31

def asJava: java.lang.Iterable[A]

32

}

33

34

implicit class BufferHasAsJava[A](b: mutable.Buffer[A]) {

35

def asJava: java.util.List[A]

36

}

37

38

implicit class MutableSeqHasAsJava[A](seq: mutable.Seq[A]) {

39

def asJava: java.util.List[A]

40

}

41

42

implicit class SeqHasAsJava[A](seq: Seq[A]) {

43

def asJava: java.util.List[A]

44

}

45

46

implicit class MutableSetHasAsJava[A](s: mutable.Set[A]) {

47

def asJava: java.util.Set[A]

48

}

49

50

implicit class SetHasAsJava[A](s: Set[A]) {

51

def asJava: java.util.Set[A]

52

}

53

```

54

55

#### Map Conversions

56

57

```scala { .api }

58

implicit class MutableMapHasAsJava[K, V](m: mutable.Map[K, V]) {

59

def asJava: java.util.Map[K, V]

60

}

61

62

implicit class MapHasAsJava[K, V](m: Map[K, V]) {

63

def asJava: java.util.Map[K, V]

64

}

65

66

implicit class ConcurrentMapHasAsJava[K, V](m: concurrent.Map[K, V]) {

67

def asJava: java.util.concurrent.ConcurrentMap[K, V]

68

}

69

```

70

71

#### Dictionary Conversions

72

73

```scala { .api }

74

implicit class DictionaryHasAsJava[K, V](d: mutable.Map[K, V]) {

75

def asJavaDictionary: java.util.Dictionary[K, V]

76

}

77

78

implicit class PropertiesHasAsScala(p: java.util.Properties) {

79

def asScala: mutable.Map[String, String]

80

}

81

```

82

83

## Java to Scala Conversions

84

85

### DecorateAsScala Conversions

86

87

The following extension methods are available on Java collections:

88

89

#### Iterable Conversions

90

91

```scala { .api }

92

// Extension methods added by DecorateAsScala

93

implicit class IteratorHasAsScala[A](it: java.util.Iterator[A]) {

94

def asScala: Iterator[A]

95

}

96

97

implicit class EnumerationHasAsScala[A](e: java.util.Enumeration[A]) {

98

def asScala: Iterator[A]

99

}

100

101

implicit class IterableHasAsScala[A](it: java.lang.Iterable[A]) {

102

def asScala: Iterable[A]

103

}

104

105

implicit class CollectionHasAsScala[A](c: java.util.Collection[A]) {

106

def asScala: Iterable[A]

107

}

108

109

implicit class ListHasAsScala[A](l: java.util.List[A]) {

110

def asScala: mutable.Buffer[A]

111

}

112

113

implicit class SetHasAsScala[A](s: java.util.Set[A]) {

114

def asScala: mutable.Set[A]

115

}

116

```

117

118

#### Map Conversions

119

120

```scala { .api }

121

implicit class MapHasAsScala[K, V](m: java.util.Map[K, V]) {

122

def asScala: mutable.Map[K, V]

123

}

124

125

implicit class ConcurrentMapHasAsScala[K, V](m: java.util.concurrent.ConcurrentMap[K, V]) {

126

def asScala: concurrent.Map[K, V]

127

}

128

129

implicit class DictionaryHasAsScala[K, V](d: java.util.Dictionary[K, V]) {

130

def asScala: mutable.Map[K, V]

131

}

132

```

133

134

## Usage Examples

135

136

### Basic Conversions

137

138

```scala

139

import scala.jdk.CollectionConverters._

140

import java.util.{ArrayList, HashMap}

141

142

// Scala to Java

143

val scalaList = List(1, 2, 3, 4, 5)

144

val javaList: java.util.List[Int] = scalaList.asJava

145

146

val scalaMap = Map("a" -> 1, "b" -> 2)

147

val javaMap: java.util.Map[String, Int] = scalaMap.asJava

148

149

val scalaSet = Set("x", "y", "z")

150

val javaSet: java.util.Set[String] = scalaSet.asJava

151

152

// Java to Scala

153

val javaArrayList = new ArrayList[String]()

154

javaArrayList.add("hello")

155

javaArrayList.add("world")

156

val scalaBuffer = javaArrayList.asScala

157

158

val javaHashMap = new HashMap[String, Int]()

159

javaHashMap.put("one", 1)

160

javaHashMap.put("two", 2)

161

val scalaMutableMap = javaHashMap.asScala

162

```

163

164

### Working with Java Libraries

165

166

```scala

167

import scala.jdk.CollectionConverters._

168

import java.util.stream.Collectors

169

170

// Processing with Java Streams

171

def processWithJavaStreams(data: List[String]): List[String] = {

172

data.asJava

173

.stream()

174

.filter(_.startsWith("A"))

175

.map(_.toUpperCase)

176

.collect(Collectors.toList())

177

.asScala

178

.toList

179

}

180

181

// Using Java concurrent collections

182

import java.util.concurrent.ConcurrentHashMap

183

184

val concurrentMap = new ConcurrentHashMap[String, Int]()

185

concurrentMap.put("count", 0)

186

187

val scalaView = concurrentMap.asScala

188

scalaView.update("count", scalaView("count") + 1)

189

```

190

191

### Interop with Java Frameworks

192

193

```scala

194

import scala.jdk.CollectionConverters._

195

196

// Example: Working with Spring Framework collections

197

class SpringService {

198

import org.springframework.util.MultiValueMap

199

200

def processMultiValueMap(javaMap: MultiValueMap[String, String]): Map[String, List[String]] = {

201

javaMap.asScala.view.mapValues(_.asScala.toList).toMap

202

}

203

}

204

205

// Example: Working with Jackson JSON processing

206

import com.fasterxml.jackson.databind.ObjectMapper

207

208

def parseJsonToScala(json: String): Map[String, Any] = {

209

val mapper = new ObjectMapper()

210

val javaMap = mapper.readValue(json, classOf[java.util.Map[String, Any]])

211

javaMap.asScala.toMap

212

}

213

```

214

215

### Bidirectional Data Flow

216

217

```scala

218

import scala.jdk.CollectionConverters._

219

220

class DataProcessor {

221

// Accept Java collections, process in Scala, return Java collections

222

def processData(javaInput: java.util.List[String]): java.util.Map[String, java.util.List[String]] = {

223

javaInput.asScala

224

.groupBy(_.charAt(0).toString)

225

.view.mapValues(_.asJava)

226

.toMap

227

.asJava

228

}

229

230

// Accept Scala collections, use Java processing, return Scala collections

231

def processWithJavaTools(scalaInput: List[Int]): List[Int] = {

232

import java.util.Collections

233

234

val javaList = scalaInput.asJava

235

Collections.sort(javaList)

236

Collections.reverse(javaList)

237

javaList.asScala.toList

238

}

239

}

240

```

241

242

### Working with Properties

243

244

```scala

245

import scala.jdk.CollectionConverters._

246

import java.util.Properties

247

248

// Load system properties as Scala map

249

val systemProps: mutable.Map[String, String] = System.getProperties.asScala

250

251

// Create Properties from Scala map

252

val config = Map(

253

"server.port" -> "8080",

254

"database.url" -> "jdbc:h2:mem:test"

255

)

256

257

val properties = new Properties()

258

config.foreach { case (k, v) => properties.setProperty(k, v) }

259

260

// Or using asJavaDictionary

261

val scalaMap = mutable.Map("key1" -> "value1", "key2" -> "value2")

262

val dictionary = scalaMap.asJavaDictionary

263

```

264

265

### Iterator and Enumeration Conversions

266

267

```scala

268

import scala.jdk.CollectionConverters._

269

import java.util.{Vector, StringTokenizer}

270

271

// Java Iterator to Scala Iterator

272

val javaVector = new Vector[String]()

273

javaVector.add("a")

274

javaVector.add("b")

275

javaVector.add("c")

276

277

val scalaIterator = javaVector.iterator().asScala

278

scalaIterator.foreach(println)

279

280

// Java Enumeration to Scala Iterator

281

val tokenizer = new StringTokenizer("hello,world,scala", ",")

282

val tokens = tokenizer.asScala.toList // List("hello", "world", "scala")

283

```

284

285

## Performance Considerations

286

287

### View-Based Conversions

288

289

The conversions provided by `CollectionConverters` create lightweight wrappers rather than copying data:

290

291

```scala

292

val scalaList = List(1, 2, 3, 4, 5)

293

val javaList = scalaList.asJava // No copying - creates a wrapper

294

val backToScala = javaList.asScala // Also no copying

295

296

// Changes through one view affect the other (for mutable collections)

297

val scalaMutableList = mutable.ListBuffer(1, 2, 3)

298

val javaView = scalaMutableList.asJava

299

javaView.add(4)

300

println(scalaMutableList) // ListBuffer(1, 2, 3, 4)

301

```

302

303

### When to Copy

304

305

Sometimes you need to create independent copies:

306

307

```scala

308

import scala.jdk.CollectionConverters._

309

310

val scalaList = List(1, 2, 3)

311

val javaListCopy = new java.util.ArrayList(scalaList.asJava) // Independent copy

312

313

val javaMap = new java.util.HashMap[String, Int]()

314

javaMap.put("a", 1)

315

val scalaMapCopy = javaMap.asScala.toMap // Independent immutable copy

316

```

317

318

## Migration Notes

319

320

- In Scala 2.13+, use `scala.jdk.CollectionConverters` instead of the deprecated `JavaConverters`

321

- The `asJava`/`asScala` methods create lightweight wrappers, not copies

322

- For mutable collections, changes through one view affect the other

323

- For independent copies, explicitly create new collections from the converted views