diff --git a/LICENSE b/LICENSE index 3e09223f..cc53a543 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Benjamin Winterberg +Copyright (c) 2023 Benjamin Winterberg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/README.md b/README.md index 360a48ba..e9caeed4 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,17 @@ # Modern Java - A Guide to Java 8 +_This article was originally posted on [my blog](http://winterbe.com/posts/2014/03/16/java-8-tutorial/)._ -> [“Java is still not dead—and people are starting to figure that out.”](https://twitter.com/mreinhold/status/429603588525281280) +> **You should also read my [Java 11 Tutorial](https://winterbe.com/posts/2018/09/24/java-11-tutorial/) (including new language and API features from Java 9, 10 and 11).** Welcome to my introduction to [Java 8](https://jdk8.java.net/). This tutorial guides you step by step through all new language features. Backed by short and simple code samples you'll learn how to use default interface methods, lambda expressions, method references and repeatable annotations. At the end of the article you'll be familiar with the most recent [API](http://download.java.net/jdk8/docs/api/) changes like streams, functional interfaces, map extensions and the new Date API. **No walls of text, just a bunch of commented code snippets. Enjoy!** -This article was originally posted on [my blog](http://winterbe.com/posts/2014/03/16/java-8-tutorial/). You should [follow me on Twitter](https://twitter.com/winterbe_). +--- + +

+ ★★★ Like this project? Leave a star, follow on Twitter or donate to support my work. Thanks! ★★★ +

+ +--- ## Table of Contents @@ -107,7 +114,7 @@ As you can see the code is much shorter and easier to read. But it gets even sho Collections.sort(names, (String a, String b) -> b.compareTo(a)); ``` -For one line method bodies you can skip both the braces `{}` and the `return` keyword. But it gets even more shorter: +For one line method bodies you can skip both the braces `{}` and the `return` keyword. But it gets even shorter: ```java names.sort((a, b) -> b.compareTo(a)); @@ -167,7 +174,7 @@ String converted = converter.convert("Java"); System.out.println(converted); // "J" ``` -Let's see how the `::` keyword works for constructors. First we define an example bean with different constructors: +Let's see how the `::` keyword works for constructors. First we define an example class with different constructors: ```java class Person { @@ -267,7 +274,7 @@ Remember the formula example from the first section? Interface `Formula` defines Default methods **cannot** be accessed from within lambda expressions. The following code does not compile: ```java -Formula formula = (a) -> sqrt( a * 100); +Formula formula = (a) -> sqrt(a * 100); ``` @@ -357,7 +364,7 @@ optional.ifPresent((s) -> System.out.println(s.charAt(0))); // "b" A `java.util.Stream` represents a sequence of elements on which one or more operations can be performed. Stream operations are either _intermediate_ or _terminal_. While terminal operations return a result of a certain type, intermediate operations return the stream itself so you can chain multiple method calls in a row. Streams are created on a source, e.g. a `java.util.Collection` like lists or sets (maps are not supported). Stream operations can either be executed sequentially or parallely. -> You should also check out [Stream.js](https://github.com/winterbe/streamjs), a JavaScript port of the Java 8 Streams API. +> Streams are extremely powerful, so I wrote a separate [Java 8 Streams Tutorial](http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/). **You should also check out [Sequency](https://github.com/winterbe/sequency) as a similiar library for the web.** Let's first look how sequential streams work. First we create a sample source in form of a list of strings: @@ -729,7 +736,7 @@ System.out.println(string); // Nov 03, 2014 - 07:13 Unlike `java.text.NumberFormat` the new `DateTimeFormatter` is immutable and **thread-safe**. -For details on the pattern syntax read [here](http://download.java.net/jdk8/docs/api/java/time/format/DateTimeFormatter.html). +For details on the pattern syntax read [here](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html). ## Annotations diff --git a/src/com/winterbe/java11/HttpClientExamples.java b/src/com/winterbe/java11/HttpClientExamples.java new file mode 100644 index 00000000..7342b1de --- /dev/null +++ b/src/com/winterbe/java11/HttpClientExamples.java @@ -0,0 +1,78 @@ +package com.winterbe.java11; + +import java.io.IOException; +import java.net.Authenticator; +import java.net.PasswordAuthentication; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +public class HttpClientExamples { + + public static void main(String[] args) throws IOException, InterruptedException { +// syncRequest(); +// asyncRequest(); +// postData(); + basicAuth(); + } + + private static void syncRequest() throws IOException, InterruptedException { + var request = HttpRequest.newBuilder() + .uri(URI.create("https://winterbe.com")) + .build(); + var client = HttpClient.newHttpClient(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + System.out.println(response.body()); + } + + private static void asyncRequest() { + var request = HttpRequest.newBuilder() + .uri(URI.create("https://winterbe.com")) + .build(); + var client = HttpClient.newHttpClient(); + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .thenApply(HttpResponse::body) + .thenAccept(System.out::println); + } + + private static void postData() throws IOException, InterruptedException { + var request = HttpRequest.newBuilder() + .uri(URI.create("https://postman-echo.com/post")) + .timeout(Duration.ofSeconds(30)) + .version(HttpClient.Version.HTTP_2) + .header("Content-Type", "text/plain") + .POST(HttpRequest.BodyPublishers.ofString("Hi there!")) + .build(); + var client = HttpClient.newHttpClient(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + System.out.println(response.statusCode()); // 200 + } + + private static void basicAuth() throws IOException, InterruptedException { + var client = HttpClient.newHttpClient(); + + var request1 = HttpRequest.newBuilder() + .uri(URI.create("https://postman-echo.com/basic-auth")) + .build(); + var response1 = client.send(request1, HttpResponse.BodyHandlers.ofString()); + System.out.println(response1.statusCode()); // 401 + + var authClient = HttpClient + .newBuilder() + .authenticator(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("postman", "password".toCharArray()); + } + }) + .build(); + var request2 = HttpRequest.newBuilder() + .uri(URI.create("https://postman-echo.com/basic-auth")) + .build(); + var response2 = authClient.send(request2, HttpResponse.BodyHandlers.ofString()); + System.out.println(response2.statusCode()); // 200 + } + +} diff --git a/src/com/winterbe/java11/LocalVariableSyntax.java b/src/com/winterbe/java11/LocalVariableSyntax.java new file mode 100644 index 00000000..e2a60906 --- /dev/null +++ b/src/com/winterbe/java11/LocalVariableSyntax.java @@ -0,0 +1,37 @@ +package com.winterbe.java11; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class LocalVariableSyntax { + + public static void main(String[] args) { + var text = "Banana"; +// Incompatible types: +// text = 1; + + +// Cannot infer type: +// var a; +// var nothing = null; +// var bla = () -> System.out.println("Hallo"); +// var method = LocalVariableSyntax::someMethod; + + var list1 = new ArrayList<>(); // ArrayList + + var list2 = new ArrayList>>(); + + for (var current : list2) { + // current is of type: Map> + System.out.println(current); + } + + Predicate predicate1 = (@Deprecated var a) -> false; + + } + + void someMethod() {} + +} diff --git a/src/com/winterbe/java11/Misc.java b/src/com/winterbe/java11/Misc.java new file mode 100644 index 00000000..e343dec7 --- /dev/null +++ b/src/com/winterbe/java11/Misc.java @@ -0,0 +1,69 @@ +package com.winterbe.java11; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Misc { + + @Deprecated(forRemoval = true) + String foo; + + public static void main(String[] args) throws IOException { + collections(); + strings(); + optionals(); + inputStreams(); + streams(); + } + + private static void streams() { + System.out.println(Stream.ofNullable(null).count()); // 0 + System.out.println(Stream.of(1, 2, 3, 2, 1) + .dropWhile(n -> n < 3) + .collect(Collectors.toList())); // [3, 2, 1] + System.out.println(Stream.of(1, 2, 3, 2, 1) + .takeWhile(n -> n < 3) + .collect(Collectors.toList())); // [1, 2] + } + + private static void inputStreams() throws IOException { + var classLoader = ClassLoader.getSystemClassLoader(); + var inputStream = classLoader.getResourceAsStream("com/winterbe/java11/dummy.txt"); + var tempFile = File.createTempFile("dummy-copy", "txt"); + try (var outputStream = new FileOutputStream(tempFile)) { + inputStream.transferTo(outputStream); + } + System.out.println(tempFile.length()); + } + + private static void optionals() { + System.out.println(Optional.of("foo").orElseThrow()); // foo + System.out.println(Optional.ofNullable(null).or(() -> Optional.of("bar")).get()); // bar + System.out.println(Optional.of("foo").stream().count()); // 1 + } + + private static void strings() { + System.out.println(" ".isBlank()); + System.out.println(" Foo Bar ".strip()); // "Foo Bar" + System.out.println(" Foo Bar ".stripTrailing()); // " Foo Bar" + System.out.println(" Foo Bar ".stripLeading()); // "Foo Bar " + System.out.println("Java".repeat(3)); // "JavaJavaJava" + System.out.println("A\nB\nC".lines().count()); // 3 + } + + private static void collections() { + var list = List.of("A", "B", "C"); + var copy = List.copyOf(list); + System.out.println(list == copy); // true + + var map = Map.of("A", 1, "B", 2); + System.out.println(map); + } + +} diff --git a/src/com/winterbe/java11/dummy.txt b/src/com/winterbe/java11/dummy.txt new file mode 100644 index 00000000..5eced957 --- /dev/null +++ b/src/com/winterbe/java11/dummy.txt @@ -0,0 +1 @@ +Foobar \ No newline at end of file diff --git a/src/com/winterbe/java8/samples/lambda/Lambda5.java b/src/com/winterbe/java8/samples/lambda/Lambda5.java new file mode 100644 index 00000000..68a311f4 --- /dev/null +++ b/src/com/winterbe/java8/samples/lambda/Lambda5.java @@ -0,0 +1,32 @@ +package com.winterbe.java8.samples.lambda; + +import java.util.HashMap; +import java.util.function.BiConsumer; + +/** + * Created by grijesh + */ +public class Lambda5 { + + //Pre-Defined Functional Interfaces + public static void main(String... args) { + + //BiConsumer Example + BiConsumer printKeyAndValue + = (key,value) -> System.out.println(key+"-"+value); + + printKeyAndValue.accept("One",1); + printKeyAndValue.accept("Two",2); + + System.out.println("##################"); + + //Java Hash-Map foreach supports BiConsumer + HashMap dummyValues = new HashMap<>(); + dummyValues.put("One", 1); + dummyValues.put("Two", 2); + dummyValues.put("Three", 3); + + dummyValues.forEach((key,value) -> System.out.println(key+"-"+value)); + + } +}