成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊 Java8 函數接口

開發 前端
本文主要演示了Java 8 API中的不同功能的函數接口,這些接口可以用作Lambda表達式。函數式流式編程方法在Java 8 之后的項目中應用非常普遍。

概述

在Java 8之前,我們通常會為每種需要封裝單個功能的情況創建一個類,這意味著需要大量不必要的樣板代碼。

Java 8以Lambda表達式的形式帶來了一個強大的新語法改進,Lambda是一個匿名函數。

Function接口

建議所有函數接口都使用@FunctionalInterface注解,用于清楚傳達函數接口的目的,并且還允許編譯器在帶有該注解的接口,在不滿足條件的情況下生成編譯錯誤。

任何帶有SAM(單一抽象方法)的接口都是函數接口,被視為Lambda表達式。

Java8 的默認方法不是抽象的,也不算在內,函數接口允許存在多個默認方法。

Lambda最簡單、最通用的情況是一個函數接口,該接口具有一個接收一個值并返回另一個值的方法。單個參數的函數可以由Function接口表示,該接口通過其參數的類型和返回值進行參數化:

public interface Function<T, R> { … }

Function類型在標準JDK庫中的用法之一是Map.computeIfAbsent方法。此方法按鍵返回映射中的值,但如果映射中尚未存在鍵,則會計算值。要計算一個值,它使用傳遞的Function實現:

Map<String, Integer> nameMap = new HashMap<>();
Integer value = nameMap.computeIfAbsent("John", s -> s.length());

Function接口還有一個默認的compose方法,它允許我們將多個函數組合為一個函數并按順序執行:

Function<Integer, String> intToString = Object::toString;
Function<String, String> quote = s -> "'" + s + "'";

Function<Integer, String> quoteIntToString = quote.compose(intToString);

assertEquals("'5'", quoteIntToString.apply(5));

基元類型函數

由于基元類型不能是泛型類型參數,因此對于最常用的基元類型double、int、long及其在參數和返回類型中的組合,函數接口有以下版本:

  • IntFunction、LongFunction、DoubleFunction:參數是指定類型的,返回類型是參數化的
  • ToIntFunction、ToLongFunction、ToDoubleFunction:返回類型為指定類型,參數是參數化的
  • DoubleToIntFunction、DoubleToLongFunction、IntToDoubleFunction、IntToLongFunction、LongToIntFunction和LongToDoubleFunction:參數和返回類型都定義為基元類型,由它們的名稱指定

例如,對于一個使用short并返回字節的函數:

@FunctionalInterface
public interface ShortToByteFunction {

    byte applyAsByte(short s);

}

現在,我們可以編寫一個方法,使用ShortToByteFunction定義的規則將short數組轉換為字節數組:

public byte[] transformArray(short[] array, ShortToByteFunction function) {
    byte[] transformedArray = new byte[array.length];
    for (int i = 0; i < array.length; i++) {
        transformedArray[i] = function.applyAsByte(array[i]);
    }
    return transformedArray;
}

以下是我們如何使用它將short數組轉換為字節乘以2的數組:

short[] array = {(short) 1, (short) 2, (short) 3};
byte[] transformedArray = transformArray(array, s -> (byte) (s * 2));

byte[] expectedArray = {(byte) 2, (byte) 4, (byte) 6};
assertArrayEquals(expectedArray, transformedArray);

Bi函數接口

要用兩個參數定義lambda,我們必須使用名稱中包含“Bi”關鍵字的附加接口:BiFunction、ToDoubleBiFunction、ToIntBiFunction和ToLongBiFunction。

BiFunction同時生成了參數和返回類型,而ToDoubleBiFunction和其他函數允許我們返回基元值。

在標準API中使用此接口的典型示例之一是Map.replaceAll方法,它允許用一些計算值替換Map中的所有值。

讓我們使用一個BiFunction實現,該實現接收一個鍵和一個舊值來計算工資的新值并返回。

Map<String, Integer> salaries = new HashMap<>();
salaries.put("John", 40000);
salaries.put("Freddy", 30000);
salaries.put("Samuel", 50000);

salaries.replaceAll((name, oldValue) -> 
  name.equals("Freddy") ? oldValue : oldValue + 10000);

Suppliers函數接口

通常用它來提供數據產出,例如,讓我們定義一個函數,它將一個值平方:

public double squareLazy(Supplier<Double> lazyValue) {
    return Math.pow(lazyValue.get(), 2);
}

Supplier<Double> lazyValue = () -> {
    Uninterruptibles.sleepUninterruptibly(1000, TimeUnit.MILLISECONDS);
    return 9d;
};

Double valueSquared = squareLazy(lazyValue);

讓我們使用一個靜態Stream.generate方法來創建一個Fibonacci數字流:

int[] fibs = {0, 1};
Stream<Integer> fibonacci = Stream.generate(() -> {
    int result = fibs[1];
    int fib3 = fibs[0] + fibs[1];
    fibs[0] = fibs[1];
    fibs[1] = fib3;
    return result;
});

我們使用一個數組而不是兩個變量,因為lambda內部使用的所有外部變量都必須是有效的final。

Consumers函數接口

例如,讓我們通過在控制臺中打印問候語來問候姓名列表中的每個人。傳遞給List.forEach方法的lambda實現了Consumer函數接口:

List<String> names = Arrays.asList("John", "Freddy", "Samuel");
names.forEach(name -> System.out.println("Hello, " + name));

還有專門版本的Consumer(DoubleConsumer、IntConsumer和LongConsumer),它們接收基元值作為參數:

Map<String, Integer> ages = new HashMap<>();
ages.put("John", 25);
ages.put("Freddy", 24);
ages.put("Samuel", 30);

ages.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));

另一組專門的BiConsumer版本由ObjDoubleConsumer、ObjIntConsumer和ObjLongConsumer組成,它們接收兩個參數;其中一個參數是泛型的,另一個是基元類型。

Predicates函數接口

Predicates是一個接收值并返回布爾值的函數。

List<String> names = Arrays.asList("Angela", "Aaron", "Bob", "Claire", "David");

List<String> namesWithA = names.stream()
  .filter(name -> name.startsWith("A"))
  .collect(Collectors.toList());

在上面的代碼中,我們使用流API過濾列表,并只保留以字母“a”開頭的名稱。Predicates實現封裝了篩選邏輯。

與前面的所有示例一樣,此函數的IntPredicate、DoublePredicate和LongPredicate版本都接收基元值。

Operators函數接口

Operator接口是接收和返回相同值類型的函數的特殊情況。UnaryOperator接口接收一個參數。它在集合API中的一個用例是用相同類型的一些計算值替換列表中的所有值:

List<String> names = Arrays.asList("bob", "josh", "megan");
names.replaceAll(name -> name.toUpperCase());

當然,我們可以簡單地使用方法引用來代替name->name.toUpperCase():

names.replaceAll(String::toUpperCase);

BinaryOperator最有趣的用例之一是歸約運算。假設我們想將一組整數聚合為所有值的總和。使用流API,我們可以使用收集器來實現這一點,但更通用的方法是使用reduce方法:

List<Integer> values = Arrays.asList(3, 5, 8, 9, 12);

int sum = values.stream()
  .reduce(0, (i1, i2) -> i1 + i2);

reduce方法接收一個初始累加器值和一個BinaryOperator函數。此函數的參數是一對相同類型的值;函數本身還包含一個邏輯,用于將它們連接到同一類型的單個值中。傳遞的函數必須是關聯的,這意味著值聚合的順序無關緊要,即應滿足以下條件:

op.apply(a, op.apply(b, c)) == op.apply(op.apply(a, b), c)

其他

并不是所有的功能接口都出現在Java 8中。以前版本的Java中的許多接口都符合FunctionalInterface的約束,我們可以將它們用作lambda。

突出的例子包括并發API中使用的Runnable和Callable接口。在Java 8中,這些接口也用@FunctionalInterface注釋進行標記。這使我們能夠極大地簡化并發代碼:

Thread thread = new Thread(() -> System.out.println("Hello From Another Thread"));
thread.start();

結論

本文主要演示了Java 8 API中的不同功能的函數接口,這些接口可以用作Lambda表達式。函數式流式編程方法在Java 8 之后的項目中應用非常普遍。

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2020-05-25 16:25:17

Java8Stream函數式接口

2021-08-03 07:51:43

Java 8 函數接口

2025-06-26 08:10:00

Java8函數

2020-10-16 10:07:03

Lambda表達式Java8

2022-12-26 07:47:37

JDK8函數式接口

2015-09-30 09:34:09

java8字母序列

2019-08-05 08:05:27

Java開發代碼

2021-01-14 10:00:57

Restful接口

2022-01-06 07:39:17

Java Default關鍵字 Java 基礎

2020-07-24 08:11:04

Java8ava5語言

2024-08-19 02:00:00

FunctionJava8接口

2020-05-27 08:05:33

MybatisMapper接口

2021-09-18 09:45:33

前端接口架構

2023-11-20 08:01:38

并發處理數Tomcat

2024-08-28 10:33:56

2021-08-13 12:53:42

StringBuildStringJoineJava

2023-05-12 07:40:01

Java8API工具

2023-05-17 08:20:34

Java 17編程語言

2022-03-30 09:01:37

CSS屬性函數

2021-09-08 08:55:45

Javascript 高階函數前端
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品九九| 91精品国产综合久久久久久蜜臀 | 青草福利 | 亚洲手机在线 | 日韩快播电影网 | 91精品国产欧美一区二区 | 中国av在线免费观看 | 亚洲精品乱码8久久久久久日本 | 欧美日韩电影免费观看 | 天天爱天天操 | 亚洲免费一区二区 | 亚洲免费三区 | www亚洲成人 | 欧美毛片免费观看 | 日韩精品一区二区三区中文在线 | 久久av一区二区三区 | 一区二区在线 | 国产精品夜色一区二区三区 | 亚洲网站在线播放 | 欧美电影在线观看网站 | 九九伦理电影 | 精品美女视频在线观看免费软件 | www久久国产 | 国产中文字幕在线 | 久久久精品一区二区三区四季av | 久久综合久久综合久久综合 | 福利网站导航 | 成人国产综合 | 国产99久久精品一区二区永久免费 | 精品成人在线视频 | 日韩一区二区三区四区五区六区 | 久久久无码精品亚洲日韩按摩 | 人妖无码| av天天看| 国产精品视频免费观看 | 久久不卡视频 | 亚洲国产高清在线观看 | 中文字幕免费 | 手机看片在线播放 | 国产精品一区二区三区在线 | 欧美中文字幕在线观看 |