java编程实现思想讲解

    科技2026-08-23  5

    java编程实现思想讲解

    If you’re a Java developer, I’m sure that you have seen code similar to the snippet above at least once. The code in the snippet above is an example of functional programming paradigm implementation in Java, which will filter and transform the List<String> in the request to another List<String>.

    如果您是Java开发人员,请确保您至少看过一次与上述代码段相似的代码。 上面代码段中的代码是Java中的函数式编程范例实现的示例,该示例将过滤请求中的List<String>并将其转换为另一个List<String> 。

    In this article, I will write about how to write code using Java’s API for functional programming. In the end, we will write our own stream API so we can understand how to implement a functional programming style in Java.

    在本文中,我将介绍如何使用Java API进行函数式编程来编写代码。 最后,我们将编写自己的流API,以便我们了解如何在Java中实现功能编程风格。

    Java函数式编程 (Functional Programming in Java)

    Functional programming in Java has been around for a long time. When Oracle released Java 8 back in 2014, they introduced lambda expression, which was the core feature for functional programming in Java.

    Java中的函数式编程已经存在了很长时间。 当Oracle在2014年发布Java 8时,他们引入了lambda expression ,这是Java函数式编程的核心功能。

    Let’s see an example of the difference between using a sequence of imperative statements and using a functional style in Java.

    让我们看一下使用命令式语句序列和使用Java中的函数样式之间的区别的示例。

    List<String> stringList = Arrays.asList("Hello", "World", "How", "Are", "You", "Today"); // imperative declaration List<String> filteredList = new ArrayList<>(); for (String string: stringList) { if (string.equals("Hello") || string.equals("Are")) { filteredList.add(string); } } List<String> mappedList = new ArrayList<>(); for (String string: filteredList) { mappedList.add(string + " String"); } for (String string: mappedList) { System.out.println(string); } List<String> stringList = Arrays.asList("Hello", "World", "How", "Are", "You", "Today"); //functional style stringList.stream() .filter(s -> s.equals("Hello") || s.equals("Are")) .map(s -> s + " String") .forEach(System.out::println);

    As we can see, even though both pieces of code achieve the same result, the difference is significant. The imperative declaration code has many curly braces and is much longer, which makes it harder to read, compared to the functional style code.

    如我们所见,即使两段代码都达到了相同的结果,两者之间的差异还是很大的。 与功能样式代码相比,命令式声明代码具有许多花括号并且更长,这使得其难以阅读。

    功能接口注释 (Functional Interface Annotation)

    To understand how functional programming works in Java, first we will need to look at the annotation included in Java 8 SDK, @FunctionalInterface. We can look at it on the Java API documentation site.

    要了解函数式编程在Java中的工作方式,首先我们需要查看Java 8 SDK中包含的注释@FunctionalInterface 。 我们可以在Java API文档站点上查看它。

    From the API documentation, we can see that the behaviors of a functional interface annotation in Java are:

    从API文档中,我们可以看到Java中的功能接口注释的行为是:

    It has exactly one abstract method in it.

    它里面只有一种抽象方法。 It can have more than one method, as long as there is only one abstract method.

    只要只有一种抽象方法,它就可以有多种方法。

    We can only add it to Interface type.

    我们只能将其添加到Interface类型。

    We can create the functional interface with a lambda expression, method references, or constructor references.

    我们可以使用lambda表达式,方法引用或构造函数引用来创建功能接口。

    We don’t need to define @FunctionalInterface because the compiler will treat any interface meeting the definition of a functional interface as a functional interface.

    我们不需要定义@FunctionalInterface因为编译器会将符合功能接口定义的任何接口视为功能接口。

    创建功能接口类 (Creating a Functional Interface Class)

    Now we know what a functional interface all about, we can create it by ourselves.

    现在我们知道了功能接口到底是什么,我们可以自己创建它。

    Let’s first create a model called Person.

    首先创建一个名为Person的模型。

    package com.example.functional.programming.model; public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name) { this.name = name; } public static Person createClassExampleFromMethodReference(String name) { return new Person(name); } }

    For the functional interface, we'll create PersonFunctionalInterface class.

    对于功能接口,我们将创建PersonFunctionalInterface类。

    package com.example.functional.programming.intf; import com.example.functional.programming.model.Person; @FunctionalInterface public interface PersonFunctionalInterface { Person createPerson(String name); default String getDefaultMethodString() { return "Default Method"; } }

    Note that there are two methods in the interface, but since there is only one abstract method, PersonFunctionalInterfaceclass is valid as a functional interface.

    请注意,接口中有两种方法,但是由于只有一种抽象方法,因此PersonFunctionalInterface类可用作功能接口。

    But suppose we define more than one abstract method, like so:

    但是假设我们定义了多个抽象方法,如下所示:

    package com.example.functional.programming.intf; import com.example.functional.programming.model.Person; @FunctionalInterface public interface PersonFunctionalInterface { Person createPerson(String name); String mapStringToObject(String str); default String getDefaultMethodString() { return "Default Method"; } }

    It will produce an error:

    它将产生一个错误:

    [INFO] ------------------------------------------------------------- [ERROR] COMPILATION ERROR : [INFO] ------------------------------------------------------------- [ERROR] /D:/Project/functional/src/main/java/com/example/functional/programming/intf/PersonFunctionalInterface.java:[5,1] Unexpected @FunctionalInterface annotation com.example.functional.programming.intf.PersonFunctionalInterface is not a functional interface multiple non-overriding abstract methods found in interface com.example.functional.programming.intf.PersonFunctionalInterface [INFO] 1 error [INFO] ------------------------------------------------------------- [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5.105 s [INFO] Finished at: 2020-09-19T10:34:45+07:00 [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project functional-programming: Compilation failure [ERROR] /D:/Project/functional/src/main/java/com/example/functional/programming/intf/PersonFunctionalInterface.java:[5,1] Unexpected @FunctionalInterface annotation [ERROR] com.example.functional.programming.intf.PersonFunctionalInterface is not a functional interface [ERROR] multiple non-overriding abstract methods found in interface com.example.functional.programming.intf.PersonFunctionalInterface

    使用功能界面(Using a Functional Interface)

    匿名班(Anonymous class)

    Let’s first learn about the anonymous class. Java documentation says that:

    首先让我们了解匿名类。 Java文档说:

    “Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.”

    “匿名类使您可以使代码更简洁。 它们使您可以同时声明和实例化一个类。 它们就像本地类,只是它们没有名称。 如果您只需要使用一次本地类,请使用它们。”

    Basically, with an anonymous class, we don’t have to define a class that implements the interface we made. We can create a class without a name and store it in a variable.

    基本上,对于匿名类,我们不必定义实现我们所创建接口的类。 我们可以创建一个没有名称的类并将其存储在变量中。

    Let’s declare an anonymous class as an example.

    让我们以一个匿名类为例。

    @Test void declareAnonymousClass() { PersonFunctionalInterface anonClassExample = new PersonFunctionalInterface() { @Override public Person createPerson(String name) { return new Person(name); } }; assert (anonClassExample.createPerson("Hello, World").getName().equals("Hello, World")); }

    What we’ve done here is we created an anonymous class with PersonFunctionalInterface type and anonClassExample name.

    我们在这里所做的是创建了一个具有PersonFunctionalInterface类型和anonClassExample名称的匿名类。

    We override the createPerson abstract method so when we call the method, it will return a new Person object with a name.

    我们覆盖了createPerson抽象方法,因此当我们调用该方法时,它将返回一个带有名称的新Person对象。

    When we called anonClassExample.createPerson(“Hello, World”), we basically just created a new Person object with “Hello, World” as its name.

    当我们调用anonClassExample.createPerson(“Hello, World”) ,我们基本上只是创建了一个名为anonClassExample.createPerson(“Hello, World”)的新Person对象。

    创建具有功能接口的匿名类 (Creating an Anonymous Class With a Functional Interface)

    We can start creating the anonymous class of PersonFunctionalinterface for the functional interface we made.

    我们可以开始为所创建的功能接口创建PersonFunctionalinterface的匿名类。

    @Test void interfaceExample() { PersonFunctionalInterface normalAnonymousClass = new PersonFunctionalInterface() { // create normal anonymous class @Override public Person createPerson(String name) { return new Person(name); } }; PersonFunctionalInterface interfaceExampleLambda = name -> new Person(name); // create anonymous class by lambda PersonFunctionalInterface interfaceExampleMethodReference = Person::createClassExampleFromMethodReference; // create anonymous class by method reference PersonFunctionalInterface interfaceExampleConstructorReference = Person::new; // create anonymous class by constructor reference // assert that every anonymous class behave the same assert(normalAnonymousClass .createPerson("Hello, World").getName().equals("Hello, World")); assert(interfaceExampleLambda .createPerson("Hello, World").getName().equals("Hello, World")); assert(interfaceExampleMethodReference .createPerson("Hello, World").getName().equals("Hello, World")); assert(interfaceExampleConstructorReference .createPerson("Hello, World").getName().equals("Hello, World")); assert(normalAnonymousClass.getDefaultMethodString().equals("Default Method")); assert(interfaceExampleLambda.getDefaultMethodString().equals("Default Method")); assert(interfaceExampleMethodReference.getDefaultMethodString().equals("Default Method")); assert(interfaceExampleConstructorReference.getDefaultMethodString().equals("Default Method")); }

    We’ve just implemented the functional interface!

    我们刚刚实现了功能接口!

    In the code above, we created three anonymous classes in different ways. Remember that the anonymous class has the behavior that we can create a functional interface with a lambda expression, method references, or constructor references.

    在上面的代码中,我们以不同的方式创建了三个匿名类。 请记住,匿名类的行为是我们可以使用lambda表达式,方法引用或构造函数引用创建功能接口。

    To make sure we created anonymous classes that behave the same, we assert every method in the interface.

    为了确保我们创建了行为相同的匿名类,我们在接口中声明了每个方法。

    Java 8中的内置功能接口 (Built-In Functional Interface in Java 8)

    Java 8 has many built-in functional interface classes in the java.util.function package that we can see in its documentation.

    Java 8在java.util.function包中具有许多内置的功能接口类,我们可以在其文档中看到。

    In this article, I will only explain four of the most commonly used functional interfaces, but if you’re interested in more, you can read it in the Java API documentation noted above.

    在本文中,我将仅解释四个最常用的功能接口,但是如果您对更多的功能感兴趣,可以在上面提到的Java API文档中阅读。

    Consumer<T>: A functional interface that accepts an object and returns nothing.

    Consumer<T> :一个接受对象且不返回任何内容的功能接口。

    Producer<T>: A functional interface that accepts nothing and returns an object.

    Producer<T> :不接受任何内容并返回对象的功能接口。

    Predicate<T>: A functional interface that accepts an object and returns a boolean.

    Predicate<T> :一个接受对象并返回布尔值的功能接口。

    Function<T, R>: A functional interface that accepts an object and returns another object.

    Function<T, R> :接受一个对象并返回另一个对象的功能接口。

    常用用法 (Common Usage)

    If you’ve been developing with Java a lot, then it’s likely you’ve met the concept of functional interface already.

    如果您经常使用Java进行开发,那么很可能已经遇到了功能接口的概念。

    流和可选API (Stream and optional API)

    Java’s Stream API uses functional interfaces a lot, as we can see in the code below.

    Java的Stream API大量使用功能接口,如下面的代码所示。

    @Test void commonFunctionalInterface() { Stream.of("Hello", "World", "How", "Are", "you") .filter(s -> s.equals("Hello") || s.equals("Are")) .map(s -> s + " String") .forEach(System.out::println); Optional.of("Hello") .filter(s -> s.equals("Hello") || s.equals("Are")) .map(s -> s + " String") .ifPresent(System.out::println); }

    The filter method has a parameter Predicate<T> functional interface. As we can see, the method accepts a String and produce a boolean.

    filter方法具有参数Predicate<T>功能接口。 如我们所见,该方法接受一个String并产生一个boolean 。

    The map method uses Function<T, R> as its parameter. It accepts a String and also returns String.

    map方法使用Function<T, R>作为其参数。 它接受String并返回String 。

    The forEach method in Stream and ifPresent method in Optional accept Consumer<T>, accepting a String and not returning anything.

    Stream中的forEach方法和ifPresent方法接受Consumer<T> ,接受String且不返回任何内容。

    React库 (Reactive library)

    Both of the most popular Java Reactive libraries, RxJava and Reactor, are based on Java 8 Streams API, which means they also use functional interfaces in their code.

    两种最流行的Java Reactive库RxJava和Reactor均基于Java 8 Streams API,这意味着它们还在代码中使用功能接口。

    If we look at Reactor’s Flux API documentation and RxJava’s Observable API documentation, we can see many of their methods accept a functional interface.

    如果我们查看Reactor的Flux API文档和RxJava的Observable API文档,我们可以看到它们的许多方法都接受一个功能接口。

    创建我们自己的流API (Creating Our Own Stream API)

    Now that we know how to create and use a functional interface, let’s try creating our own streaming API so we can understand how we can implement the functional interface.

    现在我们知道如何创建和使用功能接口,让我们尝试创建自己的流API,以便我们了解如何实现功能接口。

    Of course, our streaming API is much simpler than Java’s.

    当然,我们的流API比Java的简单得多。

    package com.example.functional.intf; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; public class SimpleStream<T> { private List<T> values; public SimpleStream(T... values) { this.values = Arrays.asList(values); } public SimpleStream(List<T> values) { this.values = values; } public SimpleStream<T> filter(Predicate<T> filter) { List<T> returnValueList = new ArrayList<>(); for (T value : values) { if (filter.test(value)) { returnValueList.add(value); } } this.values = returnValueList; return this; } public SimpleStream<T> map(Function<T, T> function) { List<T> returnValueList = new ArrayList<>(); for (T value : values) { returnValueList.add(function.apply(value)); } this.values = returnValueList; return this; } public void forEach(Consumer<T> consumer) { for (T value : values) { consumer.accept(value); } } public List<T> toList() { return this.values; } }

    And a test class:

    和一个测试班:

    @Test void implementingFunctionalInterface() { List<String> stringsFromSimpleStream = new SimpleStream<>("Hello", "World", "How", "Are", "you") .filter(s -> s.equals("Hello") || s.equals("Are")) .map(s -> s + " String") .toList(); assert(stringsFromSimpleStream.size() == 2); assert(stringsFromSimpleStream.get(0).equals("Hello String")); assert(stringsFromSimpleStream.get(1).equals("Are String")); new SimpleStream<>(stringsFromSimpleStream) .forEach(System.out::println); }

    Okay, let’s discuss the methods one by one.

    好吧,让我们一一讨论这些方法。

    建设者 (Constructor)

    We made two constructors, one constructor imitating the Stream.of() API and one constructor to convert List<T> to SimpleStream<T>.

    我们创建了两个构造函数,一个构造函数模仿Stream.of() API,另一个构造函数将List<T>转换为SimpleStream<T> 。

    过滤 (Filter)

    In this method, we accept Predicate<T> as a parameter since Predicate<T> has an abstract parameter named test that accepts an object and produces a boolean.

    在此方法中,我们接受Predicate<T>作为参数,因为Predicate<T>具有一个名为test的抽象参数,该抽象参数接受一个对象并产生一个布尔值。

    Let’s look at the test class, where we wrote:

    让我们看一下我们编写的测试类:

    .filter(s -> s.equals("Hello") || s.equals("Are"))

    This means we wrote an anonymous class implementing Predicate<T>:

    这意味着我们编写了一个实现Predicate<T>的匿名类:

    Predicate<String> filter = new Predicate<String>() { @Override public boolean test(String s) { return s.equals("Hello") || s.equals("Are"); } };

    So in the SimpleStream<T> class, we can see the filter method as:

    因此,在SimpleStream<T>类中,我们可以看到filter方法为:

    public SimpleStream<T> filter(Predicate<T> filter) { List<T> returnValueList = new ArrayList<>(); for (T value : values) { if (value.equals("Hello") || value.equals("Are")) { returnValueList.add(value); } } this.values = returnValueList; return this; }

    地图(Map)

    In the map method, we accept Function<T, R> as its parameter, which means the map method will accept a functional interface that accepts an object and also produces an object.

    在map方法中,我们接受Function<T, R>作为其参数,这意味着map方法将接受一个接受对象并生成对象的功能接口。

    We wrote the following in the test class:

    我们在测试类中编写了以下内容:

    .map(s -> s + " String")

    It’s the same as creating an anonymous class implementing Function<T, R>:

    与创建实现Function<T, R>的匿名类相同:

    Function<String, String> map = new Function<String, String>() { @Override public String apply(String s) { return s + " String"; } };

    And in the SimpleStream<T> class, we can see it as this:

    在SimpleStream<T>类中,我们可以这样看:

    public SimpleStream<T> map(Function<T, T> function) { List<T> returnValueList = new ArrayList<>(); for (T value : values) { returnValueList.add(value + " String"); } this.values = returnValueList; return this; }

    每次(forEach)

    The forEach method accepts Consumer<T> as its parameter, meaning that it will accept an object and return nothing.

    forEach方法接受Consumer<T>作为其参数,这意味着它将接受一个对象并且不返回任何内容。

    We wrote the following in the test class:

    我们在测试类中编写了以下内容:

    .forEach(System.out::println);

    This translates to creating an anonymous class implementing Consumer<T>:

    这转化为创建实现Consumer<T>的匿名类:

    Consumer<String> forEach = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } };

    In the SimpleStream<T>, we can see the forEach method, as below:

    在SimpleStream<T> ,我们可以看到forEach方法,如下所示:

    public void forEach(Consumer<T> consumer) { for (T value : values) { System.out.println(value); } }

    结论(Conclusion)

    With the release of Java 8 back in 2014, we can use a functional programming style in Java. Using a functional programming style in Java has many benefits, one of which is making your code shorter and more readable. With the benefits it provides, knowing the implementation of functional programming in Java if you’re a Java developer is a must!

    随着2014年Java 8的发布,我们可以使用Java中的函数式编程风格。 在Java中使用函数式编程风格有很多好处,其中之一就是使您的代码更短,更易读。 借助它提供的好处,如果您是Java开发人员,那么必须了解Java中的函数式编程实现!

    Thanks for reading this article!

    感谢您阅读本文!

    You can find the GitHub repository used for this article here:

    您可以在此处找到用于本文的GitHub存储库:

    资源资源 (Resources)

    https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html

    https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html

    https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html

    https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html

    https://www.amitph.com/java-method-and-constructor-reference/#:~:text=Constructor%20Reference%20is%20used%20to,assign%20to%20a%20target%20type.

    https://www.amitph.com/java-method-and-constructor-reference/#:~:text=Constructor%20Reference%20is%20used%20to,assign%20to%20a%20target%20type 。

    https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

    https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

    https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

    https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

    http://reactivex.io/RxJava/javadoc/

    http://reactivex.io/RxJava/javadoc/

    https://projectreactor.io/docs/core/release/api/

    https://projectreactor.io/docs/core/release/api/

    翻译自: https://medium.com/better-programming/functional-programming-in-java-explained-ae396e9e516f

    java编程实现思想讲解

    相关资源:headFirst java核心技术 java编程思想
    Processed: 0.010, SQL: 9