Класс 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 refjava.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 — всё без сетевых обращений, поскольку разбор не требует подключения к сети.
Что следует вынести из этого примера:
- Каждый геттер извлёк один именованный фрагмент из строки 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.