Jak używać subList ()

79

Mam stronę JSF, która wyświetla listę plików dziennika Glassfish. Używam leniwego ładowania do paginacji. Przechowuję listę nazw plików dziennika w Javie List.

private List<directoryListObj> dataList = new ArrayList<>();

dataList = dataList.subList(firstRow, lastRow);

I tu jest problem. Na przykład mam 35 plików w katalogu. Kiedy to robię

dataList = dataList.subList(5, 15);

To działa dobrze. Ale kiedy to robię:

dataList = dataList.subList(30, 38);

Otrzymuję błąd, zły indeks, ponieważ chcę, aby indeks był poza listą. Jak mogę na przykład zwrócić elementy listy od 30 do 35? Chcę, jeśli chcę uzyskać indeks od 30 do 40, ale jeśli jest tylko 35 indeksów, aby uzyskać tylko 5.

user1285928
źródło
13
dataList = dataList.subList(30, 38 > dataList.size() ? dataList.size() : 38);
pb2q
18
LubdataList.subList(30, Math.min(38, dataList.size())
Ismail Badawi
1
@ pb2q wygląda na to, że straciłeś szansę na odpowiedź.
Luiggi Mendoza
Jeśli spojrzysz na APIdoc , zauważysz, że rzuca IndexOutOfBoundsException - endpoint index value out of range (fromIndex < 0 || toIndex > size). Więc spójrz na APIdoc, aby znaleźć takie wskazówki w przyszłości.
zeller

Odpowiedzi:

97

Używanie subList(30, 38);nie powiedzie się, ponieważ max indeks 38 nie jest dostępny na liście, więc nie jest to możliwe.

Jedynym sposobem może być przed zapytaniem o podlistę, jawne określenie maksymalnego indeksu przy użyciu metody list size ().

na przykład sprawdź rozmiar, który zwraca 35, więc zadzwoń sublist(30, size());

LUB

SKOPIOWANE Z komentarza pb2q

dataList = dataList.subList(30, 38 > dataList.size() ? dataList.size() : 38);
kosa
źródło
6
To również by się nie udało, gdyby lista zawierała mniej niż 30 pozycji.
Haroldo_OK
@Haroldo_OK: Tak, masz rację, ale założono, że lista zawiera ponad 30 pozycji.
kosa
3
WolędataList = dataList.subList(30, Math.min(38, dataList.size()));
Benny Bottema
46

Wdrożyłem i przetestowałem ten; powinien obejmować większość baz:

public static <T> List<T> safeSubList(List<T> list, int fromIndex, int toIndex) {
    int size = list.size();
    if (fromIndex >= size || toIndex <= 0 || fromIndex >= toIndex) {
        return Collections.emptyList();
    }

    fromIndex = Math.max(0, fromIndex);
    toIndex = Math.min(size, toIndex);

    return list.subList(fromIndex, toIndex);
}
Haroldo_OK
źródło
4
To powinna być akceptowana odpowiedź, jedyna, która zadała sobie trud przetestowania swojego kodu.
Ed Randall,
2
Bardzo pomocne, dzięki. Rozbicie tego na metodę ma więcej sensu niż próba podsumowania logiki operatorami trójskładnikowymi, po prostu staje się zbyt trudne do odczytania w ten sposób.
Steve
43

Aby uzyskać ostatni element, po prostu użyj rozmiaru listy jako drugiego parametru. Na przykład, jeśli masz 35 plików i chcesz mieć pięć ostatnich, zrobiłbyś:

dataList.subList(30, 35);

Gwarantowanym bezpiecznym sposobem na to jest:

dataList.subList(Math.max(0, first), Math.min(dataList.size(), last) );
Joe K.
źródło
4
To również nie powiedzie się, jeśli „pierwszy” jest większy niż rozmiar listy.
Haroldo_OK
3
@Haroldo_OK: lub jeśli lastjest ujemne!
Tagir Valeev
Nie uda się też, jeślifirst >= last
augurar
7

Możesz użyć strumieni w Javie 8. Aby zawsze uzyskać najwyżej 10 wpisów, możesz zrobić:

dataList.stream().skip(5).limit(10).collect(Collectors.toList());
dataList.stream().skip(30).limit(10).collect(Collectors.toList());
Stefan Haberl
źródło