Hilfe bei einfachem Stream-Beispiel

Bitte helft mir bei einem einfachem Beispiel, ich möchte ein Verzeichnis auflisten:

import java.io.File;
import java.util.Arrays;
import java.util.Comparator;

public class ListDirs {
    public static void main(String[] args) {
        File d = new File("a Directory");
        File[] files = d.listFiles();
        Arrays.stream(files)
                .filter(File::isDirectory)
                .sorted(Comparator.comparing(File::lastModified).reversed())
                .limit(12)
                .map(File::getName)
                .map(s -> s.substring(0, s.lastIndexOf('-') - 5))
                .forEach(System.out::println);
    }
}

Arrays.stream(files) files könnte null sein…
.limit(12) was passiert bei weniger als 12?
s -> s.substring(0, s.lastIndexOf('-') - 5) lässt sich das vereinfachen?

Vielen Dank!

Edit: Könnte das ein Kompromiss sein?:

import java.io.File;
import java.util.Arrays;
import java.util.Comparator;

public class ListDirs {
    public static void main(String[] args) {
        @SuppressWarnings("SpellCheckingInspection")
        File d = new File("abc");
        File[] files = d.listFiles();
        assert files != null;
        Arrays.stream(files)
                .filter(File::isDirectory)
                .sorted(Comparator.comparing(File::lastModified).reversed())
                .limit(12)
                .map(File::getName)
                .map(s -> s.substring(0, s.lastIndexOf('-') - 5)) // negative value?
                .forEach(System.out::println);
    }
}

Du könntest noch Filenamen ohne '-' herausfiltern, damit es in substring() nicht kracht.

limit() hat kein Problem mit kürzeren Streams

Besser oder „unübersichtlich“?

import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;

public class ListDirs {

    public static String getSub(String s) {
        if (!s.contains("-")) {
            return null;
        }
        int lio = s.lastIndexOf('-') - 5;
        if (lio <= 0) {
            return null;
        }
        return s.substring(0, lio);
    }

    public static void main(String[] args) {
        @SuppressWarnings("SpellCheckingInspection")
        File d = new File("a b c");
        File[] files = d.listFiles();
        assert files != null;
        Arrays.stream(files)
                .filter(File::isDirectory)
                .sorted(Comparator.comparing(File::lastModified).reversed())
                .limit(12)
                .map(File::getName)
                .map(ListDirs::getSub)
                .filter(Objects::nonNull)
                .forEach(System.out::println);
    }
}

Das .limit(12) steht jetzt an falscher Stelle…

Ich würde die Method getSub() sprechender machen. Was tut diese Methode?
Auch den Parameter lio würde ich sprechend umformulieren.
Ich würde vermutlich auch als Rückgabewert auf Optional setzen. Das macht die Signature der Methode klarer.

Das Limit würde ich einfach vor das letzte forEach setzen.

Jetzt gefällt mir es und die Klasse ist auch grün geworden:

import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Predicate;

public class ListDirs {
    public static void main(String[] args) {
        @SuppressWarnings("SpellCheckingInspection")
        File d = new File("...");
        File[] files = d.listFiles();
        assert files != null;
        Arrays.stream(files)
                .filter(File::isDirectory)
                .sorted(Comparator.comparing(File::lastModified).reversed())
                .map(File::getName)
                .filter(((Predicate<String>) s -> s.contains("-")).and(s -> s.lastIndexOf('-') - 5 > 0))
                .map(s -> s.substring(0, s.lastIndexOf('-') - 5))
                .limit(12)
                .forEach(System.out::println);
    }
}

@Landei Eine Frage zur Theorie… Ist .limit( ) vor- oder nachgreifend? Also es gilt nicht für den gesamten Stream oder? Nur für alles danach. Dann sollte es doch eigentlich so früh wie möglich platziert werden.

Denk einfach darüber nach was du machen willst und wie limit dir dabei hilft oder dich behindert

Es beschränkt die Anzahl Elemente an der Stelle, wo es aufgerufen wird (ist aber trotzdem so lazy wie möglich). Aber ganz ehrlich, du kannst so eine Sache schneller ausprobieren, als hier eine Frage zu stellen:

System.out.println(Stream.of(1,2,3,4,5,6).limit(2).filter(x -> x % 2 == 0).collect(Collectors.toList()));
// [2]
System.out.println(Stream.of(1,2,3,4,5,6).filter(x -> x % 2 == 0).limit(2).collect(Collectors.toList()));
// [2, 4]

Sehe ich das denn richtig, wenn ich das limit eine Zeile weiter oben geschrieben hätte (also zwischen filter und map), dass dann intern genau ein substring-Aufruf eingespart würde?