Skal vi lukke en Java-stream?

1. Oversigt

Med introduktionen af ​​lambda-udtryk i Java 8 er det muligt at skrive kode på en mere kortfattet og funktionel måde. Streams og funktionelle grænseflader er hjertet i denne revolutionerende ændring i Java-platformen.

I denne hurtige vejledning lærer vi, om vi eksplicit skal lukke Java 8-streams ved at se på dem fra et ressourceperspektiv.

2. Afslutning af streams

Java 8 streams implementerer Kan lukkes automatisk grænseflade:

offentlig grænseflade Stream udvider BaseStream {// udeladt} offentlig grænseflade BaseStream udvider automatisk lukkelig {// udeladt}

Enkelt sagt, vi bør tænke på streams som ressourcer, som vi kan låne og returnere, når vi er færdige med dem. I modsætning til de fleste ressourcer behøver vi ikke altid lukke streams.

Dette kan måske lyde kontraintuitivt i starten, så lad os se, hvornår vi skal og hvornår vi ikke skal lukke Java 8-streams.

2.1. Samlinger, arrays og generatorer

Det meste af tiden skaber vi Strøm forekomster fra Java-samlinger, arrays eller generatorfunktioner. For eksempel arbejder vi her på en samling af Snor via Stream API:

Listefarver = List.of ("Rød", "Blå", "Grøn") .stream () .filter (c -> c.length ()> 4) .map (String :: toUpperCase) .collect (Collectors. toList ());

Nogle gange genererer vi en endelig eller uendelig sekventiel strøm:

Tilfældig tilfældig = ny tilfældig (); random.ints (). takeWhile (i -> i <1000) .forEach (System.out :: println);

Derudover kan vi også bruge array-baserede streams:

Streng [] farver = {"Rød", "Blå", "Grøn"}; Arrays.stream (farver) .map (String :: toUpperCase) .toArray ()

Når vi beskæftiger os med denne slags strømme, bør vi ikke lukke dem eksplicit. Den eneste værdifulde ressource, der er forbundet med disse streams, er hukommelse, og Garbage Collection (GC) sørger automatisk for det.

2.2. IO-ressourcer

Nogle streams understøttes dog af IO-ressourcer såsom filer eller sockets. F.eks Files.lines () metoden streamer alle linjer for den givne fil:

Files.lines (Paths.get ("/ path / to / file")) .flatMap (line -> Arrays.stream (line.split (","))) // udeladt

Under emhætten åbner denne metode en FileChannel instans og lukker den derefter ved lukning af strømmen. Derfor, hvis vi glemmer at lukke strømmen, forbliver den underliggende kanal åben, og så ender vi med en ressourcelækage.

For at forhindre sådanne ressourcelækager anbefales det stærkt at bruge prøv med ressourcer idiom til at lukke IO-baserede streams:

prøv (Stream linjer = Files.lines (Paths.get ("/ sti / til / fil"))) {lines.flatMap (line -> Arrays.stream (line.split (",")) // udeladt}

På denne måde lukker kompilatoren kanalen automatisk. Den vigtigste afhentning her er at lukke alle IO-baserede streams.

Bemærk, at lukning af en allerede lukket stream ville kaste IllegalStateException.

3. Konklusion

I denne korte vejledning så vi forskellene mellem enkle strømme og IO-tunge. Vi lærte også, hvordan disse forskelle informerer vores beslutning om, hvorvidt Java 8-streams skal lukkes eller ej.

Som sædvanlig er prøvekoden tilgængelig på GitHub.