W3docs

Класс URL в Java

Разбор и представление URL в Java с помощью класса URL — протокол, хост, порт, путь, запрос.

URL (Uniform Resource Locator) идентифицирует ресурс и способ его получения: https://www.example.com:443/docs?q=net#top. Java моделирует его с помощью java.net.URL, который одновременно разбирает URL на составные части и может открывать соединение для его загрузки. Эта глава посвящена разбору и структуре; открытие соединения для реальной загрузки байтов рассматривается в Java URLConnection.

На этой странице описаны части URL, геттеры, которые их раскрывают, способы создания URL (включая разрешение относительных ссылок), а также причины, по которым в современном коде следует использовать URI вместо устаревших строковых конструкторов URL.

Анатомия URL

  https://user:[email protected]:8443/docs/java?topic=net#intro
  └─┬─┘   └──┬──┘ └──────┬───────┘└┬─┘└───┬────┘ └────┬────┘└─┬─┘
 protocol  userInfo     host     port   path        query    ref

java.net.URL предоставляет каждую часть через геттер: getProtocol(), getUserInfo(), getHost(), getPort(), getPath(), getQuery() и getRef() (фрагмент). getPort() возвращает -1, если порт не указан; getDefaultPort() возвращает стандартный порт для протокола (80 для http, 443 для https).

Создание URL

URL url = new URL("https://example.com/path?x=1");      // from a string
URL rel = new URL(base, "../images/logo.png");          // relative to a base

Двухаргументный конструктор разрешает относительную ссылку относительно базового URL — по тем же правилам, которые браузер применяет для ссылок на странице. Именно так ../images/logo.png на странице /a/b/page.html превращается в абсолютный путь /a/images/logo.png.

Предпочитайте URI для разбора и валидации

В современных JDK строковые конструкторы URL устарели. URL теперь предназначен для открытия соединений, а не для разбора или валидации. Для чистого разбора используйте java.net.URI и преобразуйте в URL только в момент, когда нужно открыть соединение:

URI uri = URI.create("https://example.com/path?x=1");   // parse / validate
URL url = uri.toURL();                                   // only to open a connection

Также важно знать об известной ловушке: URL.equals() и URL.hashCode() могут выполнять DNS-разрешение для сравнения хостов, что делает их медленными и зависящими от сети. Никогда не помещайте объекты URL в HashSet и не используйте их в качестве ключей map — используйте URI, чья проверка равенства основана исключительно на тексте.

Практический пример: разбор и разрешение URL

Эта программа разбирает полный URL на составные части, разрешает относительную ссылку и сравнивает URL с удобным для разбора URI — всё без сетевых обращений, поскольку разбор не требует подключения к сети.

java— editable, runs on the server

Что следует вынести из этого примера:

  • Каждый геттер извлёк один именованный фрагмент из строки URL: протокол, информацию о пользователе, хост, порт, путь, запрос и фрагмент #intro через getRef(). URL — это структурированное значение, а не просто текст: лучше разобрать его один раз и читать поля, чем вручную применять String.split по символам / и ?.
  • URL без порта вернул getPort() == -1, тогда как getDefaultPort() вернул 80. Это различие важно при установке соединения: -1 означает «порт не указан», и следует использовать стандартный порт для протокола, а не трактовать -1 как реальный порт.
  • base.resolve("../images/logo.png") сформировал абсолютный URL, выйдя из директории /a/b/ — именно так браузер разрешает относительные ссылки. Относительные ссылки разрешаются относительно базового URL, поэтому путь базы определяет, куда ведёт ...
  • В примере URL создаётся через URI.create(...).toURL(), а не через устаревший new URL(String). В современных JDK это рекомендуемый подход: разбирайте и валидируйте с помощью URI, преобразуйте в URL только в момент открытия соединения.
  • URI.equals сравнил два идентичных URI текстуально и вернул true без обращения к сети. Это безопасный способ сравнения и использования в качестве ключей map — URL.equals мог бы инициировать DNS-запрос для разрешения хоста, что медленно и может завершиться ошибкой при отсутствии сети.

Получив объект URL, следующим шагом обычно является его открытие. Для низкоуровневого потока используйте url.openConnection() (см. Java URLConnection); для современного высокоуровневого HTTP API предпочтите Java HttpClient.

Практика

Практика
Коллега хранит загружаемые ресурсы в 'HashSet<URL>', чтобы пропускать дубликаты, и замечает, что программа работает медленно и иногда зависает без подключения к сети. Какое объяснение и решение верны?
Коллега хранит загружаемые ресурсы в 'HashSet<URL>', чтобы пропускать дубликаты, и замечает, что программа работает медленно и иногда зависает без подключения к сети. Какое объяснение и решение верны?
Was this page helpful?