ホームページ Java &#&チュートリアル Java Lambda式の詳しい説明とサンプルコード

Java Lambda式の詳しい説明とサンプルコード

Jan 23, 2017 pm 01:24 PM
Javaラムダ式

Java ラムダ式は、Java 8 で導入された新機能です。これは、関数型プログラミングをシミュレートするための構文糖衣と言えますが、JavaScript のクロージャに似ていますが、主な目的は、Simplify に関数型構文を提供することです。私たちのコーディング。

Lambdaの基本構文

Lambdaの基本的な構造は、(arguments)->bodyとなります。

パラメータの型が推定できる場合、(など)の型を指定する必要はありません。 a) -> System.out.println(a)

パラメータが 1 つしかなく、型が推定できる場合は、->out.println(a) のように () を記述する必要はありません。 )

パラメータで型を指定する場合は、(int a ) -> System.out.println(a) のように括弧が必要です

パラメータは () -> のように空にすることもできます。 .println("hello")

bodyにはステートメントが1つしかない場合は{}を使ってステートメントを含める必要があります

一般的な書き方は以下の通りです

(a) -> a * a
(int a, int b) -> a + b
(a, b) -> {return a - b;}
() -> System.out.println() .getId())

FunctionalInterfaceFunctionalInterface

Concept

Java Lambda 式は関数インターフェイスに基づいています。関数型インターフェース(FunctionalInterface)とは何ですか? 簡単に言えば、このタイプのインターフェイスの目的は 1 つのメソッド (関数) のみであり、1 つの関数に相当します。 Runnable や Comparator などの一般的なインターフェイスは関数インターフェイスであり、@FunctionalInterface の注釈が付けられます。

理解しやすいように、スレッドを例として取り上げます。 Runnable インターフェイスは、スレッド プログラミングで一般的に使用されるインターフェイスであり、スレッドの実行ロジックである void run() メソッドが含まれています。前の構文によると、新しいスレッドを作成するときは、次のように Runnable 匿名クラスを使用することが一般的です。

new Thread(new Runnable() {
  @Override
  public void run() {
    System.out.println(Thread.currentThread().getId());
  }
 
}).start();
ログイン後にコピー

あまり書きすぎると退屈になりますが、Lambda ベースの記述方法は簡潔になり、次のようにクリアします:

new Thread(() -> System.out.println(Thread.currentThread().getId())).start();

Thread のパラメータに注意してください。 Runnable の実装は、以下のように書かれた一文で実現されます

Runnable r = () -> System.out.println(Thread.currentThread().getId());
new Thread(r).start( );

Lambdaの目的はもちろん簡単に書けるだけでなく、高次の目的も気づいたらまとめられます。

コンパレータの別の例を見てください。従来の記述方法によれば、次のようになります。

Integer[] a = {1, 8, 3, 9, 2, 0, 5};
Arrays.sort(a, new Comparator<Integer>() {
  @Override
  public int compare(Integer o1, Integer o2) {
    return o1 - o2;
  }
});
ログイン後にコピー

ラムダ式は次のように記述されます:

Integer[] a = {1, 8, 3, 9, 2, 0, 5} ;
Arrays.sort(a, (o1, o2) -> o1 - o2);

JDKの関数インターフェース

既存のクラスライブラリがラムダ式を直接使用するために、いくつかのものが存在しましたJava 8 より前 インターフェースは関数インターフェースとしてマークされています:

java.lang.Runnable

java.util.Comparator

java.util.concurrent.Callable

java.io.FileFilter

java.security.PrivilegedAction

java .beans.PropertyChangeListener

Java 8 では、一般的に使用される関数インターフェイスを提供する新しいパッケージ java.util.function が追加されました。 , U, R> - 関数: 入力 T と U と出力 R オブジェクト

- アサーション/判定: 入力 T と出力 boolean

BiPredicate - アサーション/判定: 入力 T と U 出力boolean

Supplier - プロデューサー: 入力なし、出力 T

Consumer - コンシューマー: 入力 T、出力なし

BiConsumer - コンシューマー: 入力 T および U 出力なし

UnaryOperator< T> - 単位演算: 入力 T、出力 T

BinaryOperator - バイナリ演算: 入力 T と T、出力 T

さらに、以下を含む、より具体的な関数とインターフェイスが追加されます。 DoubleBinaryOperator、DoubleConsumer、DoubleFunction、DoublePredicate、DoubleSupplier、DoubleToIntFunction、DoubleToLongFunction、DoubleUnaryOperator、IntBinaryOperator、IntConsumer、IntFunction、IntPredicate、IntSupplier、IntToDoubleFunction、IntToLongFunction、IntUnary 演算子、LongBinaryOperator、 LongFunction、LongPredicate、 LongSupplier、LongToDoubleFunction、LongToIntFunction、LongUnaryOperator、ToDoubleBiFunction、ToDoubleFunction、ToIntBiFunction、ToIntFunction、ToLongBiFunction、ToL ongFunction上記の関数型インターフェイスと組み合わせると、これらの基本的なタイプの関数型インターフェイスの機能がクラス名から一目でわかります。


関数型インターフェイスを作成する

場合によっては、関数型インターフェイスを自分で実装する必要があります。この方法も非常に簡単です。まず、このインターフェイスに関数操作が 1 つだけ含まれていることを確認し、そのインターフェイスに @FunctionalInterface の注釈を付ける必要があります。タイプ。

型導出

型導出はラムダ式の基礎であり、型導出のプロセスはラムダ式のコンパイルプロセスです。次のコードを例として挙げます:

Function strToInt = str -> Integer.parseInt(str);
编译期间,我理解的类型推导的过程如下:

先确定目标类型 Function

Function 作为函数式接口,其方法签名为:Integer apply(String t)

检测 str -> Integer.parseInt(str) 是否与方法签名匹配(方法的参数类型、个数、顺序 和返回值类型)

如果不匹配,则报编译错误

这里的目标类型是关键,通过目标类型获取方法签名,然后和 Lambda 表达式做出对比。

方法引用

方法引用(Method Reference)的基础同样是函数式接口,可以直接作为函数式接口的实现,与 Lambda 表达式有相同的作用,同样依赖于类型推导。方法引用可以看作是只调用一个方法的 Lambda 表达式的简化。

方法引用的语法为: Type::methodName 或者 instanceName::methodName , 构造函数对应的 methodName 为 new。

例如上面曾用到例子:

Function strToInt = str -> Integer.parseInt(str);

对应的方法引用的写法为

Function strToInt = Integer::parseInt;

根据方法的类型,方法引用主要分为一下几种类型,构造方法引用、静态方法引用、实例上实例方法引用、类型上实例方法引用等

构造方法引用

语法为: Type::new 。 如下面的函数为了将字符串转为数组

方法引用写法

Function strToInt = Integer::new;

Lambda 写法

Function strToInt = str -> new Integer(str);

传统写法

Function<String, Integer> strToInt = new Function<String, Integer>() {
  @Override
  public Integer apply(String str) {
    return new Integer(str);
  }
};
ログイン後にコピー

数组构造方法引用

语法为: Type[]::new 。如下面的函数为了构造一个指定长度的字符串数组

方法引用写法

Function fixedArray = String[]::new;

方法引用写法

Function fixedArray = length -> new String[length];

传统写法

Function<Integer, String[]> fixedArray = new Function<Integer, String[]>() {
  @Override
  public String[] apply(Integer length) {
    return new String[length];
  }
};
ログイン後にコピー

静态方法引用

语法为: Type::new 。 如下面的函数同样为了将字符串转为数组

方法引用写法

Function strToInt = Integer::parseInt;

Lambda 写法

Function strToInt = str -> Integer.parseInt(str);

传统写法

Function<String, Integer> strToInt = new Function<String, Integer>() {
  @Override
  public Integer apply(String str) {
    return Integer.parseInt(str);
  }
};
ログイン後にコピー

实例上实例方法引用

语法为: instanceName::methodName 。如下面的判断函数用来判断给定的姓名是否在列表中存在

List names = Arrays.asList(new String[]{"张三", "李四", "王五"});
Predicate checkNameExists = names::contains;
System.out.println(checkNameExists.test("张三"));
System.out.println(checkNameExists.test("张四"));

类型上实例方法引用

语法为: Type::methodName 。运行时引用是指上下文中的对象,如下面的函数来返回字符串的长度

Function<String, Integer> calcStrLength = String::length;
System.out.println(calcStrLength.apply("张三"));
List<String> names = Arrays.asList(new String[]{"zhangsan", "lisi", "wangwu"});
names.stream().map(String::length).forEach(System.out::println);<br>
ログイン後にコピー

又比如下面的函数已指定的分隔符分割字符串为数组

BiFunction split = String::split;
String[] names = split.apply("zhangsan,lisi,wangwu", ",");
System.out.println(Arrays.toString(names));

Stream 对象

概念

什么是 Stream ? 这里的 Stream 不同于 io 中的 InputStream 和 OutputStream,Stream 位于包 java.util.stream 中, 也是 java 8 新加入的,Stream 只的是一组支持串行并行聚合操作的元素,可以理解为集合或者迭代器的增强版。什么是聚合操作?简单举例来说常见的有平均值、最大值、最小值、总和、排序、过滤等。

Stream 的几个特征:

单次处理。一次处理结束后,当前Stream就关闭了。
支持并行操作
常见的获取 Stream 的方式

从集合中获取

Collection.stream();
Collection.parallelStream();

静态工厂

Arrays.stream(array)
Stream.of(T …)
IntStream.range()
这里只对 Stream 做简单的介绍,下面会有具体的应用。要说 Stream 与 Lambda 表达式有什么关系,其实并没有什么特别紧密的关系,只是 Lambda 表达式极大的方便了 Stream 的使用。如果没有 Lambda 表达式,使用 Stream 的过程中会产生大量的匿名类,非常别扭。

举例

以下的demo依赖于 Employee 对象,以及由 Employee 对象组成的 List 对象。

public class Employee {
 
  private String name;
  private String sex;
  private int age;
 
  public Employee(String name, String sex, int age) {
    super();
    this.name = name;
    this.sex = sex;
    this.age = age;
  }
  public String getName() {
    return name;
  }
 
  public String getSex() {
    return sex;
  }
  public int getAge() {
    return age;
  }
  @Override
  public String toString() {
    StringBuilder builder = new StringBuilder();
    builder.append("Employee {name=").append(name).append(", sex=").append(sex).append(", age=").append(age)
        .append("}");
    return builder.toString();
  }
}
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("张三", "男", 25));
employees.add(new Employee("李四", "女", 24));
employees.add(new Employee("王五", "女", 23));
employees.add(new Employee("周六", "男", 22));
employees.add(new Employee("孙七", "女", 21));
employees.add(new Employee("刘八", "男", 20));
ログイン後にコピー

打印所有员工

Collection 提供了 forEach 方法,供我们逐个操作单个对象。

employees.forEach(e -> System.out.println(e));
或者
employees.stream().forEach(e -> System.out.println(e));

按年龄排序

Collections.sort(employees, (e1, e2) -> e1.getAge() - e2.getAge());
employees.forEach(e -> System.out.println(e));
或者
employees.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).forEach(e -> System.out.println(e));
打印年龄最大的女员工

max/min 返回指定排序条件下最大/最小的元素

Employee maxAgeFemaleEmployee = employees.stream()
    .filter(e -> "女".equals(e.getSex()))
    .max((e1, e2) -> e1.getAge() - e2.getAge())
    .get();
System.out.println(maxAgeFemaleEmployee);
ログイン後にコピー

打印出年龄大于20 的男员工

filter 可以过滤出符合条件的元素

employees.stream()
.filter(e -> e.getAge() > 20 && "男".equals(e.getSex()))
.forEach(e -> System.out.println(e));
打印出年龄最大的2名男员工

limit 方法截取有限的元素

employees.stream()
    .filter(e -> "男".equals(e.getSex()))
    .sorted((e1, e2) -> e2.getAge() - e1.getAge())
    .limit(2)
    .forEach(e -> System.out.println(e));
ログイン後にコピー

打印出所有男员工的姓名,使用 , 分隔

map 将 Stream 中所有元素的执行给定的函数后返回值组成新的 Stream

String maleEmployeesNames = employees.stream()
    .map(e -> e.getName())
    .collect(Collectors.joining(","));
System.out.println(maleEmployeesNames);
ログイン後にコピー

统计信息

IntSummaryStatistics, DoubleSummaryStatistics, LongSummaryStatistics 包含了 Stream 中的汇总数据。

IntSummaryStatistics stat = employees.stream()
    .mapToInt(Employee::getAge).summaryStatistics();
System.out.println("员工总数:" + stat.getCount());
System.out.println("最高年龄:" + stat.getMax());
System.out.println("最小年龄:" + stat.getMin());
System.out.println("平均年龄:" + stat.getAverage());
ログイン後にコピー

   

总结

Lambda 表达式确实可以减少很多代码,能提高生产力,当然也有弊端,就是复杂的表达式可读性会比较差,也可能是还不是很习惯的缘故吧,如果习惯了,相信会喜欢上的。凡事都有两面性,就看我们如何去平衡这其中的利弊了,尤其是在一个团队中。

以上就是对Java8 JavaLambda 的资料整理,后续继续补充相关资料谢谢大家对本站的支持!

更多Java Lambda 表达式详解及示例代码相关文章请关注PHP中文网!

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか? Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか? Mar 17, 2025 pm 05:35 PM

Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか? カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか? Mar 17, 2025 pm 05:44 PM

この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか? キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか? Mar 17, 2025 pm 05:43 PM

この記事では、キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPAを使用することについて説明します。潜在的な落とし穴を強調しながら、パフォーマンスを最適化するためのセットアップ、エンティティマッピング、およびベストプラクティスをカバーしています。[159文字]

高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか? 高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか? Mar 17, 2025 pm 05:46 PM

この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか? 適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか? Mar 17, 2025 pm 05:45 PM

この記事では、MavenやGradleなどのツールを使用して、適切なバージョン化と依存関係管理を使用して、カスタムJavaライブラリ(JARファイル)の作成と使用について説明します。

See all articles