Lambda Expression & Functional Interface & Stream

Table of contents

1. Lambda expression

1. Overview of functional programming ideas

2. Lambda optimization

3. Format of Lambda

standard format:

Parameters and return values:

Omit format:

4. Prerequisites for Lambda

 2. Functional interface

1 Overview

Format

FunctionalInterface annotation

2. Commonly used functional interfaces

Supplier interface

Consumer interface

Function interface

Predicate interface

3. Stream flow

1 Introduction

2. Overview of stream thinking

3. Get stream method

4. Common methods

forEach : process one by one

filter: filter

count: the number of statistics

limit: take the first few

skip: skip the first few

concat: combination

4. Conclusion


1. Lambda expression


1. Overview of functional programming ideas

In mathematics, a function is a set of calculation schemes with input and output, that is, "what to do with something". Relatively speaking, object-oriented places too much emphasis on "things must be done in the form of objects", while functional thinking tries to ignore the complex syntax of object-oriented- emphasizing what to do, not what form to do .  

y = 2*x + 5;

Functional thinking:

public class A {

public int method(int x) {

return 2*x + 5;

}

}

Object-oriented thinking:

A a = new A();

int y = a.method(5);

java.util.Scanner class

Scanner sc = ...;

int num = sc.nextInt();

what to do, not how

Do we really want to create an anonymous inner class object? No. We have to create an object just to do this . What we really want to do is: pass runthe code in the method body to Threadthe class.

Pass a piece of code - that's what we're really here for. And creating an object is only a means that has to be taken due to the limitation of object-oriented syntax. So, is there an easier way? If we return the focus from "how to do" to the essence of "what to do", we will find that as long as the purpose can be better achieved, the process and form are not important.

2. Lambda optimization

When a thread needs to be started to complete a task, java.lang.Runnablethe task content is usually defined through an interface, and java.lang.Threadthe thread is started using a class.

The traditional way of writing, the code is as follows:

public class Demo03Thread {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程任务执行!");
            }
        }).start();
    }
}

In line with the idea of ​​"everything is an object", this approach is understandable: first create an Runnableanonymous inner class object of the interface to specify the task content, and then hand it over to a thread to start.

Code analysis:

For Runnablethe usage of the anonymous inner class, we can analyze a few things:

  • ThreadThe class requires Runnablean interface as a parameter, and the abstract runmethod is the core used to specify the content of the thread task;

  • For the specified runmethod body, the implementation class of the interface has to be required Runnable;

  • In order to save the trouble of defining an RunnableImplimplementation class, an anonymous inner class has to be used;

  • The abstract runmethod must be overridden, so the method name, method parameters, and method return value have to be written again, and cannot be written wrong;

  • In fact, only the method body seems to be the key .

 

Lambda expression writing method, the code is as follows:

With the help of the new syntax of Java 8, Runnablethe anonymous inner class writing method of the above interface can be equivalent through a simpler Lambda expression:

public class Demo04LambdaRunnable {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程
    }
}

This code is exactly the same as the execution effect just now, and can be passed at a compilation level of 1.8 or higher. It can be seen from the semantics of the code: we start a thread, and the content of the thread task is specified in a more concise form.

There is no longer the constraint of "having to create an interface object", and there is no longer the burden of "abstract method overwriting and rewriting", it's that simple!

3. Format of Lambda

standard format:

Lambda omits object-oriented rules and regulations, and the format consists of 3 parts :

  • some parameters

  • an arrow

  • a piece of code

The standard format for a Lambda expression is:

(parameter type parameter name) -> { code statement }

Format specification:

  • The syntax inside parentheses is the same as for traditional method parameter lists: leave blank if no parameter; multiple parameters are separated by commas.

  • ->is a newly introduced grammatical format, representing a pointing action.

  • The syntax inside curly braces is basically consistent with the traditional method body requirements.

Anonymous inner class compared with lambda:

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程任务执行!");
            }
}).start();

Carefully analyze the code, Runnablethe interface has only one runmethod definition:

  • public abstract void run();

That is, a plan to do things (actually a method) has been formulated:

  • No parameters : No conditions are required to execute the scenario.

  • No return value : The program produces no results.

  • Code block (method body): the specific execution steps of the solution.

The same semantics are reflected in Lambdathe syntax, which is simpler:

() -> System.out.println("Multi-thread task execution!")

  • The previous pair of parentheses are runthe parameters of the method (none), which means that no conditions are required;

  • An arrow in the middle represents passing the previous parameters to the following code;

  • The following output statement is the business logic code.

Parameters and return values:

The following example demonstrates java.util.Comparator<T>the usage scenario code of the interface, where the abstract method is defined as:

  • public abstract int compare(T o1, T o2);

When it is necessary to sort an array of objects, Arrays.sortthe method needs an Comparatorinterface instance to specify the sorting rules. Suppose there is a Personclass with String nametwo int agemember variables:

public class Person { 
    private String name;
    private int age;
    
    // 省略构造器、toString方法与Getter Setter 
}

traditional writing

If you use traditional code to Person[]sort the array, it is written as follows:

public class Demo05Comparator {
    public static void main(String[] args) {
        // 本来年龄乱序的对象数组
        Person[] array = { new Person("古力娜扎", 19),          new Person("迪丽热巴", 18),             new Person("马尔扎哈", 20) };
​
        // 匿名内部类
        Comparator<Person> comp = new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        };
        Arrays.sort(array, comp); // 第二个参数为排序规则,即Comparator接口实例
​
        for (Person person : array) {
            System.out.println(person);
        }
    }
}

This approach seems to be "natural" in object-oriented thinking. Among them, Comparatorthe instance of the interface (using the anonymous inner class) represents the sorting rule of "according to age from youngest to oldest".

code analysis

Let's figure out what the above code really does.

  • For sorting, Arrays.sortmethods need sorting rules, that is, Comparatorinstances of interfaces, and abstract methods compareare the key;

  • For the specified comparemethod body, the implementation class of the interface has to be required Comparator;

  • In order to save the trouble of defining an ComparatorImplimplementation class, an anonymous inner class has to be used;

  • The abstract comparemethod must be overridden, so the method name, method parameters, and method return value have to be written again, and cannot be written wrong;

  • In fact, only the parameters and method body are the key .

Lambda writing

public class Demo06ComparatorLambda {
    public static void main(String[] args) {
        Person[] array = {
          	new Person("古力娜扎", 19),
          	new Person("迪丽热巴", 18),
          	new Person("马尔扎哈", 20) };

        Arrays.sort(array, (Person a, Person b) -> {
          	return a.getAge() - b.getAge();
        });

        for (Person person : array) {
            System.out.println(person);
        }
    }
}

Omit format:

omitting rules

Based on the Lambda standard format, the rules for using ellipsis are:

  1. The type of parameters in parentheses can be omitted;

  2. If there is only one parameter in the parentheses , the parentheses can be omitted;

  3. If there is one and only one statement inside the braces , the braces, the return keyword and the statement semicolon can be omitted regardless of whether there is a return value.

Note: After mastering these omission rules, please review the multithreading case at the beginning of this chapter accordingly.

Can be deduced or omitted

Lambda emphasizes "what to do" rather than "how to do it", so any information that can be derived can be omitted. For example, the above example can also use the omission of Lambda:

Runnable interface simplification:
1. () -> System.out.println("Multi-threaded task execution!")
Comparator interface simplification:
2. Arrays.sort(array, (a, b) -> a.getAge() - b.getAge()); 

4. Prerequisites for Lambda

The syntax of Lambda is very concise, without the constraints of object-oriented complexity. However, there are several issues that need special attention when using it:

  1. The use of Lambda must have an interface, and requires one and only one abstract method in the interface . Whether it is a JDK built-in interface Runnableor Comparatora custom interface, Lambda can only be used when the abstract method in the interface exists and is unique.

  2. Using Lambda must have interface as method parameter. That is, the parameter or local variable type of the method must be the interface type corresponding to Lambda, so that Lambda can be used as an instance of the interface.

Note: An interface with one and only one abstract method is called a " functional interface ".

Note:  The reason why Lambda expressions in Java 8 only allow capture of immutable variables

# statement one

Local variables in Java are stored on the stack, not the heap. Each thread has its own stack, so local variables are limited to their own thread. This is because the life cycle of a local variable is limited to the method or code block where it is located. When the method or code block is executed, the local variable will be destroyed.

Local variables are considered thread-safe in multithreaded programming because they are restricted to the thread in which they reside. Each thread has its own stack, and the data on the stack will not be shared between threads, so there will be no thread safety issues.

Lambda expressions in Java 8 only allow the capture (use) of immutable local variables, because local variables are stored on the stack and implicitly indicate that they are limited to the thread in which they reside. Allowing capture of mutable local variables opens up the possibility of thread unsafety, which we don't want. (new instance variables are ok, since they are kept on the heap, which is shared between threads)

# statement two

In Java 8, Lambda expressions allow the use of external variables. However, when using Lambda expressions, the outer variable must be effectively final or effectively final. The so-called effectively final means that the variable value has not been modified inside the Lambda expression.

Effectively final means that the variable is not reassigned after it is declared. This means that you can access the value of the variable in the Lambda expression, but not modify it. This is because the variable captured in the lambda expression is actually a copy of the variable, not the original variable itself. If a variable is final, the compiler can guarantee that the value of the variable will not change, so it is safe to use in Lambda expressions.

Failure to follow this rule will result in compilation errors.

The purpose of this rule is to ensure that the values ​​of variables captured in Lambda expressions are immutable, so as to avoid race conditions when multiple threads access variables concurrently. If you need to modify the value of a variable in a Lambda expression, you can use mutable variables such as arrays or objects, or use Atomic variables for thread safety.

# statement three

The reason lambda expressions in Java 8 only allow capture of immutable variables is to ensure thread safety and maintainability of the code.

If Lambda expressions could capture mutable variables, then accessing the values ​​of those variables could be shared among multiple threads, causing race conditions and thread safety issues. Therefore, to avoid this, Lambda expressions can only access immutable variables.

In addition, variables used in Lambda expressions must meet the requirement of being effectively final, that is, variables are not reassigned after they are declared. This makes the code clearer and easier to understand, because the reader of the code can more easily understand that the value of the variable will not be changed in the Lambda expression.

For mutable variables, Atomic variables or other thread-safe mechanisms can be used to ensure thread safety. However, using these mechanisms may increase code complexity and maintenance costs. Therefore, it is recommended to use immutable variables as much as possible when writing Lambda expressions to keep the code concise and maintainable.

 2. Functional interface


1 Overview

A functional interface in Java refers to an interface with one and only one abstract method .

Functional interface, that is, an interface suitable for functional programming scenarios. The embodiment of functional programming in Java is Lambda, so the functional interface is an interface that can be applied to Lambda. Only by ensuring that there is one and only one abstract method in the interface can Lambda in Java be deduced smoothly.

Remarks: From the application level, Lambda in Java can be regarded as a simplified format of anonymous inner class, but the two are different in principle.

Format

Just make sure that the interface has one and only one abstract method:

Modifier interface interface name{    

        public abstract return value type method name (optional parameter information);  

         // Other non-abstract method content

}

Since the abstract method in the interface public abstractcan be omitted, it is very simple to define a functional interface:

 public interface MyFunctionalInterface {    
    void myMethod();
}

FunctionalInterface annotation

Similar to @Overridethe role of annotations, Java 8 introduces a new annotation specifically for functional interfaces: @FunctionalInterface. This annotation can be used on the definition of an interface:

@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

2. Commonly used functional interfaces

JDK provides a large number of commonly used functional interfaces to enrich typical usage scenarios of Lambda, and they are mainly java.util.functionprovided in packages. The preceding MySupplierinterface is simulating a functional interface: java.util.function.Supplier<T>. In fact, there are many more. The following are the simplest interfaces and usage examples.

Supplier interface

java.util.function.Supplier<T>Interface, which means "supply", the corresponding Lambda expression needs to " provide " an object data conforming to the generic type.

abstract method: get

Contains only one parameterless method: T get(). Used to get object data of the type specified by a generic parameter.

public class Demo08Supplier {
    private static String getString(Supplier<String> function) {
      	return function.get();
    }

    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        System.out.println(getString(() -> msgA + msgB));
    }
}

Find the maximum value of an array element

Use Supplierthe interface as the method parameter type, and find the maximum value in the int array through the Lambda expression. Tip: For interface generics, please use java.lang.Integerclasses.

Code example:

public class DemoIntArray {
    public static void main(String[] args) {
        int[] array = { 10, 20, 100, 30, 40, 50 };
        printMax(() -> {
            int max = array[0];
            for (int i = 1; i < array.length; i++) {
                if (array[i] > max) {              
                  	max = array[i];
                }
            }
            return max;
        });
    }

    private static void printMax(Supplier<Integer> supplier) {
        int max = supplier.get();
        System.out.println(max);
    }
}

Consumer interface

java.util.function.Consumer<T>The interface is just the opposite. Instead of producing a data, it consumes a data, and its data type is determined by the generic parameter.

Abstract method: accept

Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据。基本使用如:

//给你一个字符串,请按照大写的方式进行消费
import java.util.function.Consumer;

public class Demo09Consumer {
    public static void main(String[] args) {
        String str = "Hello World";
        //1.lambda表达式标准格式
        fun(str,(String s)->{
            System.out.println(s.toUpperCase());
        });
        //2.lambda表达式简化格式
        fun(str,s-> System.out.println(s.toUpperCase()));
    }
    /*
        定义方法,使用Consumer接口作为参数
        fun方法: 消费一个String类型的变量
     */
    public static void fun(String s,Consumer<String> con) {
        con.accept(s);
    }
}

Function interface

java.util.function.Function<T,R>An interface is used to obtain data of another type based on data of one type. The former is called a precondition, and the latter is called a postcondition. There are in and out, so it is called "Function".

Abstract method: apply

FunctionThe main abstract method in the interface is: R apply(T t), to obtain the result of type R according to the parameter of type T. Scenarios used eg: converting Stringtype to Integertype.

//给你一个String的数字,你给我转成一个int数字
public class Demo11FunctionApply {
    private static void method(Function<String, Integer> function, Str str) {
        int num = function.apply(str);
        System.out.println(num + 20);
    }

    public static void main(String[] args) {
        method(s -> Integer.parseInt(s) , "10");
    }
}

Predicate interface

Sometimes we need to judge a certain type of data to get a boolean value result. java.util.function.Predicate<T>This is where interfaces can be used .

Abstract method: test

PredicateThe interface contains one abstract method: boolean test(T t). It is used in conditional judgment scenarios. The criterion for conditional judgment is the logic of the incoming Lambda expression. As long as the string length is greater than 5, it is considered very long.

//1.练习:判断字符串长度是否大于5
//2.练习:判断字符串是否包含"H"
public class Demo15PredicateTest {
    private static void method(Predicate<String> predicate,String str) {
        boolean veryLong = predicate.test(str);
        System.out.println("字符串很长吗:" + veryLong);
    }

    public static void main(String[] args) {
        method(s -> s.length() > 5, "HelloWorld");
    }
}

3. Stream flow


In Java 8, thanks to the functional programming brought by Lambda, a new Stream concept is introduced to solve the existing drawbacks of existing collection libraries.

1 Introduction

Multi-step traversal code for traditional collections

Almost all collections (such as Collectioninterfaces or Mapinterfaces, etc.) support direct or indirect traversal operations. When we need to operate on the elements in the collection, in addition to the necessary addition, deletion, and acquisition, the most typical one is collection traversal. For example:

public class Demo10ForEach {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        for (String name : list) {
          	System.out.println(name);
        }
    }  
}

This is a very simple collection traversal operation: print out each string in the collection.

Disadvantages of looping

Java 8's Lambda allows us to focus more on what to do (What) rather than how to do it (How). This has been compared with internal classes before. Now, if we take a closer look at the above example code, we can find that:

  • The syntax of the for loop is " how to do it "

  • The loop body of the for loop is " what to do "

Why use a loop? Because of the traversal. But is looping the only way to traverse? Traversal means that each element is processed one by one, rather than a loop that is processed sequentially from the first to the last . The former is the purpose, the latter is the way.

Just imagine, if you want to filter the elements in the collection:

  1. Filter set A into subset B according to condition one ;

  2. Then filter it into subset C according to the second condition .

What should I do then? The way before Java 8 may be:

This code contains three loops, each with a different effect:

  1. First filter all people with the surname Zhang;

  2. Then screen people with three characters in their name;

  3. Finally, print out the results.

public class Demo11NormalFilter {
  	public static void main(String[] args) {
      	List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        List<String> zhangList = new ArrayList<>();
        for (String name : list) {
            if (name.startsWith("张")) {
              	zhangList.add(name);
            }
        }

        List<String> shortList = new ArrayList<>();
        for (String name : zhangList) {
            if (name.length() == 3) {
              	shortList.add(name);
            }
        }

        for (String name : shortList) {
          	System.out.println(name);
        }
    }
}

Whenever we need to operate on elements in a collection, we always need to loop, loop, and recycle. Is this taken for granted? no. Loops are a way of doing things, not an end. On the other hand, using a linear loop means that it can only be traversed once. If you want to traverse again, you can only use another loop to start from the beginning.

So, what kind of more elegant way can Lambda's derivative Stream bring us?

A better way to write Stream

Let's take a look at what is elegant with the help of Java 8's Stream API:

public class Demo12StreamFilter {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        list.stream()
          	.filter(s -> s.startsWith("张"))
            .filter(s -> s.length() == 3)
            .forEach(s -> System.out.println(s));
    }
}

2. Overview of stream thinking

Note: Please temporarily forget the inherent impression of traditional IO streams!

On the whole, the streaming idea is similar to the " production line " on the factory floor.

 

When it is necessary to operate on multiple elements (especially multi-step operations), considering performance and convenience, we should first put together a "model" step plan, and then execute it according to the plan.

This figure shows multi-step operations such as filtering, mapping, skipping, and counting. This is a processing scheme for collection elements, and the scheme is a "function model". Each box in the diagram is a "flow", which can be converted from one flow model to another by calling the specified method. And the number 3 on the far right is the final result.

The filter, map, and here skipare all operating on the function model, and the collection elements are not really processed. Only when the final method countis executed, the entire model will perform operations according to the specified strategy. And this benefits from the delayed execution feature of Lambda.

Remarks: "Stream" is actually a functional model of a collection element. It is not a collection or a data structure, and it does not store any elements (or their address values).

3. Get stream method

java.util.stream.Stream<T>It is the most commonly used stream interface newly added by Java 8. (This is not a functional interface.)

Obtaining a stream is very simple, and there are several common ways:

  • All Collectioncollections can streamget streams by default method;

  • StreamThe static method of the interface ofcan obtain the stream corresponding to the array.

Method 1: Get the stream according to Collection

public default Stream<E> stream(): Get the Stream stream object corresponding to the Collection collection object

First of all, java.util.Collectiona default method is added to the interface streamto obtain the stream, so all its implementation classes can obtain the stream.

import java.util.*;
import java.util.stream.Stream;
/*
    获取Stream流的方式

    1.Collection中 方法
        Stream stream()
    2.Stream接口 中静态方法
        of(T...t) 向Stream中添加多个数据
 */
public class Demo13GetStream {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        // ...
        Stream<String> stream1 = list.stream();

        Set<String> set = new HashSet<>();
        // ...
        Stream<String> stream2 = set.stream();
    }
}

Method 2: Get the stream according to the array

If you are not using a collection or map but an array, since it is impossible to add a default method to an array object, a Streamstatic method is provided in the interface of, which is very simple to use:

import java.util.stream.Stream;

public class Demo14GetStream {
    public static void main(String[] args) {
        String[] array = { "张无忌", "张翠山", "张三丰", "张一元" };
        Stream<String> stream = Stream.of(array);
    }
}

Remarks: ofThe parameter of the method is actually a variable parameter, so arrays are supported.  

4. Common methods

The operation of the stream model is very rich, and some commonly used APIs are introduced here. These methods can be divided into two types:

  • Final method : The return value type is no longer Streama method of the interface's own type, so StringBuilderchain calls like that are no longer supported. In this section, final methods include countand forEachmethods.

  • Non-terminal method : The return value type is still Streamthe method of the interface's own type, so chain calls are supported. (Except for final methods, the remaining methods are non-terminal methods.)

Remarks: For more methods beyond this section, please refer to the API documentation yourself.

forEach : process one by one

Although the method name is called forEach, but unlike the "for-each" nickname in the for loop, this method does not guarantee that the element-by-element consumption actions are executed in order in the stream .

void forEach(Consumer<? super T> action);

This method receives an Consumerinterface function, and will hand over each stream element to the function for processing. For example:

import java.util.stream.Stream;

public class Demo15StreamForEach {
    public static void main(String[] args) {
        Stream<String> stream =  Stream.of("大娃","二娃","三娃","四娃","五娃","六娃","七娃","爷爷","蛇精","蝎子精");
        //Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若");
        stream.forEach((String str)->{System.out.println(str);});
    }
}

Here, the lambda expression (String str)->{System.out.println(str);}is an example of a Consumer functional interface.

filter: filter

Methods can be used filterto transform a stream into another subset stream. Method declaration:

Stream<T> filter(Predicate<? super T> predicate);

This interface receives a Predicatefunctional interface parameter (which can be a Lambda) as a filter condition.

basic use

filterThe basic code used by the method   in the Stream stream is as follows:

public class Demo16StreamFilter {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
        Stream<String> result = original.filter((String s) -> {return s.startsWith("张");});
    }
}

Here, the filter condition is specified through a Lambda expression: the surname must be Zhang.

count: the number of statistics

CollectionJust like methods in old collections size, streams provide countmethods to count the number of elements in them:

long count();

This method returns a long value representing the number of elements (no longer an int value like the old collection). Basic use:

public class Demo17StreamCount {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
        Stream<String> result = original.filter(s -> s.startsWith("张"));
        System.out.println(result.count()); // 2
    }
}

limit: take the first few

limitThe method can intercept the stream and only use the first n streams. Method signature:

Stream<T> limit(long n): Get the first n elements in the Stream stream object and return a new Stream stream object

The parameter is a long type. If the current length of the collection is greater than the parameter, it will be intercepted; otherwise, no operation will be performed. Basic use:

import java.util.stream.Stream;

public class Demo18StreamLimit {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
        Stream<String> result = original.limit(2);
        System.out.println(result.count()); // 2
    }
}

skip: skip the first few

If you want to skip the first few elements, you can use skipthe method to get a new stream after interception:

Stream<T> skip(long n): Skip the first n elements in the Stream object and return a new Stream object

If the current length of the stream is greater than n, the first n streams are skipped; otherwise, an empty stream of length 0 will be obtained. Basic use:  

import java.util.stream.Stream;

public class Demo19StreamSkip {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
        Stream<String> result = original.skip(2);
        System.out.println(result.count()); // 1
    }
}

concat: combination

If you have two streams and want to merge them into one stream, you can use Streamthe static method of the interface concat:

static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): Merge the two Stream objects a and b in the parameter list into a new Stream object

Remarks: This is a static method, which is different from the methods java.lang.Stringin it .concat

The basic usage code of this method is as follows:

import java.util.stream.Stream;

public class Demo20StreamConcat {
    public static void main(String[] args) {
        Stream<String> streamA = Stream.of("张无忌");
        Stream<String> streamB = Stream.of("张翠山");
        Stream<String> result = Stream.concat(streamA, streamB);
    }
}

4. Conclusion


  • It can be said that Lambda expression is an accessory of functional programming language. It was introduced in Java to improve the flexibility and expressive ability of Java language and better support the concept of functional programming.
  • The essence of Lambda expression is an anonymous function, which can be passed as a method parameter, or used as an instance of a functional interface, so as to realize the concept of functional programming. This results in more concise, efficient and readable code.
  • Functional interface, Stream API, method reference and other features, together with Lambda expressions, constitute the core content of Java 8 functional programming.
  • Lambda expressions and Stream API are interrelated, and Lambda expressions provide a way to implement various operations in Stream API
  • Lambda expressions are one of the core features supporting functional programming in Java 8, and functional interfaces are an important prerequisite for supporting Lambda expressions.
  • Streams and functional interfaces are closely related. The Stream API provides a set of functional interfaces that can be used to manipulate collection data, making the code more concise and easy to understand. At the same time, the functional interface is also the basis of the Stream API, and many operations in the Stream API are implemented based on the functional interface.

Guess you like

Origin blog.csdn.net/m0_69057918/article/details/131120602