一般的に使用される機能インターフェイス
レビュー
機能インターフェイスの概念については、前の記事「ラムダ式」で説明しました。ラムダ式で機能インターフェイスを使用すると、場合によってはJavaコードの記述を大幅に簡素化できます。機能インターフェイスとは、インターフェイスに抽象メソッドが1つだけあり、インターフェイスが@FunctionalInterfaceアノテーションで装飾されていることを指します。JDKは、一般的に使用される機能インターフェイスの定義に役立ちました。これらの機能インターフェイスは、Lambdaおよび後で説明するストリームと連携して、フィルタリングデータ操作を実行します。使用は非常に簡単です。一般的に使用される機能インターフェイスについて説明します。
機能インターフェイスの比較的大規模なアプリケーションシナリオがパラメータとしてメソッドに渡されることは言及する価値があります。
サプライヤーインターフェース
(サプライヤサプライヤ)は、データを渡さずに、対応するデータタイプを「生成」するために使用される「ファクトリ」タイプのインターフェイスです。特定の用途は、次のストリームに反映されます。
@FunctionalInterface
public interface Supplier<T> {
}
抽象的方法
T get():汎用パラメータータイプで指定されたデータを取得するため、つまり、要件を満たすデータタイプを提供し、「サプライヤー」と同様にデータを「生成」するために使用されます。
例:配列の最大値を取得する
public class SupplierDemo {
public static int getMaxValue(Supplier<int> supplier) {
//接口作为参数进行传递
return supplier.get();
}
public static void main(String[] args) {
int[] nums = {
2, 9, 19, 1, 20};
int max = getMaxValue(()->{
//使用Lambad表达式
int max = nums[0];
for (int i = 1; i < nums.length; i++) {
max = nums[i] > max ? nums[i] : max;
}
return max;
});
}
}
もちろん、上記の例は、get()メソッドの目的が目的のデータタイプを提供することであることを確認するためのものです。
消費者インターフェース
(消費者消費)データを作成するサプライヤとは異なり、消費者はデータを消費する、つまり操作のためにデータを渡すためのものであり、戻り値はありません。
@FunctionalInterface
public interface Consumer<T> {
}
抽象的方法
void accept(T):指定されたパラメーターのメソッドのコンテンツを実行します
例:渡された文字列データを逆にする
public class ConsumerDemo {
public static void reserveString(String str, Consumer<String> con) {
con.accept(str);
}
public static void main(String[] args) {
String str = "lambda";
reserveString(str, (str)->{
System.out.println(str); //lambda
StringBuffer reStr = new StringBuffer(str);
reStr.reverse().toString(); //将字符串进行逆转
System.out.println(reStr); //adbmal
});
}
}
デフォルトの方法
サプライヤインターフェイスとは異なり、デフォルトのメソッドはコンシューマインターフェイスに実装されています。addThen()
/**
* 默认方法
* 1. 返回一个组合的Consumer对象,并且会按照顺序执行accept方法:即可以拼接多个进行执行
* 2. 如果after方法执行出现异常(或接下去拼接的出现异常了)就会将该异常转发给调用者(例如main)。
* 3. 如果执行this操作出现异常时,不会执行after的操作。
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after); //判断是否为空指针
return (T t) -> {
accept(t);
after.accept(t);
}; //这也是一个Consumer接口accept的lambad实现
}
例:文字列を大文字小文字に変換する
public class ConsumerDemo {
public static void method(String str, Consumer<String> con1, Consumer<String> con2) {
con1.andThen(con2).accept(str);
}
public static void main(String[] args) {
String str = "Lambda";
method(str, (t)->{
System.out.println(t.toUpperCase()); //LAMBDA
}, (t) -> {
System.out.println(t.toLowerCase()); //lambda
});
}
}
述語インターフェース
(述語述語、離散数学の概念)、パラメータを渡し、パラメータが条件を満たしているかどうかを確認するためにパラメータを論理的に判断し(指定されたパラメータの述語を評価します)、戻り値はブール値です。
@FunctionalInterface
public interface Predicate<T> {
}
抽象インターフェース
boolean test(T t):入力パラメーターが条件を満たすかどうかを判別します
例:文字列のリストを渡し、4より大きい長さの文字列を出力します
public class PredicateDemo {
public static void checkString(String[] strs, Predicate<String> pre) {
for (int i = 0; i < strs.length; i++) {
if (pre.test(strs[i])) {
System.out.println(strs[i]);
}
}
}
public static void main(String[] args) {
String[] strs = {
"java", "c", "C++", "python", "javascript", "Typescript"};
checkString(strs, (str)->{
return str.length() > 4;
}); //python, javascript,Typescript
}
}
デフォルトの方法
論理的な判断に使用されるため、論理演算子が不可欠であり、いくつかのデフォルトの論理操作メソッドがPredicateインターフェイスに組み込まれています。
/**
* 1.返回一个通过逻辑与组合的Predicate接口
* 2.other.test抛出异常的话将该异常转发给调用者
* 3.this.test抛出异常的话不执行other.test的内容
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
//逻辑非
default Predicate<T> negate() {
return (t) -> !test(t);
}
//逻辑或
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
例:文字列にが含まれていて、長さが5より大きいことを確認します
public class PredicateDemo {
public static boolean checkString(String str, Predicate<String> pre1, Predicate<String> pre2) {
return pre1.and(pre2).test(str);
}
public static void main(String[] args) {
String str = "lambda";
boolean b = checkString(str, (str1)->{
return str1.length() > 5;
}, (str1) -> {
return str1.contains("a");
});
System.out.println(b); // true
}
}
機能インターフェース
@FunctionalInterface
public interface Function<T, R> {
}
このインターフェイスは、タイプTをタイプRに変換するために使用されます。Tは前提条件と呼ばれ、Rは事後条件と呼ばれます。
抽象的方法
R apply(T t):指定されたパラメータータイプTをRタイプに変換します
たとえば、文字列タイプの数値を整数タイプに変換します
public class FunctionDemo {
private static void transform(Function<String, Integer> function) {
int num = function.apply("10"); //数字10
System.out.println(num + 20);
}
public static void main(String[] args) {
transform(s ‐> Integer.parseInt(s));
}
}
デフォルトの方法
Consumerと同様に、FunctionにもaddThenメソッドがあります。このメソッドも、結合された操作の後にFunctionインターフェイスを返し、最終的に変換されたデータタイプは変換後のデータタイプと一致します。
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after); //判断是否为空指针
return (T t) -> after.apply(apply(t)); //这也是一个Consumer接口apply的lambad实现
}
例:文字列番号を整数型に変換してから、+ 10を文字列に変換します
public class FunctionDemo{
public static void addTen(String str, Function<String, Integer> fun1, Function<Integer, String> fun2) {
//注意最后返回的与fun2的类型相同
String s = fun1.andThen(fun2).apply(str);
System.out.println(s); //"20"
}
public static void main(String[] args) {
String s = "10";
addTen(s, (String str1) ->{
return Integer.parseInt(str1) + 10;
}, (Integer integer) -> {
return integer.toString();
});
}
}
概要
- 機能インターフェイスを通じて、ラムダ式の簡潔さを確認できます。もちろん、より簡潔な方法は、メソッド参照を使用することです。
- この段階では、この操作は不要だと感じるかもしれませんが、これらのインターフェイスは後続のストリームで非常に役立ちます。