Lambda表达式的类型

lambda表达式本身没有特定类型。
虽然参数的类型和数量是如此,以及返回值的类型可以传达某些类型的信息,但这些信息只会

  • 约束它可以分配的类型。 Lambda在以下方式之一以以下方式分配给功能接口类型时,Lambda会收到类型:
  • 直接分配给功能类型,例如mypredicate = s - > s.isempty()
  • 将其传递为具有功能类型的参数,例如, Stream.Filter(S - > S.Isempty())
  • 从返回函数类型的函数返回它,例如,返回s - > s.isempty()

在对函数类型进行任何此类赋值之前,lambda没有确定的类型。为了说明,考虑lambda表达式O-> O.ISUNTY()。相同的lambda表达式可以分配给许多不同的函数类型:

Predicate<String> javaStringPred = o -> o.isEmpty();
Function<String>, javaFunc = o -> o.isEmpty();
Predicate<List> javaListPred = o -> o.isEmpty();
Consumer<String> javaStringConsumer = o -> o.isEmpty(); //return value is ignored!
com.google.common.base.Predicate guavaPredicate = o -> o.isEmpty();

既然分配了它们,那么所示的示例是完全不同的类型,即使lambda表达式看起来是相同的,它们也不能相互分配。

使用Lambda表达式对集合排序

排序列表

在Java 8之前,有必要在排序列表1时使用匿名(或者命名)类实现java.util.Comparator接口:

List people = …
Collections.sort(
     people,
     new Comparator() {
         public int compare(Person p1, Person p2){
             return p1.getFirstName().compareTo(p2.getFirstName());
         }
     }
);

版本≥javase 1.2

Collections.sort(
     people,
     (p1, p2) -> p1.getFirstName().compareTo(p2.getFirstName())
);

从Java 8开始,可以用Lambda表达式替换匿名类。
请注意,可以遗漏参数P1和P2的类型,因为编译器将自动推断出来:

Collections.sort(
    people,
    Comparator.comparing(Person::getFirstName)
);

通过使用比较器,可以简化该示例.Comparing和方法引用使用::表示

import static java.util.Collections.sort;
import static java.util.Comparator.comparing;
//…
sort(people, comparing(Person::getFirstName));

静态导入允许我们更简单地表达这一点,但这是值得易于改进的整体可读性:

sort(people, comparing(Person::getFirstName).thenComparing(Person::getLastName));

也可以将比较器建成的,也可以将这种方式连接在一起。
例如,在通过他们的名字比较人们之后,如果有人的名字,左上一名称的Thencomparing方法也比较:

注意集合.sort(...)仅适用于列表子类型的集合。
集合和集合API并不意味着元素的任何排序。

排序map

您可以用类似的方式按值对HashMap的条目进行排序(请注意,LinkedHashMap必须用作目标。普通HashMap中的键是无序的。)

Map map = new HashMap(); //… or any other Map class
//populate the map
map = map.entrySet()
     .stream()
     .sorted(Map.Entry.comparingByValue())
     .collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue(),
              (k, v) -> k, LinkedHashMap::new));

Java Lambdas简介

功能接口

Lambdas只能在功能接口上运行,这是一个只有一个抽象方法的接口。
功能接口可以具有任何数量的默认或者静态方法。
(因此,它们有时被称为单个抽象方法接口或者SAM接口)。

interface Foo1 {
void bar();
}
interface Foo2 {
int bar(boolean baz);
}
interface Foo3 {
String bar(Object baz, int mink);
}
interface Foo4 {
     default String bar() { //default so not counted
          return "baz";
     }
     void quux();
}

在声明功能接口时,可以添加@FunctionalInterface注释。
这没有特殊效果,但如果该注释应用于不起作用的接口,则将生成编译器错误,从而提醒接口不应更改接口。

@FunctionalInterface
interface Foo5 {
    void bar();
}
@FunctionalInterface
interface BlankFoo1 extends Foo3 { //inherits abstract method from Foo3
}
@FunctionalInterface
interface Foo6 {
     void bar();
     boolean equals(Object obj); //overrides one of Object's method so not counted
}

相反,这不是功能接口,因为它具有多个抽象方法:

interface BadFoo {
     void bar();
     void quux(); //<-- Second method prevents lambda: which one should
           //be considered as lambda?
}

这也不是功能接口,因为它没有任何方法:

interface BlankFoo2 { }

注意以下内容。
假设你有

interface Parent { public int parentMethod(); }

interface Child extends Parent { public int ChildMethod(); }

然后,由于它具有两种指定方法,因此不能成为功能接口。

Java 8还提供了包java.util.function中的许多通用模板功能接口。
例如,内置接口谓词软件包一个方法,该方法输入T型值并返回布尔值。

lambda表达式

Lambda表达的基本结构是:

然后将保存一个类的单例实例,类似于匿名类,它实现了functionalinterface,其中一个方法的定义是{system.out.println(“hello”); }。
其他
单词,以上大多等同于:

FunctionalInterface fi = new FunctionalInterface() {
      @Override
      public void theOneMethod() {
           System.out.println("Hello");
      }
};

λ只有“大多数等效”到匿名类,因为在一个lambda中,如此,super或者toString()的表达式的含义引用了分配所发生的类,而不是新创建的
目的。

我们无法在使用lambda时指定方法的名称 - 但我们不应该需要,因为功能接口必须只有一个抽象方法,因此Java覆盖了那个。

在Lambda的类型不确定的情况下,(例如,过载方法)我们可以将演员添加到Lambda,以告诉编译器应该是什么,如:

Object fooHolder = (Foo1) () -> System.out.println("Hello");
System.out.println(fooHolder instanceof Foo1); //returns true

如果功能接口的单个方法采用参数,则应在Lambda的括号之间出现本地正式名称。
没有必要声明参数或者返回的类型
取自接口(虽然如果我们想要声明参数类型并非错误)。
因此,这两个例子是等同的:

Foo2 longFoo = new Foo2() {
      @Override
      public int bar(boolean baz) {
            return baz ? 1 : 0;
      }
};
Foo2 shortFoo = (x) -> { return x ? 1 : 0; };

如果函数只有一个参数,则可以省略周围参数周围的括号:

Foo2 np = x -> { return x ? 1 : 0; }; //okay
Foo3 np2 = x, y -> x.toString() + y //not okay

隐含返回值

如果放置在Lambda中的代码是Java表达式而不是语句,则将其视为返回表达式值的方法。
因此,以下两个是等同的:

IntUnaryOperator addOneShort = (x) -> (x + 1);
IntUnaryOperator addOneLong = (x) -> { return (x + 1); };

访问本地变量(值闭合)

由于Lambdas是匿名类的语法速记,因此它们遵循相同的规则来访问封闭范围中的局部变量;变量必须被视为最终且未在Lambda内修改。

IntUnaryOperator makeAdder(int amount) {
     return (x) -> (x + amount); //Legal even though amount will go out of scope
                                 //because amount is not modified
}
IntUnaryOperator makeAccumulator(int value) {
     return (x) -> { value += x; return value; }; //Will not compile
}

如果有必要以这种方式缠绕变化变量,则应使用保持变量副本的常规对象。
阅读更多用Lambda表达式的Java Closes。

因为Lambda是一个接口的实现,所以没有完成任何特殊的东西来使方法接受一个lambda:任何采用功能接口的功能也可以接受一个lambda。

接受lambdas.

public void passMeALambda(Foo1 f) { 
f.bar(); 
} 
passMeALambda(() -> System.out.println("Lambda called"));
java中什么是lambda表达式

Lambda表达式提供了一种使用表达式实现单个方法接口的清晰简洁的方法。它们允许您减少必须创建和维护的代码量。虽然类似于匿名类,但它们本身没有类型信息。需要进行类型推断。
方法引用使用现有方法而不是表达式实现函数接口。它们也属于lambda家族。

日期:2020-06-02 22:15:23 来源:oir作者:oir