In Java 8, thanks to the functional programming enabled by lambda, a new Stream concept was introduced to address the existing drawbacks of collections.
About the use of ::
: :
Is used to assign implementation methods to single-method interfaces- The implementation method to be used for appointment needs to be static or constructor
- The constructor is equivalent to the class that returns the constructor
The sample
Interface class to be assigned:
@FunctionalInterface
public interface ITest<T> {
T test(String s);
}
Copy the code
Classes used to implement interfaces:
public class SomeThingTest {
SomeThingTest(String s) {
System.out.println("Constructor implementation");
}
static String staticTest(String s) {
System.out.println("Static method implementation");
return "Static method"; }}Copy the code
Use:
public class MyMain {
public static void main(String[] args) {
ITest iTest = SomeThingTest::new;
ITest iTest2 = SomeThingTest::staticTest;
iTest.test("a");
iTest2.test("a"); }}Copy the code
About lambda expressions
Two usages:
Substitution function interface
- Instead of functional interfaces. A functional interface is simply an interface that contains only an abstract method, such as java.lang.Runnable and java.util.Com Parator in the Java standard library are typical functional interfaces. For functional interfaces, in addition to the standard Java methods for creating implementation objects, lambda expressions can be used to create implementation objects, which greatly simplifies code implementation. When lambda expressions are used, only formal parameters and method bodies need to be supplied. Since a functional interface has only one abstract method, the method body declared by a lambda expression must be the implementation of that unique abstract method, and the types of formal parameters can be automatically inferred from the method’s type declaration (that is, formal parameters can omit types).
First we need to know the properties that the implementation class needs to know to implement the single-method interface:
1. The method requires the value passed in
2. The value returned by the method
Both of these are expressed in lambda expressions:
(value passed by method) -> Value returned by method
Void (); void (); void ();
(value passed by method) -> Some operations within the method
Example:
@FunctionalInterface
public interface ITest<T> {
void test(String s);
}
Copy the code
ITest<String> stringITest = s -> System.out.println(s);
Copy the code
Works with collections
- Works with collections. Java 8 has two new packages for batch manipulation of collection data: java.util.function and java.util.stream. Arguably, lambda expressions and Streams are the biggest changes to the Java language since generics and annotations were added, and lambda expressions have greatly influenced the way we code when dealing with collections. This will be reflected below
about<? extends T>
and<? super T>
<? extends T>
Represents match genericsT
And its subclasses<? super T>
Represents match genericsT
And its parent class
Stream flow operation
Original collection – > Stream – > various operations (filtering, grouping, statistics) – > Terminal operations
The operation of a Stream is usually done by converting a collection to a Stream, and then by various operations such as filtering, filtering, grouping, and calculation. The final terminal operation is to convert it into the data we want. The form of this data is generally a set, and sometimes it will output count as required.
features
- No storage: A Stream is a data-source-based object that does not store data elements itself, but pipes the data source’s elements to an operation.
- Functional programming: Any modification to a Stream does not modify the data source behind it. For example, a filter operation on a Stream does not remove the filtered element, but rather produces a new Stream without the filtered element.
- Delayed execution: The operation of a Stream consists of zero or more intermediate operations and one terminal operation. The intermediate operations defined by a Stream are executed sequentially only if the end operation is performed, which is the delayed nature of the Stream.
- Consumability: A Stream can only be “consumed” once and is invalidated once traversed. Like a container iterator, to iterate again you must regenerate a new Stream.
Create a flow
Stream () : serial stream
ParallelStream () : Parallel streams
When creating a Stream, the default is to create a serial Stream. But you can use parallelStream() to create parallel streams or parallel() to replace serial streams with parallel streams. Parallel streams can also be converted to serial streams by sequential().
Filter (T-> Boolean)
The filter -> arrow is followed by a Boolean value, which can be used to write any filter criteria. In other words, it can be used to write anything that can be implemented in SQL
Personal test understanding, for reference only
When it comes to the use of this method, I have doubts. It is not difficult to simply understand its usage, but what is the sequence of its specific implementation? Enter the source code of filter, you can see:
Stream<T> filter(Predicate<? super T> predicate);
Copy the code
public interface Predicate<T> {
boolean test(T t);
}
Copy the code
It’s obvious that lambda expressions implement the test method in Predicate. The return value is Boolean, and the input parameter is T, but because <? Super T>, which means that all objects stored in the set are the parent class of T, so the parameter T entered here must be T or a subclass of T. However, after implementation, the filter method does not directly call the test method (for convenience, I did not use lambda expressions).
List<String> names = new ArrayList<>();
names.add("Zhang Sanfeng");
names.add("Zhang Dabao");
names.add("Zhang");
names.add(demarger);
names.add("Xiao feng.");
names.add("Li Dabao");
names.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
System.out.println(s);
return s.startsWith("Zhang"); }}); System.out.println("The end");
Copy the code
Results:
The test method was executed after the collect method was called
List<String> names = new ArrayList<>();
names.add("Zhang Sanfeng");
names.add("Zhang Dabao");
names.add("Zhang");
names.add(demarger);
names.add("Xiao feng.");
names.add("Li Dabao");
List<String> z = names.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
System.out.println(s);
return s.startsWith("Zhang");
}
}).collect(Collectors.toList());
System.out.println(z.toString());
System.out.println("The end");
Copy the code
Results:
Once the filter call is implemented, the test method in the Predicate is not executed directly. Instead, it waits for other methods in the stream that can call the object. @ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $
Distinct to heavy
This is similar to the DISTINCT keyword in SQL.
/ / distinct to heavy
List<User> distinctList = filterList.stream().distinct()
.collect(toList());
Copy the code
Sorted order
If the classes of the elements in the stream implement the Comparable interface, that is, they have their own sorting rules, then the sorted() method can be called directly to sort the elements. The no-parameter method requires that the elements in the stream implement the Comparable interface. Or you will quote Java. Lang. ClassCastException, have reference method needs to call sorted ((T, T) – > int) realize the Comparator interface
//sorted()
List<User> sortedList = distinctList.stream().sorted(Comparator.comparingInt(User::getAge))
.collect(toList());
Copy the code
Limit (long n) returns the element
Returns the first n elements
//limit returns the first n elements
List<User> limitList = sortedList.stream().limit(1)
.collect(toList());
Copy the code
Skip (long n) Skips elements
As opposed to limit, skip means to skip, to remove the first n elements.
Map (T -> R) type conversion
Map converts T data into R data:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Copy the code
Let’s say we have a set of students and we need to extract the ages of the students to analyze the age distribution curve of the students. Prior to Java 8 we would consume the age attribute in the element by creating a new collection and then iterating through the student collection. We have now fulfilled this requirement with a very simple streaming operation.
/ / pseudo code
List<Integer> ages=studentList.stream().map(Student::getAge).collect(Collectors.toList());
Copy the code
FlatMap (T -> Stream) indicates a Stream
Convert a class to a stream type:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Copy the code
The ages of all students under all classes were extracted to analyze the age distribution curve of students. If using map to get student stream:
List<List<Student>> studentGroup= gradeList.stream().map(Grade::getStudents).collect(Collectors.toList());
Copy the code
If you find that List<List> is nested, you also need to pull it out one by one and convert it to a stream using flatMap:
// flatMap extract List
map extract age
List<Integer> ages = grades.stream().flatMap(grade -> grade.getStudents().stream()).map(Student::getAge).collect(Collectors.toList());
Copy the code
AllMatch (T-> Boolean) Checks for all matches and returns Boolean
Check whether all the parameter behaviors are met. If these users are the list of Internet cafe users, it is necessary to check whether everyone is 18 years old or not.
boolean isAdult = list.stream().allMatch(user -> user.getAge() >= 18);
Copy the code
AnyMatch (T-> Boolean) Checks if there are any matching objects and returns Boolean
Check if any element satisfies a given condition, for example, if you want to know if there are girls in the class list.
//anyMatch(T -> Boolean) Specifies whether any element satisfies the given condition
boolean isGirl = list.stream().anyMatch(user -> user.getSex() == 1);
Copy the code
NoneMatch (T -> Boolean) Check whether all matches
Like checking to see if there are no users from Paris.
boolean isLSJ = list.stream().noneMatch(user -> user.getAddress().contains("Paris"));
Copy the code
FindFirst (): Finds the first element
Optional<User> fristUser = list.stream().findFirst();
Copy the code
FindAny (): Finds any element
Optional<User> anyUser = list.stream().findAny();
Copy the code
Here we see that findAny always returns the first element as well, so why make the distinction? Because the parallelStream parallelStream() does find any element.
Max and min Maximum and minimum values
Property property = properties.stream()
.max(Comparator.comparingInt(p -> p.priceLevel))
.get();
Copy the code
When looking for the largest or smallest element in a Stream, the first thing to consider is what sort indicator to use. Take finding the shop with the lowest price as an example, the sorting index is the price grade of the shop. To order the Stream object by price rank, pass it a Comparator object. Java8 provides a new static method, comparingInt, that makes it easy to implement a comparator. In the past, we needed to compare the value of an attribute between two objects. Now we only need to provide an access method.
Collect Result
Get the 2 stores closest to me:
List<Property> properties = properties.stream()
.sorted(Comparator.comparingInt(x -> x.distance))
.limit(2)
.collect(Collectors.toList());
Copy the code
Get the price level of each store:
Map<String, Integer> map = properties.stream()
.collect(Collectors.toMap(Property::getName, Property::getPriceLevel));
Copy the code
A list of stores in all price levels
Map<Integer, List<Property>> priceMap = properties.stream()
.collect(Collectors.groupingBy(Property::getPriceLevel));
Copy the code
Peek looks at elements of a step
The PEEK method can consume each element without adjusting the order or number of elements, and then generate a new stream if you want to see how each element flows through multiple stream operations
Stream.of("one"."two"."three"."four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: "+ e)) .collect(Collectors.toList()); Filtered value: three Mapped Value: three Mapped Value: four Mapped value: fourCopy the code
The forEach traversal
The forEach method works like a regular for loop, except that it supports multithreaded traversal, but not in order
List<String> names = new ArrayList<>();
Stream.of("one"."two"."three"."four")
.filter(e -> e.length() > 2)
.map(String::toUpperCase)
.forEach(s -> names.add(s));
System.out.println(names.toString());
Copy the code
ForEachOrdered traversal
The forEachOrdered method can be used to guarantee sequential traversal, such as if the stream was passed in from outside and parallel was called before that to enable multi-threaded execution
Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
// Iterate over the output elements sequentially
stringStream.forEachOrdered(System.out::println);
// Multithreading through the output element, the following line is the same as the result of the above execution
//stringStream.parallel().forEachOrdered(System.out::println);
Copy the code
Elements in a toArray stream are converted to arrays
ToArray has one parameterless method and one parameterless method, which is used to convert elements in the stream into an Object array
Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
Object[] objArray = stringStream.toArray();
Copy the code
The parameter method toArray(IntFunction
Generator) supports converting elements in A stream to an array of elements of A specified type
[]>
Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
String[] strArray = stringStream.toArray(String[]::new);
Copy the code
Count Indicates the number of elements in the statistics flow
The count method is used to count the total number of elements in the stream
Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
//count=6
long count = numStream.count();
Copy the code
Optional class
Conclusion:
Optional
Classes were created to solve problems common in programs with functional expressionsNullPointerException
(null pointer exception) Exception- When you’re pretty sure that an object can’t
null
Should be usedof()
Methods, otherwise, use whenever possibleofNullable()
methods- Use its map function expressions as much as possible to simplify if-else or null operations
basic
The java.util.Optional
class is a container object that encapsulates an Optional value. The Optional value can be null, and isPresent() returns true if the value exists.
Create an Optional object
The Optional class provides three methods to instantiate an Optional object: empty(), of(), and ofNullable(). These methods are static and can be called directly.
Its constructor is private and cannot be instantiated with new
private Optional(a) {
this.value = null;
}
Copy the code
empty()
Create an Optional object with no value:
Optional<String> optionalITest=Optional.empty();
Copy the code
If calling isPresent() on a variable returns false, calling get() throws a NullPointerException.
of()
Method creates an Optional object with a non-empty value:
String str = "Hello World";
Optional<String> notNullOpt = Optional.of(str);
Copy the code
If a null value is passed in, a NullPointerException is thrown
ofNullable()
The method receives a value that can be null:
Optional<String> nullableOpt = Optional.ofNullable(str);
Copy the code
If STR is null, the resulting nullableOpt object is an Optional object with no value.
map(T -> R)
Gets the set of values for the object in Optional
Optional<User> userOpt = Optional.ofNullable(user);
Optional<String> roleIdOpt = userOpt.map(User::getRoleId);
Copy the code
orElse(T other)
Get a value, return if there is one, and give a default value of the same type if there is none
Optional<String> optionalITest=Optional.ofNullable(null);
String s = optionalITest.orElse("");
Copy the code
orElseGet(Supplier<? extends T>)
: Works like the orElse() method, except for how the default values are generated.
This method accepts a Supplier
a functional interface parameter used to generate default values;
Optional<List<String>> optionalITest=Optional.ofNullable(null);
optionalITest.orElseGet(()->new ArrayList<>());
Copy the code
orElseThrow(Supplier<? extends X> exceptionSupplier)
Customizing the value method for throwing an exception.
An exception is also thrown when the value is null, but you can define your own exception
Optional<List<String>> optionalITest=Optional.ofNullable(null);
optionalITest.orElseThrow(() -> new IllegalArgumentException("Self-imposed exception"));
Copy the code
ifPresent(Consumer<? super T>)
Method receivesConsumer<? super T>
Generally used for printing to the background
Optional<String> strOpt = Optional.of("Hello World");
strOpt.ifPresent(System.out::println);
Copy the code
filter(Predicate<? super T> predicate)
filter
With the Stream filter (Predicate
predicate)
Stream returns a filtered stream object. Optional returns a filtered optional object
Optional<String> optionalITest=Optional.ofNullable("add");
Optional<String> a = optionalITest.filter(s -> s.startsWith("a"));
a.ifPresent(System.out::println);
Copy the code
orElse()
Use of methods
Simplify:
Original:
returnstr ! =null ? str : "Hello World"
Copy the code
After the improvement:
return strOpt.orElse("Hello World")
Copy the code
To simplify the if – else
Simplify:
Original:
User user = ...
if(user ! =null) {
String userName = user.getUserName();
if(userName ! =null) {
return userName.toUpperCase();
} else {
return null; }}else {
return null;
}
Copy the code
After the improvement:
User user = ...
Optional<User> userOpt = Optional.ofNullable(user);
return userOpt.map(User::getUserName)
.map(String::toUpperCase)
.orElse(null);
Copy the code
Reference article: juejin.cn/post/684490… Juejin. Cn/post / 684490… Juejin. Cn/post / 684490… Juejin. Cn/post / 684490… Juejin. Cn/post / 684490… Juejin. Cn/post / 684668…