Java8 Stream flow in simple terms: multi instance explanation

Posted by Eiolon on Fri, 14 Jan 2022 10:03:04 +0100

preface

Lambda expression is the basis of stream. Beginners are recommended to learn lambda expression - > first, Lambda expression of new features in Java 8

1, Get to know Stream

1.1.Stream overview

Stream is about algorithm and computation, which allows you to process data sets declaratively. It can be regarded as a high-level iterator to traverse data sets.
In addition, unlike iterators, streams can be processed in parallel. The data can be divided into multiple segments, each of which is executed in different threads, and finally the results are output together.
When we use a stream, there are usually three basic steps:
Obtain a data source → data conversion → execute the operation to obtain the desired result. Each time the original Stream object is converted, a new Stream object is returned (there can be multiple conversions), which allows the operation to be arranged like a chain and become a pipe, as shown in the following figure.

1.2. Three characteristics of flow

1. The stream does not store elements;
2. The stream will not modify its data source;
3. Flow execution has delay characteristics;

2, Creation of Sream flow

2.1. From an array or collection

1 .Arrays.stream(T array) or Stream.of()
2 .Collection.stream()
3 .Collection.parallelStream()

	@Test
	public void testArrayStream() {
        //1. Through arrays stream
        //1.1 basic types
        Integer[] arr = new Integer[]{1,2,3,4,5,6,7};

        //Via arrays stream
        Stream stream1 = Arrays.stream(arr);

        stream1.forEach(System.out::print);

        //2. Through stream of
        Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6,7);

        stream2.forEach(System.out::print);
    }

    @Test
    public void testCollectionStream(){
        List<Integer> strs = Arrays.asList(1,2,3,4,5,6,7);
        //Create normal flow
        Stream<Integer> stream  = strs.stream();
        //Create parallel stream
        Stream<Integer> stream1 = strs.parallelStream();
    }

2.2. Create infinite flow

	@Test
    public void test4(){

//      iteration
//      public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        //Traverse the first 10 even numbers
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::print);
        System.out.println();
        Stream.iterate(1,t->t+2).limit(5).forEach(System.out::print);
        System.out.println();
//      generate
//      public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
        List<Double> collect = Stream.generate(Math::random).limit(10).collect(Collectors.toList());

        Stream.generate(Math::random).limit(10).collect(Collectors.toList());

    }

2.3. Create regular flow

    @Test
    public void testUnlimitStream1(){
        Stream.iterate(0,x -> x+1).limit(10).forEach(System.out::println);
        Stream.iterate(0,x -> x).limit(10).forEach(System.out::println);
    }

2.4. of() through Stream

    @Test
    public void test3(){
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
    }

3, Detailed explanation of Stream operation and examples

Stream operations are divided into intermediate operations and terminal operations. Intermediate operations will return another stream and can continue to perform the next intermediate operation.
The terminal operation is the return result. The terminal operation triggers the flow to perform intermediate operations. The terminal operation ends the life of this flow.

3.1. Intermediate operation

3.1.1.filter

The filter filters the original Stream, and the qualified original number is left to generate a new Stream.

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// Gets the number of empty strings
long count = strings.stream().filter(string -> string.isEmpty()).count();

3.1.2.sorted

sorted sorts the elements in the original Stream and generates a new Stream after sorting.

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

3.1.3.distinct

Remove duplicate values

	@Test
    public void testDistinct() {
        Integer[] sixNums = {1, 2, 4, 3, 5, 5, 6};
        Integer[] distinctedNums = Stream.of(sixNums).distinct().toArray(Integer[]::new);
        System.out.println(distinctedNums);
    }

3.1.4.map

map converts an existing stream to a new stream. map takes a function as a parameter, which acts on each element in the stream and maps it to a new element.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// Get the corresponding square number
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());

3.1.5.flatMap

Flatten the flow, and each element in the flow is disassembled into a new flow. To use flatMap, you need to know the element type in the original stream in advance.

	@Test
    public void testFlapMap1() {
        String[] words = {"Hello", "World"};
        Stream.of(words)
                .map(word -> word.split(""))
                .flatMap(Arrays::stream).forEach(System.out::println);
    }

3.1.6.limit

Truncate the stream, which returns a stream no longer than the given length.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

3.2. Terminal operation

Traverse each element in the flow. When you need to optimize a multi-core system, you can parallelstream() Foreach(), but the order of the original elements cannot be guaranteed. In parallel, the behavior of serial operation will be changed.

	@Test
    public void testFlapMap1() {
        String[] words = {"Hello", "World"};
        Stream.of(words)
                .map(word -> word.split(""))
                .flatMap(Arrays::stream).forEach(System.out::println);
    }

3.2.1.findFirst, findAny

	//The functions of the two are similar. findAny does not require order, and the use of parallel flow has advantages.
	@Test
    public void testFindFirser() {
        String[] arr = new String[]{"yes", "YES", "no", "NO"};
        Arrays.stream(arr).filter(str -> Objects.equals(str, "yes")).findFirst().ifPresent(System.out::println);
    }

3.2.2.allMatch, noneMatch, anyMatch

Stream provides three match methods. allMatch requires that all elements in the stream meet the conditions before returning true. Any match returns true as long as one element meets the conditions. Nonematch, on the contrary, returns true if all elements do not meet the conditions

	@Test
    public void testMatch() {
        String[] arr = new String[]{"yes", "YES", "no", "NO"};
        System.out.println(Arrays.stream(arr).noneMatch( str  -> str.length() > 2));
        System.out.println(Arrays.stream(arr).anyMatch( str  -> str.length() > 2));
        System.out.println(Arrays.stream(arr).allMatch( str  -> str.length() > 2));
    }

3.2.3.reduce

The main function of this method is to combine the Stream elements. It provides a starting value (seed), and then combines it with the first, second and Nth elements of the previous Stream according to the operation rules (BinaryOperator). In this sense, string splicing, sum, min, max and average of numerical values are special reduce. For example, the sum of Stream is equivalent to

Integer sum = integers.reduce(0, (a, b) -> a+b); 

or

Integer sum = integers.reduce(0, Integer::sum);
	@Test
    public void testReduce() {
        // String connection, concat = "ABCD"
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        // Find the minimum value, minValue = -3.0
        double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
        // Sum, sumValue = 10, with starting value
        int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
        // Summation, sumValue = 10, no starting value
        sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
        // Filter, string connection, concat = "ace"
        concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
    }

3.2.4. Statistics (count/averaging)

Reference article here: Java8 Stream: 20 instances of 20000 words, playing with the filtering, reduction, grouping and aggregation of collections
Collectors provide a series of static methods for data statistics:

Count: count
Average value: averagingInt, averagingLong, averagingDouble
Max value: maxBy, minBy
Summation: summerint, summerlong, summerdouble
Statistics of all the above: summarizingInt, summarizingLong, summarizingDouble

public class StreamTest {
	public static void main(String[] args) {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 23, "male", "New York"));
		personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

		// Total
		Long count = personList.stream().collect(Collectors.counting());
		// Average wage
		Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
		// Seek maximum wage
		Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
		// Sum of wages
		Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
		// One time statistics of all information
		DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));

		System.out.println("Total number of employees:" + count);
		System.out.println("Average salary of employees:" + average);
		System.out.println("Total employee salary:" + sum);
		System.out.println("Employee salary statistics:" + collect);
	}
}

Operation results:

Total number of employees: 3
 Average salary of employees: 7900.0
 Total employee salary: 23700
 Employee salary statistics: DoubleSummaryStatistics{count=3, sum=23700.000000,min=7000.000000, average=7900.000000, max=8900.000000}

3.2.5.collect

This is widely used in actual projects, and the results are generated through collect. It can generate various forms, such as array, list, set and map. In addition, it can be grouped.

public class Student {
        private String name;
        private Integer score;
        //-----getters and setters-----

        Student(String name, Integer score) {
            this.name = name;
            this.score = score;
        }

        public String getName() {
            return name;
        }

        public Integer getScore() {
            return score;
        }

        public String toString() {
            return "name: " + name
                    + " score: " + score;
        }
    }

    Student[] students;

    @Before
    public void init(){
        students = new Student[10];
        for (int i = 0; i <= 3; i++){
            Student student = new Student("user", i);
            students[i] = student;
        }
        for (int i = 3; i <= 6; i++){
            Student student = new Student("user" + i, i + 1);
            students[i] = student;
        }
        for (int i = 6; i < 10; i++){
            Student student = new Student("user" + i, i + 2);
            students[i] = student;
        }

    }
    @Test
    public void testCollect1(){
        /**
         * Generate List
         */
        List<Student> list = Arrays.stream(students).collect(Collectors.toList());
        list.forEach((x) -> System.out.println(x));
        /**
         * Generate Set
         */
        Set<Student> set = Arrays.stream(students).collect(Collectors.toSet());
        set.forEach((x)-> System.out.println(x));
        /**
         * If the Map contains the same key, the third parameter needs to be provided. Otherwise, an error is reported. Here, the old value is overwritten
         */
        Map<String,Integer> map = Arrays.stream(students).collect(Collectors.toMap(Student::getName, Student::getScore, (v1, v2) -> v2));
        map.forEach((x, y) -> System.out.println(x + "->" + y));
    }

    /**
     * Generate array
     */
    @Test
    public void testCollect2(){
        Student[] s = Arrays.stream(students).toArray(Student[]::new);
        for (int i=0; i< s.length; i++)
            System.out.println(s[i]);
    }

3.2.6.groupingBy

groupingBy can group and fragment streams according to certain conditions. The condition is key. The elements after grouping form a new stream. Intermediate and terminal operations can be performed on the new stream. A List is generated by default. Finally, the type of Map generated. Key is the grouping condition, and value depends on the type generated after operating the grouped flow. There will be a problem of duplicate keys when generating a Map. Using groupingBy to put the value value of duplicate keys into a List can also solve this problem.
If you want to group according to multiple conditions, one method is groupingB nesting, using groupBy to group multiple times; Another method is to splice multiple grouping conditions into a key and group according to the spliced key.

	@Test
    public void testGroupBy1(){
        Map<String,List<Student>> map = Arrays.stream(students).collect(Collectors.groupingBy(Student::getName));
        map.forEach((x,y)-> System.out.println(x+"->"+y));
    }

    /**
     * If there are only two types, using partitioningBy is more efficient than grouping by
     */
    @Test
    public void testPartitioningBy(){
        Map<Boolean,List<Student>> map = Arrays.stream(students).collect(Collectors.partitioningBy(x -> x.getScore() > 5));
        map.forEach((x, y)-> System.out.println(x+ "->" + y));
    }

    /**
     * downstream Specify type
     */
    @Test
    public void testGroupBy2(){
        Map<String,Set<Student>> map = Arrays.stream(students).collect(Collectors.groupingBy(Student::getName, Collectors.toSet()));
        map.forEach((x, y)-> System.out.println(x + "->"+ y));
    }

    /**
     * downstream Aggregation operation
     */
    @Test
    public void testGroupBy3(){
        /**
         * counting
         */
        Map<String,Long> map1 = Arrays.stream(students).collect(Collectors.groupingBy(Student::getName, Collectors.counting()));
        map1.forEach((x, y)-> System.out.println(x + "->" + y));
        /**
         * summingInt
         */
        Map<String,Integer> map2 = Arrays.stream(students).collect(Collectors.groupingBy(Student::getName, Collectors.summingInt(Student::getScore)));
        map2.forEach((x,y) -> System.out.println(x + "->" + y));
        /**
         * maxBy
         */
        Map<String,Optional<Student>> map3 = Arrays.stream(students).collect(Collectors.groupingBy(Student::getName, Collectors.maxBy(Comparator.comparing(Student::getScore))));
        map3.forEach((x, y)-> System.out.println(x + "->" + y));
        
        /**
         * mapping, This is also used more. You can use the element variable as value or create a new object as value
         */
        Map<String,Set<Integer>> map4 = Arrays.stream(students).collect(Collectors.groupingBy(Student::getName, Collectors.mapping(Student::getScore, Collectors.toSet())));
        map4.forEach((x, y)-> System.out.println(x + "->" + y));

        /**
         * mapping, Use elements to group multiple variables
         */
        Map<String, Map<Integer, List<Student>>> map5 = Arrays.stream(students).collect(Collectors.groupingBy(Student::getName, Collectors.groupingBy(Student::getScore)));
        map5.forEach((x, y)-> System.out.println(x + "->" + y));

        /**
         * mapping, The second method is to splice multiple variables. I recommend this method
         */
        Map<String, List<Student>> map6 = Arrays.stream(students).collect(Collectors.groupingBy(student -> student.getName() + "_" + student.getScore()));
        map6.forEach((x, y)-> System.out.println(x + "->" + y));
    }

3.3. Collectors operation in stream

3.3.1.Collectors.toList()

List<String> listResult = list.stream().collect(Collectors.toList());
        log.info("{}",listResult);

Convert stream to list. The list converted here is ArrayList. If you want to convert it to a specific list, you need to use the toCollection method.

3.3.2.Collectors.toSet()

Set<String> setResult = list.stream().collect(Collectors.toSet());
        log.info("{}",setResult);

toSet converts a Stream to a set. HashSet is converted here. If you need to specify a set specifically, you need to use the toCollection method.

Because there are no duplicate elements in set, if we use duplicateList to convert, we will find that there is only one jack in the final result.

Set<String> duplicateSetResult = duplicateList.stream().collect(Collectors.toSet());
        log.info("{}",duplicateSetResult);

3.3.3.Collectors.toCollection()

The togap and toset above are all of specific types. If we need to customize them, we can use toCollection()

List<String> custListResult = list.stream().collect(Collectors.toCollection(LinkedList::new));
        log.info("{}",custListResult);

In the above example, we convert it to LinkedList.

3.3.4.Collectors.toMap()

toMap receives two parameters. The first parameter is keyMapper and the second parameter is valueMapper:

Map<String, Integer> mapResult = list.stream()
                .collect(Collectors.toMap(Function.identity(), String::length));
        log.info("{}",mapResult);

If there are duplicate values in the stream, the conversion will report IllegalStateException:

Map<String, Integer> duplicateMapResult = duplicateList.stream()
                .collect(Collectors.toMap(Function.identity(), String::length));

How to solve this problem? We can do this:

Map<String, Integer> duplicateMapResult2 = duplicateList.stream()
                .collect(Collectors.toMap(Function.identity(), String::length, (item, identicalItem) -> item));
        log.info("{}",duplicateMapResult2);

Add the third parameter mergeFunction in the toMap to solve the conflict.

3.3.5.Collectors.collectingAndThen()

collectingAndThen allows us to do another operation on the generated collection.

List<String> collectAndThenResult = list.stream()
                .collect(Collectors.collectingAndThen(Collectors.toList(), l -> {return new ArrayList<>(l);}));
        log.info("{}",collectAndThenResult);

3.3.6.Collectors.joining()

Joining is used to connect elements in the stream:

String joinResult = list.stream().collect(Collectors.joining());
        log.info("{}",joinResult);
        String joinResult1 = list.stream().collect(Collectors.joining(" "));
        log.info("{}",joinResult1);
        String joinResult2 = list.stream().collect(Collectors.joining(" ", "prefix","suffix"));
        log.info("{}",joinResult2);

You can take no parameters, one parameter or three parameters, which can be selected according to our needs.

3.3.7.Collectors.counting()

counting is mainly used to count the number of elements in the stream:

Long countResult = list.stream().collect(Collectors.counting());
        log.info("{}",countResult);

3.3.8.Collectors.summarizingDouble/Long/Int()

SummarizingDouble/Long/Int generates statistics for the elements in the stream. The returned result is a statistics class:

IntSummaryStatistics intResult = list.stream()
                .collect(Collectors.summarizingInt(String::length));
        log.info("{}",intResult);

Output results:

22:22:35.238 [main] INFO com.flydean.CollectorUsage - IntSummaryStatistics{count=4, sum=16, min=3, average=4.000000, max=5}

3.3.9.Collectors.averagingDouble/Long/Int()

Averagedouble / long / int() averages the elements in the stream:

Double averageResult = list.stream().collect(Collectors.averagingInt(String::length));
        log.info("{}",averageResult);

3.3.10.Collectors.summingDouble/Long/Int()

summingDouble/Long/Int() performs a sum operation on the elements in the stream:

Double summingResult = list.stream().collect(Collectors.summingDouble(String::length));
        log.info("{}",summingResult);

3.3.11.Collectors.maxBy()/minBy()

maxBy()/minBy() returns the maximum or minimum value in the stream according to the provided Comparator:

Optional<String> maxByResult = list.stream().collect(Collectors.maxBy(Comparator.naturalOrder()));
        log.info("{}",maxByResult);

3.3.12.Collectors.groupingBy()

GroupingBy groups according to some properties and returns a Map:

Map<Integer, Set<String>> groupByResult = list.stream()
                .collect(Collectors.groupingBy(String::length, Collectors.toSet()));
        log.info("{}",groupByResult);

3.3.13.Collectors.partitioningBy()

PartitioningBy is a special groupingBy. PartitioningBy returns a Map. This Map takes the boolean value as the key, which divides the stream into two parts. One part matches the partitionby condition, and the other part does not meet the condition:

 Map<Boolean, List<String>> partitionResult = list.stream()
                .collect(Collectors.partitioningBy(s -> s.length() > 3));
        log.info("{}",partitionResult);

See the operation results:

22:39:37.082 [main] INFO com.flydean.CollectorUsage - {false=[bob], true=[jack, alice, mark]}

The results are divided into two parts.

3.4.Stream full instance

import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;
 
public class Java8Tester {
   public static void main(String args[]){
      System.out.println("use Java 7: ");
        
      // Calculate empty string
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
      System.out.println("list: " +strings);
      long count = getCountEmptyStringUsingJava7(strings);
        
      System.out.println("The number of empty characters is: " + count);
      count = getCountLength3UsingJava7(strings);
        
      System.out.println("The number of strings with length 3 is: " + count);
        
      // Delete empty string
      List<String> filtered = deleteEmptyStringsUsingJava7(strings);
      System.out.println("Filtered list: " + filtered);
        
      // Delete empty strings and combine them with commas
      String mergedString = getMergedStringUsingJava7(strings,", ");
      System.out.println("Merge string: " + mergedString);
      List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        
      // Gets the square number of list elements
      List<Integer> squaresList = getSquares(numbers);
      System.out.println("Square list: " + squaresList);
      List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
        
      System.out.println("list: " +integers);
      System.out.println("Maximum number of in the list : " + getMax(integers));
      System.out.println("Minimum number in the list : " + getMin(integers));
      System.out.println("Sum of all numbers : " + getSum(integers));
      System.out.println("average : " + getAverage(integers));
      System.out.println("random number: ");
        
      // Output 10 random numbers
      Random random = new Random();
        
      for(int i=0; i < 10; i++){
         System.out.println(random.nextInt());
      }
        
      System.out.println("use Java 8: ");
      System.out.println("list: " +strings);
        
      count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("The number of empty strings is: " + count);
        
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("The number of strings with length 3 is: " + count);
        
      filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
      System.out.println("Filtered list: " + filtered);
        
      mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
      System.out.println("Merge string: " + mergedString);
        
      squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
      System.out.println("Squares List: " + squaresList);
      System.out.println("list: " +integers);
        
      IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
        
      System.out.println("Maximum number of in the list : " + stats.getMax());
      System.out.println("Minimum number in the list : " + stats.getMin());
      System.out.println("Sum of all numbers : " + stats.getSum());
      System.out.println("average : " + stats.getAverage());
      System.out.println("random number: ");
        
      random.ints().limit(10).sorted().forEach(System.out::println);
        
      // parallel processing 
      count = strings.parallelStream().filter(string -> string.isEmpty()).count();
      System.out.println("The number of empty strings is: " + count);
   }
    
   private static int getCountEmptyStringUsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.isEmpty()){
            count++;
         }
      }
      return count;
   }
    
   private static int getCountLength3UsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.length() == 3){
            count++;
         }
      }
      return count;
   }
    
   private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
      List<String> filteredList = new ArrayList<String>();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
             filteredList.add(string);
         }
      }
      return filteredList;
   }
    
   private static String getMergedStringUsingJava7(List<String> strings, String separator){
      StringBuilder stringBuilder = new StringBuilder();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
            stringBuilder.append(string);
            stringBuilder.append(separator);
         }
      }
      String mergedString = stringBuilder.toString();
      return mergedString.substring(0, mergedString.length()-2);
   }
    
   private static List<Integer> getSquares(List<Integer> numbers){
      List<Integer> squaresList = new ArrayList<Integer>();
        
      for(Integer number: numbers){
         Integer square = new Integer(number.intValue() * number.intValue());
            
         if(!squaresList.contains(square)){
            squaresList.add(square);
         }
      }
      return squaresList;
   }
    
   private static int getMax(List<Integer> numbers){
      int max = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
        
         Integer number = numbers.get(i);
            
         if(number.intValue() > max){
            max = number.intValue();
         }
      }
      return max;
   }
    
   private static int getMin(List<Integer> numbers){
      int min = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
         Integer number = numbers.get(i);
        
         if(number.intValue() < min){
            min = number.intValue();
         }
      }
      return min;
   }
    
   private static int getSum(List numbers){
      int sum = (int)(numbers.get(0));
        
      for(int i=1;i < numbers.size();i++){
         sum += (int)numbers.get(i);
      }
      return sum;
   }
    
   private static int getAverage(List<Integer> numbers){
      return getSum(numbers) / numbers.size();
   }
}

Execute the above script, and the output result is:

$ javac Java8Tester.java 
$ java Java8Tester
 use Java 7: 
list: [abc, , bc, efg, abcd, , jkl]
The number of empty characters is: 2
 The number of strings with length 3 is: 3
 Filtered list: [abc, bc, efg, abcd, jkl]
Merge string: abc, bc, efg, abcd, jkl
 Square list: [9, 4, 49, 25]
list: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Maximum number of in the list : 19
 Minimum number in the list : 1
 Sum of all numbers : 85
 average : 9
 random number: 
-393170844
-963842252
447036679
-1043163142
-881079698
221586850
-1101570113
576190039
-1045184578
1647841045
 use Java 8: 
list: [abc, , bc, efg, abcd, , jkl]
The number of empty strings is: 2
 The number of strings with length 3 is: 3
 Filtered list: [abc, bc, efg, abcd, jkl]
Merge string: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
list: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Maximum number of in the list : 19
 Minimum number in the list : 1
 Sum of all numbers : 85
 average : 9.444444444444445
 random number: 
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
 The number of empty strings is: 2

Topics: Java filter stream reduce