Catalog
- Brief Introduction to Stream
- Why use Stream
- Instance data source
- Filter
- Map
- FlatMap
- Reduce
- Collect
- Optional
- Concurrent
- debugging
Brief Introduction to Stream
- Java 8 introduced a new Stream API. Stream here is different from I/O streams. It is more like a collection class with Iterable, but its behavior and collection class are different.
- stream is an enhancement of the functions of collection objects. It focuses on a variety of very convenient and efficient aggregation operations on collection objects, or large quantities of data operations.
- Stream implicitly traverses the elements it contains, such as "filtering out strings longer than 10" and "capturing the initial letters of each string" to make the corresponding data conversion.
Why use Stream
- The benefits of functional programming are particularly evident. This code expresses the intention of business logic more than its implementation mechanism. Readable code is also easy to maintain, more reliable, and less error-prone.
- High-end
Instance data source
public class Data {
private static List<PersonModel> list = null;
static {
PersonModel wu = new PersonModel("wu qi", 18, "male");
PersonModel zhang = new PersonModel("zhang san", 19, "male");
PersonModel wang = new PersonModel("wang si", 20, "female");
PersonModel zhao = new PersonModel("zhao wu", 20, "male");
PersonModel chen = new PersonModel("chen liu", 21, "male");
list = Arrays.asList(wu, zhang, wang, zhao, chen);
}
public static List<PersonModel> getData() {
return list;
}
}
Filter
- Use when traversing data and checking elements.
- The filter accepts a function as a parameter, which is expressed in Lambda expression.
/**
* Filter all males
*/
public static void fiterSex(){
List<PersonModel> data = Data.getData();
//old
List<PersonModel> temp=new ArrayList<>();
for (PersonModel person:data) {
if ("male".equals(person.getSex())){
temp.add(person);
}
}
System.out.println(temp);
//new
List<PersonModel> collect = data
.stream()
.filter(person -> "male".equals(person.getSex()))
.collect(toList());
System.out.println(collect);
}
/**
* Filter all males and less than 20 years old
*/
public static void fiterSexAndAge(){
List<PersonModel> data = Data.getData();
//old
List<PersonModel> temp=new ArrayList<>();
for (PersonModel person:data) {
if ("male".equals(person.getSex())&&person.getAge()<20){
temp.add(person);
}
}
//new 1
List<PersonModel> collect = data
.stream()
.filter(person -> {
if ("male".equals(person.getSex())&&person.getAge()<20){
return true;
}
return false;
})
.collect(toList());
//new 2
List<PersonModel> collect1 = data
.stream()
.filter(person -> ("male".equals(person.getSex())&&person.getAge()<20))
.collect(toList());
}
Map
- map generates a one-to-one mapping, the function of for
- More commonly used
- And it's simple.
/**
* Take out all user names
*/
public static void getUserNameList(){
List<PersonModel> data = Data.getData();
//old
List<String> list=new ArrayList<>();
for (PersonModel persion:data) {
list.add(persion.getName());
}
System.out.println(list);
//new 1
List<String> collect = data.stream().map(person -> person.getName()).collect(toList());
System.out.println(collect);
//new 2
List<String> collect1 = data.stream().map(PersonModel::getName).collect(toList());
System.out.println(collect1);
//new 3
List<String> collect2 = data.stream().map(person -> {
System.out.println(person.getName());
return person.getName();
}).collect(toList());
}
FlatMap
-
As the name implies, it's similar to map, a deeper operation.
-
But there are differences.
-
map and flat return values are different
-
Each input element of Map is converted into another element according to the rules.
There are also scenarios where a one-to-many mapping relationship requires flatMap. -
Map one-to-one
-
Flatmap One-to-Many
-
The method declarations of map and flatMap are different
-
- <r> Stream<r> map(Function mapper);
-
- <r> Stream<r> flatMap(Function> mapper);
-
The difference between map and flatMap: Personally, I think that flatMap can process deeper data, enter into multiple lists, and the result can be returned to a list, while map is one-to-one, join multiple lists, and the result must be returned to multiple lists. Generally speaking, flatMap can manipulate the objects in the object if all the parameters are objects, while map can only manipulate the first layer.
public static void flatMapString() {
List<PersonModel> data = Data.getData();
//The return type is different
List<String> collect = data.stream()
.flatMap(person -> Arrays.stream(person.getName().split(" "))).collect(toList());
List<Stream<String>> collect1 = data.stream()
.map(person -> Arrays.stream(person.getName().split(" "))).collect(toList());
//Implementation with map
List<String> collect2 = data.stream()
.map(person -> person.getName().split(" "))
.flatMap(Arrays::stream).collect(toList());
//Another way
List<String> collect3 = data.stream()
.map(person -> person.getName().split(" "))
.flatMap(str -> Arrays.asList(str).stream()).collect(toList());
}
Reduce
- Feeling like recursion
- Number (String) Accumulation
- Personally, I haven't used it.
public static void reduceTest(){
//Cumulative, initialization value is 10
Integer reduce = Stream.of(1, 2, 3, 4)
.reduce(10, (count, item) ->{
System.out.println("count:"+count);
System.out.println("item:"+item);
return count + item;
} );
System.out.println(reduce);
Integer reduce1 = Stream.of(1, 2, 3, 4)
.reduce(0, (x, y) -> x + y);
System.out.println(reduce1);
String reduce2 = Stream.of("1", "2", "3")
.reduce("0", (x, y) -> (x + "," + y));
System.out.println(reduce2);
}
Collect
- collect generates lists, map s, and other commonly used data structures in streams
- toList()
- toSet()
- toMap()
- custom
/**
* toList
*/
public static void toListTest(){
List<PersonModel> data = Data.getData();
List<String> collect = data.stream()
.map(PersonModel::getName)
.collect(Collectors.toList());
}
/**
* toSet
*/
public static void toSetTest(){
List<PersonModel> data = Data.getData();
Set<String> collect = data.stream()
.map(PersonModel::getName)
.collect(Collectors.toSet());
}
/**
* toMap
*/
public static void toMapTest(){
List<PersonModel> data = Data.getData();
Map<String, Integer> collect = data.stream()
.collect(
Collectors.toMap(PersonModel::getName, PersonModel::getAge)
);
data.stream()
.collect(Collectors.toMap(per->per.getName(), value->{
return value+"1";
}));
}
/**
* Specified type
*/
public static void toTreeSetTest(){
List<PersonModel> data = Data.getData();
TreeSet<PersonModel> collect = data.stream()
.collect(Collectors.toCollection(TreeSet::new));
System.out.println(collect);
}
/**
* Grouping
*/
public static void toGroupTest(){
List<PersonModel> data = Data.getData();
Map<Boolean, List<PersonModel>> collect = data.stream()
.collect(Collectors.groupingBy(per -> "male".equals(per.getSex())));
System.out.println(collect);
}
/**
* Separate
*/
public static void toJoiningTest(){
List<PersonModel> data = Data.getData();
String collect = data.stream()
.map(personModel -> personModel.getName())
.collect(Collectors.joining(",", "{", "}"));
System.out.println(collect);
}
/**
* custom
*/
public static void reduce(){
List<String> collect = Stream.of("1", "2", "3").collect(
Collectors.reducing(new ArrayList<String>(), x -> Arrays.asList(x), (y, z) -> {
y.addAll(z);
return y;
}));
System.out.println(collect);
}
Optional
- Optional is a new data type designed for core class libraries to replace null values.
- People complain a lot about null values, even Tony Hoare, who invented the concept. He once said it was a "valuable mistake" of his own.
- It's very useful, not just in lambda, but everywhere.
- Optional.of(T), T is not null, otherwise initialization error is reported
- Optional. of Nullable (T), T is arbitrary and can be empty
- isPresent(), equivalent to! = null
- ifPresent(T), T can be a lambda expression, or other code, executed when it is not empty
public static void main(String[] args) {
PersonModel personModel=new PersonModel();
//If the object is empty, it will be typed out.-
Optional<Object> o = Optional.of(personModel);
System.out.println(o.isPresent()?o.get():"-");
//If the name is blank, type it out.-
Optional<String> name = Optional.ofNullable(personModel.getName());
System.out.println(name.isPresent()?name.get():"-");
//If it's not empty, type xxx
Optional.ofNullable("test").ifPresent(na->{
System.out.println(na+"ifPresent");
});
//If null, return the specified string
System.out.println(Optional.ofNullable(null).orElse("-"));
System.out.println(Optional.ofNullable("1").orElse("-"));
//If null, return the specified method, or code
System.out.println(Optional.ofNullable(null).orElseGet(()->{
return "hahah";
}));
System.out.println(Optional.ofNullable("1").orElseGet(()->{
return "hahah";
}));
//If null, an exception can be thrown
System.out.println(Optional.ofNullable("1").orElseThrow(()->{
throw new RuntimeException("ss");
}));
// Objects.requireNonNull(null,"is null");
//Multilevel Judgment Using Optional
EarthModel earthModel1 = new EarthModel();
//old
if (earthModel1!=null){
if (earthModel1.getTea()!=null){
//...
}
}
//new
Optional.ofNullable(earthModel1)
.map(EarthModel::getTea)
.map(TeaModel::getType)
.isPresent();
// Optional<EarthModel> earthModel = Optional.ofNullable(new EarthModel());
// Optional<List<PersonModel>> personModels = earthModel.map(EarthModel::getPersonModels);
// Optional<Stream<String>> stringStream = personModels.map(per -> per.stream().map(PersonModel::getName));
//Judging the list in the object
Optional.ofNullable(new EarthModel())
.map(EarthModel::getPersonModels)
.map(pers->pers
.stream()
.map(PersonModel::getName)
.collect(toList()))
.ifPresent(per-> System.out.println(per));
List<PersonModel> models=Data.getData();
Optional.ofNullable(models)
.map(per -> per
.stream()
.map(PersonModel::getName)
.collect(toList()))
.ifPresent(per-> System.out.println(per));
}
Concurrent
-
Replace stream with parallelStream or parallel
-
The size of the input stream is not the only factor that determines whether parallelization will lead to speed improvements. Performance is also affected by the way code is written and the number of cores.
-
Five factors that affect performance are data size, source data structure, value boxed, number of CPU cores available, and the time spent processing each element.
//Depending on the size of the number, there are different results.
private static int size=10000000;
public static void main(String[] args) {
System.out.println("-----------List-----------");
testList();
System.out.println("-----------Set-----------");
testSet();
}
/**
* Test list
*/
public static void testList(){
List<Integer> list = new ArrayList<>(size);
for (Integer i = 0; i < size; i++) {
list.add(new Integer(i));
}
List<Integer> temp1 = new ArrayList<>(size);
//Old
long start=System.currentTimeMillis();
for (Integer i: list) {
temp1.add(i);
}
System.out.println(+System.currentTimeMillis()-start);
//synchronization
long start1=System.currentTimeMillis();
list.stream().collect(Collectors.toList());
System.out.println(System.currentTimeMillis()-start1);
//Concurrent
long start2=System.currentTimeMillis();
list.parallelStream().collect(Collectors.toList());
System.out.println(System.currentTimeMillis()-start2);
}
/**
* Test set
*/
public static void testSet(){
List<Integer> list = new ArrayList<>(size);
for (Integer i = 0; i < size; i++) {
list.add(new Integer(i));
}
Set<Integer> temp1 = new HashSet<>(size);
//Old
long start=System.currentTimeMillis();
for (Integer i: list) {
temp1.add(i);
}
System.out.println(+System.currentTimeMillis()-start);
//synchronization
long start1=System.currentTimeMillis();
list.stream().collect(Collectors.toSet());
System.out.println(System.currentTimeMillis()-start1);
//Concurrent
long start2=System.currentTimeMillis();
list.parallelStream().collect(Collectors.toSet());
System.out.println(System.currentTimeMillis()-start2);
}
debugging
-
list.map.fiter.map.xx is a chain call, and the final call collect(xx) returns the result.
-
Inert Valuation and Early Valuation
-
It's easy to determine whether an operation is evaluated lazily or early: just look at its return value. If the return value is Stream, it is lazy evaluation; if the return value is another value or empty, it is early evaluation. The ideal way to use these operations is to form a chain of inert evaluation, and finally return the desired results with an early evaluation operation.
-
peek allows you to view each value while continuing to manipulate the flow
private static void peekTest() {
List<PersonModel> data = Data.getData();
//peek prints out each per traversed
data.stream().map(per->per.getName()).peek(p->{
System.out.println(p);
}).collect(toList());
}