List<Dish> vegetarianMenu = menu.stream()//
.filter(Dish::isVegetarian)//Predicate<T> as a parameter
.collect(toList());
vegetarianMenu.forEach(System.out::println);
// Filtering unique elements
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()//
.filter(i -> i % 2 == 0)//
.distinct()//
.forEach(System.out::println);
// Truncating a stream
List<Dish> dishesLimit3 = menu.stream()//
.filter(d -> d.getCalories() > 300)//
.limit(3)//
.collect(toList());
dishesLimit3.forEach(System.out::println);
List<Dish> dishesSkip2 = menu.stream()//
.filter(d -> d.getCalories() > 300)//
.skip(2)//
.collect(toList());
dishesSkip2.forEach(System.out::println);
// map
List<String> dishNames = Dish.menu.stream()
.map(Dish::getName)
.collect(toList());
System.out.println(dishNames);
// map
List<String> words = Arrays.asList("Hello", "World");
List<Integer> wordLengths = words.stream()
.map(String::length)
.collect(toList());
System.out.println(wordLengths);
PS. Multiple map flattening
task
Given a word list ["Hello","World"],
Want to return to the list ["H","e","l","o","W","r","d"]
The first version
words.stream()
.map(word -> word.split("")) //Return Stream<String[]>
.distinct()
.collect(toList());
The problem with this method is that the Lambda passed to the map method returns a String[] (List of Strings) for each word. Therefore, the flow returned by the map is actuallyStream<String[]> Type of . What you really want is to use Stream to represent a string stream.
The solution
1. Try to use map and Array.stream()
String[] arrayOfWords = {"Goodbye", "World"};
Stream<String> streamOfwords = Arrays.stream(arrayOfWords);
//What is returned is not the desired List<String>
List<Stream<String>> list = words.stream()
.map(word -> word.split(""))// Return Stream<String[]>
.map(Arrays::stream)// Return Stream<Stream<String>>
.distinct()
.collect(toList());
2. Use flatMap
List<String> uniqueCharacters =
words.stream()
.map(w -> w.split(""))// Return Stream<String[]>
.flatMap(Arrays::stream)// Return Stream<String>, compress Stream<Stream<String>> into Stream<String>
.distinct()
.collect(Collectors.toList());
In a nutshell, the flatmap method allows you to replace every value in one stream with another stream, and then connect all streams into one stream.
PS. flatmap can compress Stream<Stream> into Stream
//Simplified some
words.stream()
.flatMap((String line) -> Arrays.stream(line.split("")))
.distinct()
.forEach(System.out::println);
0. Given a list of numbers, how to return a list consisting of the square of each number? For example, given [1, 2, 3, 4, 5], it should return [1, 4, 9, 16, 25]
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(toList());
1. Given two lists of numbers, how to return all the number pairs? For example, given list [1, 2, 3] and list [3, 4], it should return [[1, 3], [1, 4], [2, 3], [2, 4], [3, 3], [3, 4]]. For simplicity, you can use an array with two elements to represent pairs of numbers.
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs = numbers1.stream()
.flatMap(i -> numbers2.stream()
.map(j -> new int[]{i, j})
)
.collect(toList());
2. How to extend the previous example to only return the number pairs whose sum is divisible by 3? For example, [2, 4] and [3, 3] are possible.
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs =
numbers1.stream()
.flatMap(i ->
numbers2.stream()
.filter(j -> (i + j) % 3 == 0)
.map(j -> new int[]{i, j})
)
.collect(toList());
private static boolean isVegetarianFriendlyMenu() {
return Dish.menu.stream().anyMatch(Dish::isVegetarian);
}
private static boolean isHealthyMenu() {
return Dish.menu.stream().allMatch(d -> d.getCalories() < 1000);
}
private static boolean isHealthyMenu2() {
return Dish.menu.stream().noneMatch(d -> d.getCalories() >= 1000);
}
The three operations anyMatch, allMatch and noneMatch all use the so-calledShort circuit, This is the familiar version of the && and || operators in Java that short-circuit in the stream
Optional<Dish> dish =
menu.stream()
.filter(Dish::isVegetarian)
.findAny();
The Optional<T> class (java.util.Optional) is a container class that represents the presence or absence of a value. In the above code, findAny may not find any elements. The library designers of Java 8 introduced Optional<T> so that there is no need to return null, which is known to be problematic.
There are several ways in Optional that can force you to explicitly check for the existence of a value or handle situations where the value does not exist.
menu.stream()
.filter(Dish::isVegetarian)
.findAny()
.ifPresent(d -> System.out.println(d.getName());
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstSquareDivisibleByThree =
someNumbers.stream()
.map(x -> x * x)
.filter(x -> x % 3 == 0)
.findFirst();
You may wonder, why are there both findFirst and findAny? the answer isparallel. Finding the first element is more restrictive in parallelism. If you don't care which element is returned, please use findAny, because it is less restrictive when using parallel streams.
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
//or
int sum = numbers.stream().reduce(0, Integer::sum);
reduce accepts two parameters:
No initial value
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));
Why does it return an Optional? Consider the case where there are no elements in the stream. The reduce operation cannot return its sum because it has no initial value. This is why the result is wrapped in an Optional object to indicate that the sum may not exist.
int product = numbers.stream().reduce(1, (a, b) -> a * b);
Optional<Integer> max = numbers.stream().reduce(Integer::max);
Optional<Integer> min = numbers.stream().reduce(Integer::min);
//Of course it can also be written as Lambda (x, y) -> x <y? X: y instead of Integer::min, but the latter is easier to read
int count = menu.stream()
.map(d -> 1)
.reduce(0, (a, b) -> a + b);
long count = menu.stream().count();
Compared with the gradual iterative summation previously written, the advantage of using reduce is that the iterations here are abstracted away by internal iterations, which allows internal implementations to choose to execute reduce operations in parallel. The iterative summation example updates the shared variable sum, which is not so easy to parallelize. If you join the synchronization,It is possible to find that thread competition offsets the performance improvement that parallelism should bring! The parallelization of this kind of calculation requires another method: divide the input into blocks, sum the blocks, and finally merge them. But in this case, the code looks completely different.
When using a stream to sum all the elements in parallel, the code hardly needs to be modified: stream() is replaced by parallelStream().
int sum = numbers.parallelStream().reduce(0, Integer::sum);
Operations such as map or filter will get every element from the input stream and get 0 or 1 result in the output stream. These operations are generallyno status: They have no internal state (assuming that the Lambda or method reference provided by the user has no internal mutable state). But operations such as reduce, sum, and max require internal state to accumulate results. In the above case, the internal state is very small. In our case it is an int or double. No matter how many elements in the stream need to be processed, the internal state is bounded.
On the contrary, operations such as sort or distinct are similar to filter and map at the beginning-both accept a stream and generate a stream (intermediate operation), but there is a key difference. You need to know the previous history when sorting and removing duplicates from the stream. For example, sorting requires all elements to be put into the buffer before adding an item to the output stream. The storage requirement for this operation isUnboundedof. If the stream is relatively large or infinite, there may be problems (what does it do if you reverse the stream of prime numbers? It should return the largest prime number, but mathematics tells us that it does not exist). We call these operationsStatefuloperating.
| operating | Types of | Return type | Type/Functional Interface Used | Function descriptor |
|---|---|---|---|---|
| filter | intermediate | Stream<T> | Predicate<T> | T->boolean |
| distinct | intermediate (Stateful-Unbounded) |
Stream<T> | - | - |
| skip | intermediate (Stateful-Bounded) |
Stream<T> | long | - |
| limit | intermediate (Stateful-Bounded) |
Stream<T> | long | - |
| map | intermediate | Stream<R> | Function<T,R> | T->R |
| flatMap | intermediate | Stream<R> | Function<T,Stream<R>> | T->Stream<R> |
| sorted | intermediate (Stateful-Unbounded) |
Stream<T> | Comparator<T> | (T,T)->int |
| anyMatch | terminal | boolean | Predicate<T> | T->boolean |
| noneMatch | terminal | boolean | Predicate<T> | T->boolean |
| allMatch | terminal | boolean | Predicate<T> | T->boolean |
| findAny | terminal | Optional<T> | - | - |
| findFirst | terminal | Optional<T> | - | - |
| forEach | terminal | void | Consumer<T> | T->void |
| collect | terminal | R | Collector<T,A,R> | - |
| reduce | terminal (Stateful-Bounded) |
Optional<T> | BinaryOperator<T> | (T,T)->T |
| count | terminal | long | - | - |
Trader executing the transaction
1. Find all transactions in 2011 and sort them by transaction amount (lowest to high)
List<Transaction> tr2011 = transactions.stream()
.filter(transaction -> transaction.getYear() == 2011)
.sorted(comparing(Transaction::getValue))
.collect(toList());
2. Which different cities have traders worked in?
List<String> cities = transactions.stream()
.map(transaction -> transaction.getTrader().getCity())
.distinct()
.collect(toList());
//or
Set<String> cities =
transactions.stream()
.map(transaction -> transaction.getTrader().getCity())
.collect(toSet());
3. Find all traders from Cambridge and sort them by name
List<Trader> traders = transactions.stream()
.map(Transaction::getTrader)
.filter(trader -> trader.getCity().equals("Cambridge"))
.distinct()
.sorted(comparing(Trader::getName))
.collect(toList());
4. Return the name strings of all traders, sorted alphabetically
String traderStr = transactions.stream()
.map(transaction -> transaction.getTrader().getName())
.distinct()
.sorted()
.reduce("", (n1, n2) -> n1 + n2);
String traderStr =
transactions.stream()
.map(transaction -> transaction.getTrader().getName())
.distinct()
.sorted()
.collect(joining());
5. Are there any traders working in Milan?
boolean milanBased = transactions.stream()
.anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan"));
System.out.println(milanBased);
6. Print all transactions of traders living in Cambridge
transactions.stream()
.filter(t -> "Cambridge".equals(t.getTrader().getCity()))
.map(Transaction::getValue)
.forEach(System.out::println);
7. What is the highest transaction amount among all transactions?
Optional<Integer> highestValue =
transactions.stream()
.map(Transaction::getValue)
.reduce(Integer::max);
8. Find the smallest transaction
Optional<Transaction> smallestTransaction =
transactions.stream()
.reduce((t1, t2) ->
t1.getValue() < t2.getValue() ? t1 : t2);
Optional<Transaction> smallestTransaction =
transactions.stream()
.min(comparing(Transaction::getValue));
You can use the reduce method to calculate the sum of the elements in the stream.
For example, you can calculate the calories of the menu like this:
int calories = menu.stream()
.map(Dish::getCalories)
.reduce(0, Integer::sum);
The problem with this code is that it has an implicit boxing cost. Each Integer must be unboxed into a primitive type, and then summed. Wouldn't it be better if the sum method could be called directly like the following?
int calories = menu.stream()
.map(Dish::getCalories)
.sum();//Cannot compile here, the Streams interface does not define the sum method
But this is impossible. The problem is that the map method generates a Stream. Although the elements in the stream are of type Integer, the Streams interface does not define the sum method.
Why not? For example, you only have a Stream like menu, and adding up various dishes is meaningless.
But don't worry, the Stream API also provides primitive type stream specialization, specifically supporting methods for processing numeric streams.
Java 8 introduced three primitive type specialization stream interfaces to solve this problem: IntStream, DoubleStream and LongStream, respectively specializing the elements in the stream into int, long and double, thus avoiding the implicit boxing cost. Each interface brings new methods for commonly used numerical reductions, such as sum of numerical streams to find the max of the largest element. In addition, there are methods to convert them back to object streams when necessary.
The thing to remember is, The reason for these specializations is not the complexity of the stream, but the complexity caused by boxing-that is, the efficiency difference between int and Integer.
Common methods for converting streams to specialized versions are mapToInt, mapToDouble, and mapToLong.
int calories = menu.stream()
.mapToInt(Dish::getCalories)//Return an IntStream, not Stream<Integer>
.sum();
Please note that if the stream is empty, sum returns 0 by default. IntStream also supports other convenient methods, such as max, min, average, etc.
Similarly, once you have a numerical stream, you may want to convert it back to a non-specialized stream.
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();
If you want to calculate the largest element in the IntStream, you have to change the way, because 0 is the wrong result. How to distinguish a stream with no elements from a stream with a maximum value of 0?
Optional can be parameterized with reference types such as Integer and String. For the three primitive stream specializations, there is also an Optional primitive type specialization version: OptionalInt, OptionalDouble, and OptionalLong.
For example, to find the largest element in the IntStream, you can call the max method, which will return an OptionalInt:
OptionalInt maxCalories = menu.stream()
.mapToInt(Dish::getCalories)
.max();
Now, if there is no maximum value, you can explicitly process OptionalInt to define a default value:
int max = maxCalories.orElse(1);
Java 8 introduced two static methods that can be used for IntStream and LongStream to help generate this range: range and rangeClosed. In both methods, the first parameter accepts the start value, and the second parameter accepts the end value. But range does not contain the end value, and rangeClosed contains the end value.
IntStream evenNumbers = IntStream.rangeClosed(1, 100)//Range [1,100], IntStream.range(1, 100) range is [1,100)
.filter(n -> n % 2 == 0);
System.out.println(evenNumbers.count());
a^2+b^2=c^2
| a | b | c |
|---|---|---|
| 3 | 4 | 5 |
| 5 | 12 | 13 |
| 6 | 8 | 10 |
| 7 | 24 | 25 |
new int[]{3, 4, 5};//To indicate the number of Pythagorean shares (3, 4, 5)
How do you know whether it can form a set of Pythagorean shares? You need to test whether the square root of a * a + b * b is an integer, which means it has no decimal part-it can be represented by expr% 1 in Java. If it is not an integer, then c is not an integer.
filter(b -> Math.sqrt(a*a + b*b) % 1 == 0);
stream.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
.map(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)});
IntStream.rangeClosed(1, 100)
.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
.mapToObj(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)});
//Conforms to form a right triangle
Stream<int[]> pythagoreanTriples = IntStream.rangeClosed(1, 100)
.boxed()flatMap uses generics, so basic types cannot be used
.flatMap(a ->
IntStream.rangeClosed(a, 100)
.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
.mapToObj(b ->new int[]{a, b, (int)Math.sqrt(a * a + b * b)})
);
pythagoreanTriples.limit(5)
.forEach(t ->System.out.println(t[0] + ", " + t[1] + ", " + t[2]));
The current solution is not optimal, because you require two square roots. One possible way to make the code more compact is to first generate all the ternary numbers (a*a, b*b, a*a+b*b), and then filter those that meet the conditions
Stream<double[]> pythagoreanTriples2 =
IntStream.rangeClosed(1, 100).boxed()
.flatMap(a ->IntStream.rangeClosed(a, 100)
.mapToObj(b -> new double[]{a, b, Math.sqrt(a*a + b*b)})
.filter(t -> t[2] % 1 == 0));
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);
//You can use empty to get an empty stream, as shown below:
Stream<String> emptyStream = Stream.empty();
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();
long uniqueWords = 0;
//The stream will automatically close
try(Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
.distinct()
.count();
}
catch(IOException e){
}
The Stream API provides two static methods to generate streams from functions: Stream.iterate and Stream.generate.
These two operations can create so-called infinite streams: unlike streams created from a fixed collection, there are no fixed-size streams. The stream generated by iterate and generate will use the given function to create values ββon demand, so it can be calculated endlessly!
In general, limit(n) should be used to limit this stream to avoid printing infinitely many values.
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
The iterate method accepts an initial value (here 0), and a Lambda (UnaryOperator<T> type) that is applied to each new value generated in turn.
//Sequence (0, 1), (1, 1), (1, 2), (2, 3), (3, 5), (5, 8), (8, 13), (13, 21) ...
Stream.iterate(new int[]{0, 1},t -> new int[]{t[1], t[0]+t[1]})
.limit(20)
.forEach(t -> System.out.println("(" + t[0] + "," + t[1] +")"));
//Just want to print the normal Fibonacci sequence
Stream.iterate(new int[]{0, 1},t -> new int[]{t[1],t[0] + t[1]})
.limit(10)
.map(t -> t[0])
.forEach(System.out::println);
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
The source of supply we use (a method reference to Math.random) isStateless: It will not record any value anywhere for future calculations. But the source of supplyNot necessarily statelessγ
You can create a supply source that stores state, it can modify the state, and use it when generating the next value for the flow.
For example, the following will show how to use generate to create a Fibonacci sequence, so you can compare it with the iterate method.
But the important point is that inIt is not safe to use a stateful supply source in parallel code. Therefore, the following code is just for completeness and should beTry to avoid using
IntStream.generate(() -> 1)
.limit(5)
.forEach(System.out::println);
IntStream twos = IntStream.generate(new IntSupplier(){
public int getAsInt(){
return 2;
}
});
IntSupplier fib = new IntSupplier(){
private int previous = 0;
private int current = 1;
public int getAsInt(){
int oldPrevious = this.previous;
int nextValue = this.previous + this.current;
this.previous = this.current;
this.current = nextValue;
return oldPrevious;
}
};
IntStream.generate(fib).limit(10).forEach(System.out::println);
The preceding code creates an instance of IntSupplier. This object hasVariableStatus: It records the previous Fibonacci term and the current Fibonacci term in two instance variables. getAsInt will change the state of the object when it is called, thereby generating a new value each time it is called.
In contrast, the iterate method is pureChangeless: It does not modify the existing state, but it willCreate a new tupleγ
Please note that because you are dealing with an infinite stream, you must use the limit operation to explicitly limit its size; otherwise, the terminal operation (here, forEach) will be calculated forever.
Similarly, you cannot sort or reduce an infinite stream, because all elements need to be processed, and this will never be done!
Bean's reference statement First of all, this series of blog refers to the oil pipeSpring Expression LanguageTeaching videoReferencing BeansAnd write. start This episode is a simple look at how to use...
table of Contents 1. Function 1.1 Functional interface 1.2 Lambda expression-anonymous function 1.2.1 Description 1.2.2 Lambda expression has three parts 1.2.3 Predicate 1.2.4 Use cases 1.2.5 Commonly...
lambda composition Example Commonly used functional interface Examples of Lambdas and functional interfaces flow Drawing 2. Intermediate operation 3. Construction stream Create flow by value Stream.of...
1. Quotes Before understanding Stream, let's take a look at a demand: Known the employee information of a company to obtain employees who are older than 30 years old in the current company. First, we ...
Right click on the desktop_Send to _Mail recipient appears "No configuration file created. To create a new configuration file, please use the "Mail" icon in the "Control Panel"...
Nginx can not only do web servers, do reverse proxy, load balancing, but also a current limiting system. Here we have an example for Nginx, introduce how to configure a current limiting system. The cu...
This problem is a bit simpler. The port of Tomcat is occupied. I used a hot deployment plugin JReble in IDEA. After updating IDEA, I found that the port is occupied. Maybe my computer has not been res...
4.1 What is the flow? The stream is a new member of the Java API, which allows you to process data sets in a declarative manner (expressed by query statements instead of temporarily writing an impleme...
30 | How to reset the consumer group displacement? We know that Kafka and traditional message engines are very different in design. One of the more significant differences is that Kafka consumers can ...