On Fri, 5 Apr 2024 00:00:58 GMT, Evemose <d...@openjdk.org> wrote: > **Subject** > Addition of Predicate-based `indexOf` and `lastIndexOf` methods to > `java.util.List` > > **Motivation** > The motivation behind this proposal is to enhance the functionality of the > `List` interface by providing a more flexible way to find the index of an > element. Currently, the `indexOf` and `lastIndexOf` methods only accept an > object as a parameter. This limits the flexibility of these methods as they > can only find the index of exact object matches. > > The proposed methods would accept a `Predicate` as a parameter, allowing > users to define a condition that the desired element must meet. This would > provide a more flexible and powerful way to find the index of an element in a > list. > > Here is a brief overview of the changes made in this pull request: > > 1. Added the `indexOf(Predicate<? super E> filter)` method to the `List` > interface. > 2. Added the `lastIndexOf(Predicate<? super E> filter)` method to the `List` > interface. > 3. Implemented these methods in all non-abstract classes that implement the > `List` interface. > > The changes have been thoroughly tested to ensure they work as expected and > do not introduce any regressions. The test cases cover a variety of scenarios > to ensure the robustness of the implementation. > > For example, consider the following test case: > > List<String> list = new ArrayList<>(); > list.add("Object one"); > list.add("NotObject two"); > list.add("NotObject three"); > > int index1 = list.indexOf(s -> s.contains("ct t")); > System.out.println(index1); // Expected output: 1 > int index2 = list.lastIndexOf(s -> s.startsWith("NotObject")); > System.out.println(index2); // Expected output: 2 > > > Currently, to achieve the same result, we would have to use a more verbose > approach: > > int index1 = IntStream.range(0, list.size()) > .filter(i -> list.get(i).contains("ct t")) > .findFirst() > .orElse(-1); > System.out.println(index1); // Output: 1 > int index2 = IntStream.range(0, list.size()) > .filter(i -> list.get(i).startsWith("NotObject")) > .reduce((first, second) -> second) > .orElse(-1); > System.out.println(index2); // Output: 2 > > > I believe these additions would greatly enhance the functionality and > flexibility of the `List` interface, making it more powerful and > user-friendly. I look forward to your feedback and am open to making any > necessary changes based on your suggestions. > > Thank you for considering this proposal. > > Best regards
Newly added methods to existing widely‑implemented non‑sealed and non‑preview interfaces in `java.base` must be `default` to avoid source incompatibilities and runtime errors, so move the implementations from `AbstractList` to `List`: I’m in favour of using `findIndex`, which also avoids the issue with `List<Predicate<…>>::indexOf` being ambiguous and having binary incompatible bridge methods. src/java.base/share/classes/java/util/AbstractList.java line 29: > 27: > 28: import java.util.function.Consumer; > 29: import java.util.function.Predicate; This is now unused: Suggestion: src/java.base/share/classes/java/util/AbstractList.java line 221: > 219: return -1; > 220: } > 221: Suggestion: src/java.base/share/classes/java/util/AbstractList.java line 269: > 267: return -1; > 268: } > 269: Suggestion: src/java.base/share/classes/java/util/List.java line 702: > 700: * (<a > href="Collection.html#optional-restrictions">optional</a>) > 701: */ > 702: int lastIndexOf(Predicate<? super E> filter); Suggestion: /** * Returns the index of the first occurrence of matching element * in this list, or -1 if this list does not contain the element. * More formally, returns the lowest index {@code i} such that * {@code filter.test(get(i))}, * or -1 if there is no such index. * * @implSpec * This implementation first gets a list iterator (with * {@code listIterator()}). Then, it iterates over the list until a * matching element is found or the beginning of the list is reached. * * @param filter a predicate to search for * @return the index of the first occurrence of the specified element in * this list, or -1 if this list does not contain the element * @throws NullPointerException if passed filter is null */ default int indexOf(Predicate<? super E> filter) { Objects.requireNonNull(filter); ListIterator<E> it = listIterator(); while (it.hasNext()) { E e = it.next(); if (filter.test(e)) { return it.previousIndex(); } } return -1; } /** * Returns the index of the last occurrence of matching element * in this list, or -1 if this list does not contain the element. * More formally, returns the highest index {@code i} such that * {@code Objects.equals(o, get(i))}, * or -1 if there is no such index. * * @implSpec * This implementation first gets a list iterator that points to the end * of the list (with {@code listIterator(size())}). Then, it iterates * backwards over the list until the matching element is found, or the * beginning of the list is reached. * * @param filter a predicate to search for * @return the index of the last occurrence of the specified element in * this list, or -1 if this list does not contain the element * @throws NullPointerException if passed filter is null */ default int lastIndexOf(Predicate<? super E> filter) { Objects.requireNonNull(filter); ListIterator<E> it = listIterator(size()); while (it.hasPrevious()) { E e = it.previous(); if (filter.test(e)) { return it.nextIndex(); } } return -1; } ------------- Changes requested by exe-b...@github.com (no known OpenJDK username). PR Review: https://git.openjdk.org/jdk/pull/18639#pullrequestreview-1985396823 PR Comment: https://git.openjdk.org/jdk/pull/18639#issuecomment-2046339464 PR Review Comment: https://git.openjdk.org/jdk/pull/18639#discussion_r1555586424 PR Review Comment: https://git.openjdk.org/jdk/pull/18639#discussion_r1555192600 PR Review Comment: https://git.openjdk.org/jdk/pull/18639#discussion_r1555192654 PR Review Comment: https://git.openjdk.org/jdk/pull/18639#discussion_r1555194862