Java 11 (выпущена в сентябре 2018 года) включает в себя множество важных и полезных обновлений. Давайте посмотрим, какие новые функции и улучшения он принесет разработчикам и архитекторам.
HTTP Client API
Java долгое время имела класс HttpURLConnection для HTTP-связи. Но со временем требования к приложениям стали более сложными и требовательными. До появления Java 11 разработчикам приходилось прибегать к многофункциональным библиотекам, таким как Apache HttpComponents или OkHttp и т.д.
В релизе Java 9, который включал реализацию HttpClient в качестве экспериментальной функции. Со временем он вырос и теперь является последней функцией Java 11. Теперь Java-приложения могут осуществлять HTTP-связь без необходимости какой-либо внешней зависимости.
Как использовать HttpClient
Типичное HTTP-взаимодействие с модулем java.net.http выглядит следующим образом-
- Создается экземпляр HttpClient и настраивается по мере необходимости.
- Создается экземпляр HttpRequest и заполняется информация.
- Передается запрос клиенту, выполняется запрос и извлекается экземпляр HttpResponse.
- Обрабатывается информация, содержащуюся в HttpResponse.
HTTP API может обрабатывать синхронную и асинхронную связь. Давайте рассмотрим краткий пример.
Пример синхронного запроса
Обратите внимание, как API HttpClient использует шаблон builder для создания сложных объектов.
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
try
{
String urlEndpoint = "https://postman-echo.com/get";
URI uri = URI.create(urlEndpoint + "?foo1=bar1&foo2=bar2");
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Status code: " + response.statusCode());
System.out.println("Headers: " + response.headers().allValues("content-type"));
System.out.println("Body: " + response.body());
Пример асинхронного запроса
Асинхронная связь полезна, если мы не хотим ждать ответа. Мы предоставляем обработчик обратного вызова, который выполняется при наличии ответа.
Обратите внимание на использование метода SendAsync() для отправки асинхронного запроса.
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
final List<URI> uris = Stream.of(
"https://www.google.com/",
"https://www.github.com/",
"https://www.yahoo.com/"
).map(URI::create).collect(toList());
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();
CompletableFuture[] futures = uris.stream()
.map(uri -> verifyUri(httpClient, uri))
.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();
private CompletableFuture<Void> verifyUri(HttpClient httpClient,
URI uri)
{
HttpRequest request = HttpRequest.newBuilder()
.timeout(Duration.ofSeconds(5))
.uri(uri)
.build();
return httpClient.sendAsync(request,HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::statusCode)
.thenApply(statusCode -> statusCode == 200)
.exceptionally(ex -> false)
.thenAccept(valid ->
{
if (valid) {
System.out.println(
"[SUCCESS] Verified " + uri);
} else {
System.out.println(
"[FAILURE] Could not " + "verify " + uri);
}
});
}
Запуск однофайловых приложений без компиляции
Традиционно для каждой программы, которую мы хотели бы выполнить, нам нужно сначала скомпилировать ее. Это кажется излишне длительным процессом для небольших программ в целях тестирования.
Java 11 изменяет его, и теперь мы можем выполнять исходный код Java, содержащийся в одном файле, без необходимости его предварительной компиляции.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Чтобы выполнить вышеуказанный класс, запустите его непосредственно с помощью команды java.
$ java HelloWorld.java
Hello World!
Обратите внимание, что программа не может использовать какие-либо внешние зависимости, кроме модуля java.base. И программа может быть только однофайловой программой.
Изменения String API
String.repeat(Integer)
Этот метод просто повторяет строку n раз. Он возвращает строку, значение которой является конкатенацией данной строки, повторяющейся N раз.
Если эта строка пуста или количество равно нулю, то возвращается пустая строка.
public class HelloWorld
{
public static void main(String[] args)
{
String str = "1".repeat(5);
System.out.println(str); //11111
}
}
String.isBlank()
Этот метод указывает, является ли строка пустой или содержит только пробелы. Ранее мы использовали его из Apache StringUtils.java .
public class HelloWorld
{
public static void main(String[] args)
{
"1".isBlank(); //false
"".isBlank(); //true
" ".isBlank(); //true
}
}
String.strip()
Этот метод заботится об удалении начальных и конечных пробелов. Мы также удалять только начальные символы с помощью String.strip Leading() или только конечные символы с помощью String.stripTrailing().
public class HelloWorld
{
public static void main(String[] args)
{
" hi ".strip(); //"hi"
" hi ".stripLeading(); //"hi "
" hi ".stripTrailing(); //" hi"
}
}
String.lines()
Этот метод помогает обрабатывать многострочные тексты в виде потока.
HelloWorld.java
public class HelloWorld
{
public static void main(String[] args)
{
String testString = "hello\nworld\nis\nexecuted";
List<String> lines = new ArrayList<>();
testString.lines().forEach(line -> lines.add(line));
assertEquals(List.of("hello", "world", "is", "executed"), lines);
}
}
Collection.toArray(IntFunction)
До появления Java 11 преобразование коллекции в массив было непростым делом. Java 11 делает преобразование более удобным.
public class HelloWorld
{
public static void main(String[] args)
{
List<String> names = new ArrayList<>();
names.add("alex");
names.add("brian");
names.add("charles");
String[] namesArr1 = names.toArray(new String[names.size()]); //Before Java 11
String[] namesArr2 = names.toArray(String[]::new); //Since Java 11
}
}
Files.readString() и Files.writeString()
Используя эти перегруженные методы, Java 11 стремится сократить количество шаблонного кода, что значительно упрощает чтение и запись файлов.
public class HelloWorld
{
public static void main(String[] args)
{
//Read file as string
URI txtFileUri = getClass().getClassLoader().getResource("helloworld.txt").toURI();
String content = Files.readString(Path.of(txtFileUri),Charset.defaultCharset());
//Write string to file
Path tmpFilePath = Path.of(File.createTempFile("tempFile", ".tmp").toURI());
Path returnedFilePath = Files.writeString(tmpFilePath,"Hello World!",
Charset.defaultCharset(), StandardOpenOption.WRITE);
}
}
Optional.isEmpty()
Optional это объект-контейнер, который может содержать или не содержать ненулевое значение. Если значение отсутствует, объект считается пустым.
Ранее существовавший метод isPresent() возвращает true, если присутствует значение, в противном случае false. Иногда это заставляет нас писать отрицательные условия, которые не читаются.
Метод isEmpty() является обратным методу is Present() и возвращает значение false, если значение присутствует, в противном случае true.
Поэтому теперь не надо писать отрицательные условия. При необходимости используйте любой из этих двух методов.
public class HelloWorld
{
public static void main(String[] args)
{
String currentTime = null;
//It's negative condition
assertTrue(!Optional.ofNullable(currentTime).isPresent());
//Write it like this
assertTrue(Optional.ofNullable(currentTime).isEmpty());
currentTime = "12:00 PM";
//It's negative condition
assertFalse(!Optional.ofNullable(currentTime).isPresent());
//Write it like this
assertFalse(Optional.ofNullable(currentTime).isEmpty());
}
}