功能接口 java8_Java 8功能接口

功能接口 java8

Welcome to the Java 8 functional interfaces example tutorial. Java has always been an Object Oriented Programming language. What is means that everything in java programming revolves around Objects (except some primitive types for simplicity). We don’t have only functions in java, they are part of Class and we need to use the class/object to invoke any function.

欢迎使用Java 8功能接口示例教程。 Java一直是面向对象的编程语言。 这意味着Java编程中的所有内容都围绕对象(为简单起见,某些基本类型除外)。 我们在Java中不仅只有函数,它们是Class的一部分,我们需要使用class / object来调用任何函数。

Java 8功能接口 (Java 8 Functional Interfaces)

java 8 functional interfaces

If we look into some other programming languages such as C++, JavaScript; they are called functional programming language because we can write functions and use them when required. Some of these languages support Object Oriented Programming as well as Functional Programming.


如果我们研究其他编程语言,例如C ++,JavaScript; 它们被称为函数式编程语言,因为我们可以编写函数并在需要时使用它们。 这些语言中的某些语言支持面向对象的编程以及函数式编程。

Being object oriented is not bad, but it brings a lot of verbosity to the program. For example, let’s say we have to create an instance of Runnable. Usually we do it using anonymous classes like below.

面向对象还不错,但是它给程序带来了很多冗长的细节。 例如,假设我们必须创建一个Runnable实例。 通常,我们使用如下所示的匿名类来执行此操作。

Runnable r = new Runnable(){
			@Override
			public void run() {
				System.out.println("My Runnable");
			}};

If you look at the above code, the actual part that is of use is the code inside run() method. Rest all of the code is because of the way java programs are structured.

如果看上面的代码,实际使用的部分是run()方法中的代码。 剩下的所有代码都是由于Java程序的结构方式。

Java 8 Functional Interfaces and Lambda Expressions help us in writing smaller and cleaner code by removing a lot of boiler-plate code.

Java 8功能接口和Lambda表达式通过删除许多样板代码来帮助我们编写更小巧,更简洁的代码。

Java 8功能接口 (Java 8 Functional Interface)

An interface with exactly one abstract method is called Functional Interface. @FunctionalInterface annotation is added so that we can mark an interface as functional interface.

具有唯一一种抽象方法的接口称为功能接口。 添加了@FunctionalInterface批注,以便我们可以将接口标记为功能接口。

It is not mandatory to use it, but it’s best practice to use it with functional interfaces to avoid addition of extra methods accidentally. If the interface is annotated with @FunctionalInterface annotation and we try to have more than one abstract method, it throws compiler error.

使用它不是强制性的,但是最好的做法是将其与功能接口一起使用,以避免意外添加其他方法。 如果接口使用@FunctionalInterface注释进行注释,并且我们尝试使用多个抽象方法,则它将引发编译器错误。

The major benefit of java 8 functional interfaces is that we can use lambda expressions to instantiate them and avoid using bulky anonymous class implementation.

Java 8功能接口的主要好处是我们可以使用lambda表达式实例化它们,并避免使用笨重的匿名类实现。

Java 8 Collections API has been rewritten and new Stream API is introduced that uses a lot of functional interfaces. Java 8 has defined a lot of functional interfaces in java.util.function package. Some of the useful java 8 functional interfaces are Consumer, Supplier, Function and Predicate.

Java 8 Collections API已被重写,并且引入了使用许多功能接口的新Stream API。 Java 8在java.util.function包中定义了许多功能接口。 一些有用的java 8功能接口是ConsumerSupplierFunctionPredicate

You can find more detail about them in Java 8 Stream Example.

您可以在Java 8 Stream Example中找到有关它们的更多详细信息。

java.lang.Runnable is a great example of functional interface with single abstract method run().

java.lang.Runnable是具有单个抽象方法run()的功能接口的一个很好的示例。

Below code snippet provides some guidance for functional interfaces:

下面的代码片段为功能接口提供了一些指导:

interface Foo { boolean equals(Object obj); }
// Not functional because equals is already an implicit member (Object class)

interface Comparator<T> {
 boolean equals(Object obj);
 int compare(T o1, T o2);
}
// Functional because Comparator has only one abstract non-Object method

interface Foo {
  int m();
  Object clone();
}
// Not functional because method Object.clone is not public

interface X { int m(Iterable<String> arg); }
interface Y { int m(Iterable<String> arg); }
interface Z extends X, Y {}
// Functional: two methods, but they have the same signature

interface X { Iterable m(Iterable<String> arg); }
interface Y { Iterable<String> m(Iterable arg); }
interface Z extends X, Y {}
// Functional: Y.m is a subsignature & return-type-substitutable

interface X { int m(Iterable<String> arg); }
interface Y { int m(Iterable<Integer> arg); }
interface Z extends X, Y {}
// Not functional: No method has a subsignature of all abstract methods

interface X { int m(Iterable<String> arg, Class c); }
interface Y { int m(Iterable arg, Class<?> c); }
interface Z extends X, Y {}
// Not functional: No method has a subsignature of all abstract methods

interface X { long m(); }
interface Y { int m(); }
interface Z extends X, Y {}
// Compiler error: no method is return type substitutable

interface Foo<T> { void m(T arg); }
interface Bar<T> { void m(T arg); }
interface FooBar<X, Y> extends Foo<X>, Bar<Y> {}
// Compiler error: different signatures, same erasure

Lambda表达 (Lambda Expression)

Lambda Expression are the way through which we can visualize functional programming in the java object oriented world. Objects are the base of java programming language and we can never have a function without an Object, that’s why Java language provide support for using lambda expressions only with functional interfaces.

Lambda Expression是我们可以在Java面向对象的世界中可视化函数编程的方式。 对象是Java编程语言的基础,没有对象,我们永远无法拥有函数,这就是Java语言提供对仅通过函数接口使用lambda表达式的支持的原因。

Since there is only one abstract function in the functional interfaces, there is no confusion in applying the lambda expression to the method. Lambda Expressions syntax is (argument) -> (body). Now let’s see how we can write above anonymous Runnable using lambda expression.

由于功能接口中只有一个抽象函数,因此在将lambda表达式应用于该方法时不会造成混淆。 Lambda Expressions语法为(参数)->(body) 。 现在,让我们看看如何使用lambda表达式在匿名Runnable之上编写代码。

Runnable r1 = () -> System.out.println("My Runnable");

Let’s try to understand what is happening in the lambda expression above.

让我们尝试了解上面的lambda表达式中发生了什么。

  • Runnable is a functional interface, that’s why we can use lambda expression to create it’s instance.

    Runnable是一个功能性的接口,这就是为什么我们可以使用lambda表达式创建其实例的原因。
  • Since run() method takes no argument, our lambda expression also have no argument.

    由于run()方法没有参数,因此我们的lambda表达式也没有参数。
  • Just like if-else blocks, we can avoid curly braces ({}) since we have a single statement in the method body. For multiple statements, we would have to use curly braces like any other methods.

    就像if-else块一样,我们可以避免使用花括号({}),因为方法主体中只有一条语句。 对于多个语句,我们必须像其他任何方法一样使用花括号。

为什么我们需要Lambda表达式 (Why do we need Lambda Expression)

  1. Reduced Lines of Code
    One of the clear benefit of using lambda expression is that the amount of code is reduced, we have already seen that how easily we can create instance of a functional interface using lambda expression rather than using anonymous class.

    减少代码行
    使用lambda表达式的明显好处之一是减少了代码量,我们已经看到,使用lambda表达式而不是使用匿名类可以轻松创建功能接口的实例。
  2. Sequential and Parallel Execution Support

    Another benefit of using lambda expression is that we can benefit from the Stream API sequential and parallel operations support.

    To explain this, let’s take a simple example where we need to write a method to test if a number passed is prime number or not.

    Traditionally we would write it’s code like below. The code is not fully optimized but good for example purpose, so bear with me on this.

    //Traditional approach
    private static boolean isPrime(int number) {		
    	if(number < 2) return false;
    	for(int i=2; i<number; i++){
    		if(number % i == 0) return false;
    	}
    	return true;
    }

    The problem with above code is that it’s sequential in nature, if the number is very huge then it will take significant amount of time. Another problem with code is that there are so many exit points and it’s not readable. Let’s see how we can write the same method using lambda expressions and stream API.

    IntStream is a sequence of primitive int-valued elements supporting sequential and parallel aggregate operations. This is the int primitive specialization of Stream.

    For more readability, we can also write the method like below.

    private static boolean isPrime(int number) {
    	IntPredicate isDivisible = index -> number % index == 0;
    	
    	return number > 1
    			&& IntStream.range(2, number).noneMatch(
    					isDivisible);
    }

    If you are not familiar with IntStream, it’s range() method returns a sequential ordered IntStream from startInclusive (inclusive) to endExclusive (exclusive) by an incremental step of 1.

    noneMatch() method returns whether no elements of this stream match the provided predicate. It may not evaluate the predicate on all elements if not necessary for determining the result.

    顺序和并行执行支持

    使用lambda表达式的另一个好处是,我们可以受益于Stream API的顺序和并行操作支持。

    为了说明这一点,让我们举一个简单的示例,在此示例中,我们需要编写一种方法来测试传递的数字是否为质数。

    传统上,我们将像下面这样编写它的代码。 代码尚未完全优化,但是仅出于示例目的,因此请耐心等待。

    上面的代码的问题在于它本质上是顺序的,如果数量很大,那么将花费大量时间。 代码的另一个问题是出口点太多,而且不可读。 让我们看看如何使用lambda表达式和流API编写相同的方法。

    //Declarative approach
    private static boolean isPrime(int number) {		
    	return number > 1
    			&& IntStream.range(2, number).noneMatch(
    					index -> number % index == 0);
    }

    IntStream是一系列原始整数值元素,它们支持顺序和并行聚合操作。 这是Stream的int原始专业化。

    为了提高可读性,我们还可以像下面这样编写方法。

    如果您不熟悉IntStream,则它的range()方法以1的增量步长从startInclusive(包括)向endExclusive(排除)返回顺序的有序IntStream。

    noneMatch()方法返回此流中是否没有元素与提供的谓词匹配。 如果不一定要确定结果,则可能不会评估所有元素上的谓词。

  3. Passing Behaviors into methods

    Let’s see how we can use lambda expressions to pass behavior of a method with a simple example. Let’s say we have to write a method to sum the numbers in a list if they match a given criteria. We can use Predicate and write a method like below.

    public static int sumWithCondition(List<Integer> numbers, Predicate<Integer> predicate) {
    	    return numbers.parallelStream()
    	    		.filter(predicate)
    	    		.mapToInt(i -> i)
    	    		.sum();
    	}

    Sample usage:

    将行为传递给方法

    让我们看看如何使用lambda表达式通过一个简单的示例传递方法的行为。 假设我们必须编写一种方法来对列表中的数字进行匹配(如果它们符合给定的条件)。 我们可以使用谓词并编写如下的方法。

    public static int sumWithCondition(List<Integer> numbers, Predicate<Integer> predicate) {
    	    return numbers.parallelStream()
    	    		.filter(predicate)
    	    		.mapToInt(i -> i)
    	    		.sum();
    	}

    用法示例:

  4. Higher Efficiency with Laziness

    One more advantage of using lambda expression is the lazy evaluation, for example let’s say we need to write a method to find out the maximum odd number in the range 3 to 11 and return square of it.

    Usually we will write code for this method like this:

    private static int findSquareOfMaxOdd(List<Integer> numbers) {
    		int max = 0;
    		for (int i : numbers) {
    			if (i % 2 != 0 && i > 3 && i < 11 && i > max) {
    				max = i;
    			}
    		}
    		return max * max;
    	}

    Above program will always run in sequential order but we can use Stream API to achieve this and get benefit of Laziness-seeking. Let’s see how we can rewrite this code in functional programming way using Stream API and lambda expressions.

    If you are surprised with the double colon (::) operator, it’s introduced in Java 8 and used for method references. Java Compiler takes care of mapping the arguments to the called method. It’s short form of lambda expressions i -> isGreaterThan3(i) or i -> NumberTest.isGreaterThan3(i).

    懒惰提高效率

    使用lambda表达式的另一个优势是惰性求值,例如,我们需要编写一种方法来找出3到11范围内的最大奇数并返回其平方。

    通常,我们将为这种方法编写如下代码:

    private static int findSquareOfMaxOdd(List<Integer> numbers) {
    		int max = 0;
    		for (int i : numbers) {
    			if (i % 2 != 0 && i > 3 && i < 11 && i > max) {
    				max = i;
    			}
    		}
    		return max * max;
    	}

    上面的程序将始终按顺序运行,但是我们可以使用Stream API来实现这一点并从懒惰寻求中受益。 让我们看看如何使用Stream API和lambda表达式以功能编程的方式重写此代码。

    如果您对双冒号(::)运算符感到惊讶,它是Java 8中引入的,可用于方法参考 。 Java编译器负责将参数映射到被调用的方法。 它是Lambda表达式i -> isGreaterThan3(i)i -> NumberTest.isGreaterThan3(i) i -> isGreaterThan3(i)

Lambda表达式示例 (Lambda Expression Examples)

Below I am providing some code snippets for lambda expressions with small comments explaining them.

下面,我为lambda表达式提供了一些代码片段,并附有一些小注释来解释它们。

() -> {}                     // No parameters; void result

() -> 42                     // No parameters, expression body
() -> null                   // No parameters, expression body
() -> { return 42; }         // No parameters, block body with return
() -> { System.gc(); }       // No parameters, void block body

// Complex block body with multiple returns
() -> {
  if (true) return 10;
  else {
    int result = 15;
    for (int i = 1; i < 10; i++)
      result *= i;
    return result;
  }
}                          

(int x) -> x+1             // Single declared-type argument
(int x) -> { return x+1; } // same as above
(x) -> x+1                 // Single inferred-type argument, same as below
x -> x+1                   // Parenthesis optional for single inferred-type case

(String s) -> s.length()   // Single declared-type argument
(Thread t) -> { t.start(); } // Single declared-type argument
s -> s.length()              // Single inferred-type argument
t -> { t.start(); }          // Single inferred-type argument

(int x, int y) -> x+y      // Multiple declared-type parameters
(x,y) -> x+y               // Multiple inferred-type parameters
(x, final y) -> x+y        // Illegal: can't modify inferred-type parameters
(x, int y) -> x+y          // Illegal: can't mix inferred and declared types

方法和构造方法参考 (Method and Constructor References)

A method reference is used to refer to a method without invoking it; a constructor reference is similarly used to refer to a constructor without creating a new instance of the named class or array type.

方法引用用于引用方法而不调用它。 类似地,构造函数引用用于引用构造函数,而无需创建命名类或数组类型的新实例。

Examples of method and constructor references:

方法和构造函数引用的示例:

System::getProperty
System.out::println
"abc"::length
ArrayList::new
int[]::new

That’s all for Java 8 Functional Interfaces and Lambda Expression Tutorial. I would strongly suggest to look into using it because this syntax is new to Java and it will take some time to grasp it.

Java 8功能接口和Lambda表达式教程就这些了。 我强烈建议您研究使用它,因为该语法是Java的新知识,需要花费一些时间来掌握它。

You should also check out Java 8 Features to learn about all the improvements and changes in Java 8 release.

您还应该查看Java 8功能,以了解Java 8版本中的所有改进和更改。

翻译自: https://www.journaldev.com/2763/java-8-functional-interfaces

功能接口 java8

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值