Stream stream + immutable collection

Immutable collection

  • Create an immutable collection: data cannot be modified and defensively copied to the immutable collection; safe when called by an untrusted library.
  • There are static methods of in the List Set Map interface->Get an immutable collection–>Cannot add, delete, modify (read-only)
List<String> list = List.of("","","");
//remove add set xxx is not allowed
Set<String> set = Set.of("","","");//No index
//Get an immutable set collection. Parameters ensure uniqueness.
Map<String,String> map = Map.of("key","value");
//Keys cannot be repeated. Parameters have an upper limit (10)
//When there are 10 more parameters ->ofEntries jdk10->copyOf
------------Fang Yi---------------
HashMap<String,String> map = new HashMap<>();
    map.put("123","123");//put more than ten
    //Get all key value objects Entry objects
    Set<Map.Entry<String,String>>entries = map.entrySet();
    //Convert entries into an array. The type is entry object.
    //toArray method compares the length of the collection with the length of the array
    //Set length > Array length Create a new array based on the actual number of collection data, otherwise <= use it directly and the excess is nul
    Map.Entry[] arr = entires.toArray(new Map.Entry[0]);
    Map map1 = Map.ofEntries(arr);
    //Immutable creation completed
---------------Fang 2------------------
    //simplify
    Map<Object,Object> map1 = Map.ofEntries(map.entrySet().toArray(new Map.Entry[0]));
---------------Fang San------------------
    //jdk10
    Map<String,String> map1 = mapMap.copyOf(map);

Stream

Introduction

Combined with Lambda expressions to simplify collection and array operations

characteristic:

  1. Stream itself does not store elements.

  2. Stream does not change the source object. Instead, they return a new Stream holding the result.

  3. Stream operations are performed lazily. This means they wait until the results are needed. That is, once the termination operation is performed, the intermediate operation chain is executed and the results are generated.

  4. Once a Stream performs a termination operation, it cannot call other intermediate operations or termination operations.

Streaming

eg:

For example, you want to filter out all even numbers from a collection containing integers and encapsulate them into a new List to return

List<Integer> evens = new ArrayList<>();
for (final Integer num : nums) {
    if (num % 2 == 0) {
        evens.add(num);
    }
}

Through Java8’s streaming processing, the code is simplified to:

List<Integer> evens = nums.stream().filter(num -> num % 2 == 0).collect(Collectors.toList());
------eg2--------
    ArrayList<String> list = new ArrayList<>();
        list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3 ).forEach(name -> System.out.println(name ));

Explanation: The stream() operation converts the collection into a stream. filter() performs our custom filtering process. Here, all even numbers are filtered out through lambda expressions. Finally We use collect() to encapsulate the result, and use Collectors.toList() to specify its encapsulation and return it as a List collection.

A stream processing can be divided into three parts: conversion into streams, intermediate operations, and terminal operations

Take collections as an example. For a streaming operation, we first need to call the stream() function to convert it into a stream, and then call the corresponding intermediate operation to achieve what we need. Collection operations, such as filtering, conversion, etc., and finally encapsulates the previous results through Terminal operations and returns the form we need.

step:

  1. Get stream exile data

    td>

    Getting method Method name Description
    Single column collection default Stream stream() Default method in Collection
    Dual column collection None (turn keySet or entrySet into a single column first) Cannot use stream directly
    Array public static Stream stream (T[] array) Static method in Arrays tool class
    A bunch of scattered data public static Stream of (T…values) Static methods in the Stream interface

    Single column collection:

     ArrayList<String> list = new ArrayList<>();
            Collections.addAll(list,"a","b","c","d","e","f");
            //Get a pipeline and put the collection data on the pipeline
            /*Stream<String> stream = list.stream();
            stream.forEach(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    // s represents each data on the pipeline at a time
                    System.out.println(s);
                }
            });*/
            list.stream().forEach(s-> System.out.println(s));

    Two-column collection:

     //Create a two-column collection
            HashMap<String, Integer> hm = new HashMap<>();
            hm.put("aaa",1111);
            hm.put("bbb",2222);
            hm.put("ccc",3333);
            hm.put("mmm",4444);
            //Get stream stream
            //Print all keys
            hm.keySet().stream().forEach(s-> System.out.println(s));
            //Print all key-value pairs
            hm.entrySet().stream().forEach(s-> System.out.println(s));

    Array:

     //Create array
            int[] arr = {1,2,3,4,5,6,7};
            Arrays.stream(arr).forEach(s-> System.out.println(s));

    Scattered data:

    Stream.of(1,2,3,4).forEach(s-> System.out.println(s));

    be careful:

    Stream.of can be used for reference data type arrays but not for basic data types.

  2. Leverage in-stream API operations

    Filter Transform -> Intermediate method (you can continue to call other methods later)

    Statistics Print -> Termination method (no other calls can be made later)

Intermediate operations

Filtering and slicing

filter ->Filter

limit -> get the first few elements

skip -> skip the first few elements

distinct -> element deduplication dependency (hashCode and equals methods)

concat -> merge the two streams a and b into one stream (parent class)

filter
 ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123","b123","c222","d11","e22","f11");
         //filter
// list.stream().filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// //The return value is true, leave false and discard it
// return s.startsWith("a");
// }
// }).forEach(s-> System.out.println(s));
        list.stream().filter(s->s.startsWith("a")).forEach(s-> System.out.println(s));
limit/skip
 //Get the first three
        list.stream().limit(3).forEach(s-> System.out.println(s));
        //Skip the first 4
        list.stream().skip(4).forEach(s-> System.out.println(s));
distinct
list.stream().distinct().forEach(s-> System.out.println(s));
concat
Stream.concat(list.stream(),list2.stream()).forEach(s-> System.out.println(s));
Mapping

map -> Convert the data type in the stream. Receive a function as a parameter. The function will be applied to each element and map it into a new element.

flatMap -> receives a function as a parameter, replaces each value in the stream with another stream, and then connects all streams into one stream

mapToDouble -> generates a new DoubleStream

mapToInt -> generate a new IntStream

mapToLong -> generates a new LongStream.

Note: Does not affect the original data

map
 ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-15","b123-56","a123-22","d11-25","e22-525","f11- 59");
        //Only get the inner -post data String ->int
        // The first type: the original type of the data in the stream. The second type: the type to be converted.
        //apply formal parameter s: data in the stream
        //Return value converted data
        //After the map method is executed, the data on the stream becomes an integer.
// list.stream().map(new Function<String, Integer>() {
// @Override
// public Integer apply(String s) {
// String[] arr = s.split("-");
// String ageString = arr[1];
// int age = Integer.parseInt(ageString);
// return age;
// }
// }).forEach(s-> System.out.println(s));
        list.stream().map(s-> Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));
?
?
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-male-15","b123-male-56","a123-female-22","d11-female-25","e22- Female-525","f11-Female-59");
        //Get names whose length is greater than 3
        //Get the name first
        List<String> collect = list.stream().map(e -> e.split("-")[0]).filter(s -> s.length() > 3).collect(Collectors. toList());
        List<String> collect = list.stream().map(Employee::getName).filter(s -> s.length() > 3).collect(Collectors.toList());
//Suppose you want to filter out the names of all students majoring in computer science. Based on the filter filter, you can map the student entities into student name strings through map.
List<String> names = students.stream()
                            .filter(student -> "Computer Science".equals(student.getMajor()))
                            .map(Student::getName).collect(Collectors.toList());
//Want to calculate the sum of the ages of all students majoring in computer science
int totalAge = students.stream()
                    .filter(student -> "Computer Science".equals(student.getMajor()))
                    .mapToInt(Student::getAge).sum();
flatMap

flatMap converts each value in a stream into streams, and then flattens these streams into a stream within a stream.

//Output all non-repeating characters that make up this array
String[] strs = {"java8", "is", "easy", "to", "use"};
List<String[]> distinctStrs = Arrays.stream(strs)
                                .map(str -> str.split("")) // Map to Stream<String[]>
                                .distinct()
                                .collect(Collectors.toList());
    /*
            [j, a, v, a, 8]
            [i, s]
            [e, a, s, y]
            [t,o]
            [u, s, e]
    */
List<String> distinctStrs = Arrays.stream(strs)
                                .map(str -> str.split("")) // Map to Stream<String[]>
                                .flatMap(Arrays::stream) // Flatten to Stream<String>
                                .distinct()
                                .collect(Collectors.toList());
//books->list
Book book = writers.stream().flatMap(writer -> writer.getBooks().stream())
                .max(new BookComparator()).get();

merge, cross, difference

 List<String> A = new ArrayList<>();
        Collections.addAll(A,"1","2","3","4");
        List<String> B = new ArrayList<>();
        Collections.addAll(A,"3","4","5","6","7");
?
        //Union
        A.addAll(B);
        List<String> AuB = A.stream().distinct().collect(Collectors.toList());
        System.out.println("Union:" + AuB);
        //[1, 2, 3, 4, 5, 6, 7]
?
        //Intersection B::contains = s -> B.contains(s) Higher versions of IDEA will prompt for conversion
        List<String> AnB = A.stream().filter(B::contains).collect(Collectors.toList());
        System.out.println("Intersection:" + AnB);
        //[3, 4]
?
        //Difference set
        List<String> difference = A.stream().filter(s -> !B.contains(s)).collect(Collectors.toList());
        System.out.println("The complement of B in A:" + difference);
Sort

sorted() -> natural sorting ascending order

sorted(Comparator com) -> Sort by comparator order

//Ascending order
//1.Natural sorting
list = list.stream().sorted().collect(Collectors.toList());
//2.Comparator sorts according to age
list = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
?
//descending order
//1. Natural sorting uses the reverseOrder() method provided by Comparator
list = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
//2.Comparator sorts according to age
list = list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());
?
?
//Multi-field sorting
//First sort by name in ascending order, if the names are the same then order by age in ascending order
list = list.stream().sorted(Comparator.comparing(Student::getName).thenComparing(Student::getAge)).collect(Collectors.toList());
Match

match is used for matching operations, and its return value is a boolean type. Through match, you can easily verify whether a certain type of element exists in a list.

// Verify whether there is a string starting with a in the list. If the first one is matched, true will be returned.
boolean anyStartsWithA =
    stringCollection
        .stream()
        .anyMatch((s) -> s.startsWith("a"));
?
System.out.println(anyStartsWithA); // true
?
// Verify whether the strings in the list all start with a
boolean allStartsWithA =
    stringCollection
        .stream()
        .allMatch((s) -> s.startsWith("a"));
?
System.out.println(allStartsWithA); // false
?
// Verify whether the strings in the list do not start with z,
boolean noneStartsWithZ =
    stringCollection
        .stream()
        .noneMatch((s) -> s.startsWith("z"));
?
System.out.println(noneStartsWithZ); // true

Termination method

forEach -> traverse

(long)count -> statistics

Reduce -> Protocol

toArray() -> Collect data from the stream and put it into an array

collect (Collector collector) -> collect data in the stream and put it into the collection

Count

count is a terminal operation that can count the total number of elements in the stream stream. The return value is of type long

// First filter the strings starting with b in the list, and then count the number
long startsWithB =
    stringCollection
        .stream()
        .filter((s) -> s.startsWith("b"))
        .count();

System.out.println(startsWithB); // 3
Reduce

Reduce Chinese translation is: reduce, shrink. By taking the parameter Function, list can be reduced to a value. Its return type is of type Optional.

Optional<String> reduced =
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);

reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
BigDecimal subjectTotalIncomeBudget = entry.getValue().stream()
                           .map(PmJtProjectSaleContractPrice::getTotalAmountExcludeTax).reduce(BigDecimal.ZERO,BigDecimal::add);
//BigDecimal.ZERO: This represents the initial value. When performing a reduce operation, the value used for the first time is the initial value. Here, BigDecimal.ZERO means the initial value is 0.
//BigDecimal::add: This represents a BinaryOperator, which represents how to combine two elements. Here, the add method of the BigDecimal class is used, which means adding two BigDecimals.
collect
 //toArray()
 ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-15","b123-56","a123-22","d11-25","e22-525","f11- 59");
        System.out.println(Arrays.toString(list.stream().toArray()));
// String[] arr = list.stream().toArray(new IntFunction<String[]>() {
// @Override
// public String[] apply(int value) {
// return new String[value];
// }
// });
        System.out.println(Arrays.toString(list.stream().toArray(value->new String[value])));

collect (Collector collector) -> Collect data in the stream and put it into a collection (List Set Map)

 ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-male-15","b123-male-56","a123-female-22","d11-female-25","e22- Female-525","f11-Female-59");
        //Collect men
        list.stream()
                .filter(s -> "male".equals(s.split("-")[1]))
                //.collect(Collectors.toList()); Collect into List collection without deduplication
                //.collect(Collectors.toSet()); Collect into Set and remove duplicates
            
            
-------------------------------------------------- ----------
                 ArrayList<String> list = new ArrayList<>();
                 Collections.addAll(list,"a123-male-15","b123-male-56","a123-female-22","d11-female-25","e22- Female-525","f11-Female-59");
                //Collect key values into map
                //Note: keys cannot be repeated
                //Collect men Key: Name Value: Age
                /*list.stream()
                .filter(s -> "male".equals(s.split("-")[1]))
                 *//* toMap: Key rules Value rules
                        Key rules: Function generic (type of each data in the stream, type of key in the map collection) -> Generate key Return key
                        Value rules: Function generic (type of each data in the stream, type of value in the map collection) -> Generate value Return value
                 *//*
                .collect(Collectors.toMap(new Function<String, String>() {
                                              @Override
                                              public String apply(String s) {
                                                  //generate key
                                                  return s.split("-")[0];
                                              }
                                          },
                        new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                return Integer.parseInt(s.split("-")[2]);
                            }
                        }));*/

list.stream()
                .filter(s -> "male".equals(s.split("-")[1]))
                .collect(Collectors.toMap(s->s.split("-")[0],s->Integer.parseInt(s.split("-")[2])));</ pre>
<h3>Example</h3>
<pre>//List<List<FieldAttributeDto>> tableValue is sorted (in ascending order) according to the value (string) of FieldName="records_projectStage" in FieldAttributeDto
//flatMap error occurs during stages 1-11
List<FieldAttributeDto> flattenedSortedTableValue = tableValue.stream()
.flatMap(List::stream) // Flatten a nested list into a stream of single elements
.filter(dto -> "records_projectStage".equals(dto.getFieldName())) // Filter out FieldAttributeDto that meets the conditions
.sorted(Comparator.comparing(FieldAttributeDto::getLabelValue)) // Sort the qualified FieldAttributeDto
.collect(Collectors.toList()); // The collection result is a list
//Solve the limitation "stage" begins
List<FieldAttributeDto> flattenedSortedTableValue = tableValue.stream()
.flatMap(List::stream) // Flatten a nested list into a stream of single elements
.filter(dto -> "records_projectStage".equals(dto.getFieldName())) // Filter out FieldAttributeDto that meets the conditions
.sorted(Comparator.comparing(this::parseStage))
.collect(Collectors.toList()); // The collection result is a list
// Custom method to parse the stage string into an integer
private int parseStage(FieldAttributeDto dto) {
String stage = dto.getLabelValue();
if (stage.startsWith("stage")) {
return Integer.parseInt(stage.substring(2));
}
return 0; //Default value
}

 List<List<FieldAttributeDto>> sortedTableValue = tableValue.stream()
                .map(list -> list.stream()
                        .filter(dto -> dto.getFieldName().equals("records_projectStage"))
                        .findFirst()
                        .orElse(null))
                .filter(dto -> dto != null)
                .sorted(Comparator.comparing(FieldAttributeDto::getValue))
                .map(dto -> tableValue.stream()
                        .filter(list -> list.contains(dto))
                        .findFirst()
                        .orElse(null))
                .filter(list -> list != null)
                .collect(Collectors.toList());