Find: примеры (JAVA)

Примеры работы методов find
Раздел: Верификация (валидация), Регулярные выражения
find: boolean

Общее описание

В Java под именем find чаще понимается не одна функция, а несколько методов в разных API, предназначенных для поиска: поиск совпадений регулярного выражения (java.util.regex.Matcher.find()), поиск файлов в дереве каталогов (java.nio.file.Files.find()), а также операции потока, возвращающие найденный элемент (java.util.stream.Stream.findFirst() и findAny()). Ниже приведено краткое, но подробное описание наиболее распространённых вариантов.

java.util.regex.Matcher.find()

Сигнатура: boolean find() и boolean find(int start).

Назначение

Ищет следующее (или первое при вызове в начале) совпадение шаблона в входной строке. При успешном нахождении соответствующие методы group(), start(), end() возвращают данные о совпадении.

Аргументы

  • int start - опциональный индекс в исходной строке, с которого начинается поиск.

Возвращаемое значение

true при нахождении совпадения, false при отсутствии.

java.nio.file.Files.find()

Сигнатура: Stream find(Path start, int maxDepth, BiPredicate matcher, FileVisitOption... options).

Назначение

Производит обход дерева файлов, начиная с start, до глубины maxDepth, и возвращает поток путей, удовлетворяющих предикату matcher. Рекомендуется оборачивать результат в try-with-resources для закрытия потока.

Аргументы

  • Path start - корневой каталог для поиска.
  • int maxDepth - максимальная глубина обхода (0 - только сам каталог).
  • BiPredicate<Path,BasicFileAttributes> matcher - предикат для фильтрации путей по атрибутам.
  • FileVisitOption... options - опции обхода (например, FOLLOW_LINKS).

Возвращаемое значение

Поток Stream<Path>. При ошибках ввода-вывода исключение выбрасывается при попытке терминальной операции.

java.util.stream.Stream.findFirst()/findAny()

Сигнатуры: Optional<T> findFirst(), Optional<T> findAny().

Назначение

Выполняет терминальную операцию поиска элемента: findFirst возвращает первый элемент потока в порядке источника; findAny разрешает возвращать любой элемент, особенно полезен в параллельных потоках для повышения производительности.

Аргументы

Аргументы отсутствуют. Часто применяется после операций фильтрации.

Возвращаемое значение

Optional<T>, пустой если элемент не найден.

Короткие примеры

1) Matcher.find - извлечение всех вхождений

import java.util.regex.*;

Pattern p = Pattern.compile("\\b\\w+\\b");
Matcher m = p.matcher("one two 123");
while (m.find()) {
    System.out.println(m.group() + " (" + m.start() + "," + m.end() + ")");
}
one (0,3)
two (4,7)
123 (8,11)

2) Stream.findFirst - поиск первого удовлетворяющего элемента

import java.util.*;

Optional<Integer> r = Arrays.asList(5, 3, 8, 1, 9).stream()
    .filter(x -> x > 4)
    .findFirst();
System.out.println(r);
Optional[5]

3) Files.find - поиск файлов с расширением .java (короткий вывод)

import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.io.IOException;

try (var s = Files.find(Paths.get("src"), 5,
        (path, attr) -> attr.isRegularFile() && path.toString().endsWith(".java"))) {
    s.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}
src/com/example/Main.java
src/com/example/util/Helper.java
... (список файлов .java)

Похожие методы в Java

  • String.indexOf() - поиск подстроки по строковым индексам; предпочтителен для простого поиска подстроки без шаблонов и с низкой нагрузкой.
  • Pattern.matches() - проверка полного соответствия всей строки шаблону; отличается от Matcher.find(), который ищет подстроки.
  • List.indexOf() - поиск позиции элемента в списке (равенство через equals); применяется при необходимости индекса, а не объекта-обёртки Optional.
  • Stream.filter(...).findFirst() - комбинация фильтрации и поиска; если нужен конкретный найденный элемент, эта пара часто удобнее чем ручной цикл.

Выбор зависит от задачи: для шаблонного поиска - Matcher.find(), для поиска по файловой структуре - Files.find(), для поиска элементов коллекций - операции Stream или методы коллекций.

Аналоги в других языках

PHP

// preg_match_all
$subject = "one two 123";
preg_match_all('/\\b\\w+\\b/', $subject, $m);
print_r($m[0]);
Array
(
    [0] => one
    [1] => two
    [2] => 123
)

JavaScript

// RegExp.prototype.exec и String.indexOf
const str = 'one two 123';
const re = /\b\w+\b/g;
let m;
while ((m = re.exec(str)) !== null) {
  console.log(m[0], m.index);
}
// String.prototype.indexOf
console.log(str.indexOf('two'));
one 0
two 4
123 8
4

Python

import re
s = 'one two 123'
for m in re.finditer(r'\b\w+\b', s):
    print(m.group(), m.start(), m.end())
# list.index
print([5,3,8].index(3))
one 0 3
two 4 7
123 8 11
1

SQL

-- Поиск строк с LIKE
SELECT * FROM users WHERE name LIKE '%Ivan%';
(записи, в которых имя содержит 'Ivan')

C#

using System.Text.RegularExpressions;

var m = Regex.Match("one two 123", "\\b\\w+\\b");
while (m.Success) {
  Console.WriteLine($"{m.Value} ({m.Index},{m.Index + m.Length})");
  m = m.NextMatch();
}
one (0,3)
two (4,7)
123 (8,11)

Go

import (
  "fmt"
  "regexp"
)

r := regexp.MustCompile(`\\b\\w+\\b`)
fmt.Println(r.FindAllString("one two 123", -1))
[one two 123]

Отличия от Java-запросов: синтаксис регулярных выражений близок, но управление потоками и доступ к файловой системе различается по API и по поведению параллелизма. В языках со встроенными функциями поиска (Python, JS) код короче, тогда как в Java для безопасности и масштабируемости часто требуется явное закрытие ресурсов и работа с Optional.

Типичные ошибки и примеры

1) Ошибка: ожидание полного совпадения при использовании find()

import java.util.regex.*;

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("abc123");
System.out.println(m.matches()); // ожидают true, но...
false

Объяснение: matches() проверяет всю строку; для поиска подстроки требуется find().

2) Не закрыт поток от Files.find()

import java.nio.file.*;

Stream<Path> s = Files.find(Paths.get("."), 2, (p,a) -> true);
// пропущен try-with-resources
s.forEach(System.out::println);
(работает, но ресурс не закрыт - возможны утечки дескрипторов)

3) Неправильное использование findAny в последовательном потоке при ожидании предсказуемого элемента

Optional<Integer> any = Arrays.asList(1,2,3).stream().findAny();
System.out.println(any);
Optional[1]

Примечание: в последовательном потоке результат детерминирован, но в параллельном findAny может вернуть другой элемент.

4) NullPointerException при использовании Optional без проверки

Optional<String> o = Optional.empty();
String s = o.get(); // исключение
Exception in thread "main" java.util.NoSuchElementException: No value present

Изменения в последних версиях Java

Интерфейсы Matcher.find(), Files.find() и методы Stream API (findFirst, findAny) существуют давно (в основном с Java 8 и ранее). В недавних релизах не было кардинальных изменений в их сигнатурах. Основные эволюционные изменения в экосистеме касаются улучшений производительности JVM и оптимизаций Stream API в реализации, а также появлению новых утилит в сопутствующих пакетах (например, дополнительные методы в классе Pattern/Matcher в более новых релизах). Следует внимательно читать примечания к релизам JVM для деталей о производительности и поведении параллельных потоков.

Расширенные и нестандартные примеры

1) Выбор N-го совпадения с помощью Matcher

Пример java
import java.util.regex.*;

Pattern p = Pattern.compile("\\b\\w+\\b");
Matcher m = p.matcher("a b c d e");
int target = 3; // третье совпадение (1-based)
int count = 0;
while (m.find()) {
    count++;
    if (count == target) {
        System.out.println("Match: " + m.group());
        break;
    }
}
if (count < target) System.out.println("Не найдено");
Match: c

2) Files.find с комплексным предикатом (по размеру и расширению) и безопасным закрытием

Пример java
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.io.IOException;

try (var s = Files.find(Paths.get("."), 4,
        (path, attr) -> attr.isRegularFile()
            && path.toString().endsWith(".log")
            && attr.size() > 1024)) {
    s.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}
./logs/app.log
./archive/old.log
... (файлы .log больше 1 KB)

3) Параллельный Stream и findAny для производительности

Пример java
import java.util.*;

Optional<Integer> any = Arrays.asList(1,2,3,4,5,6,7,8,9,10)
    .parallelStream()
    .filter(x -> heavyCheck(x))
    .findAny();
System.out.println(any);

static boolean heavyCheck(int x) {
    try { Thread.sleep(50); } catch (InterruptedException e) {}
    return x % 7 == 0;
}
Optional[7]  // может отличаться при других запусках в параллели

4) Извлечение имен и позиций совпадений с группами и последующая подстановка

Пример java
import java.util.regex.*;

String s = "John: 25, Mary: 30";
Pattern p = Pattern.compile("(\\w+):\\s*(\\d+)");
Matcher m = p.matcher(s);
StringBuffer sb = new StringBuffer();
while (m.find()) {
    String name = m.group(1);
    String age = m.group(2);
    m.appendReplacement(sb, name + "(" + age + ")");
}
m.appendTail(sb);
System.out.println(sb.toString());
John(25), Mary(30)

5) Комбинация Files.find и Stream API для поиска и ранней остановки через findFirst

Пример java
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.io.IOException;

try (var s = Files.find(Paths.get("."), 10,
        (p, a) -> a.isRegularFile() && p.toString().endsWith(".properties"))) {
    Optional<Path> any = s.filter(p -> p.getFileName().toString().contains("app"))
                             .findFirst();
    System.out.println(any);
} catch (IOException e) {
    e.printStackTrace();
}
Optional[./config/app.properties]  // или Optional.empty()

6) Поиск с учётом локали и сложных шаблонов (lookahead/lookbehind)

Пример java
import java.util.regex.*;

String s = "price: $12.50, tax: $1.25";
Pattern p = Pattern.compile("(?<=\\$)\\d+\\.\\d{2}");
Matcher m = p.matcher(s);
while (m.find()) System.out.println(m.group());
12.50
1.25

В продвинутых сценариях рекомендуется сочетать возможности API: регулярные выражения для сложных текстовых матчей, Files.find для файловой фильтрации и Stream.findFirst/findAny для управляемого извлечения элементов и оптимизации производительности.

джава find function comments

En
Find Attempts to find the next subsequence of the input sequence that matches the pattern