一般に、述語とは、値が真であるか偽であるかを決定するステートメントを意味します。プログラミングにおいて、述語とは、ブール値を返す 1 つの引数を持つ関数を意味します。Functional Interface Predicate は Java 8 で実現されました。「Functional」とは、抽象メソッドが 1 つだけ含まれていることを意味します。引数を受け取り、ブール値を返します。Java では、関数型インターフェイスはラムダ式、コンストラクター、およびメソッド参照を処理するために使用されます。通常、Java 8 述語は、オブジェクトのコレクションにフィルターを適用するために使用されます。その主な用途と広く使用されている方法を見て、いくつかの練習問題を解いてみましょう。
開発者が述語を使用する理由
基本的に、開発者は、事前定義された基準に基づいて項目を評価し、ブール値を返すタスクに述語を使用できます。 開発者が述語を使用して処理する単純なタスクの例を次に示します。- 一連の整数をフィルタリングします。
- データがいくつかの事前定義された条件に準拠していることを確認してリストを並べ替えます (たとえば、価格と重量の条件を設定して一連の品目を整理します)。
- 並行プログラミングでのユーティリティ パッケージの使用。
Javaの述語構文
java.util.function.Predicate は、 Lambda で評価インプレッションを処理する代替方法として Java 8 で導入されました。インターフェイスの標準ビューはPredicate<T>です。ここで、 T はブール値を返す単一の引数です。Java 述語には、指定されたオブジェクトに対してこの述語を評価する 関数型 (抽象) メソッドtest(Object)があります。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
ここでは、「より大きい」、「より小さい」という条件に基づいて整数をフィルタリングする単純な述語を作成する例を示します。
// An example of a simple Java predicate
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args)
{
// Creating predicate
Predicate<Integer> lesserThan = i -> (i < 18);
// Calling Predicate method
System.out.println(lesserThan.test(10));
}
}
10 < 18 であるため、出力はtrueになります。 filter()の Predicate を使用したもう 1 つの例。述語は、年齢のリストからすべての成人をフィルタリングするのに役立ちます。
import java.util.List;
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
List<Integer> ages = List.of(17, 18, 19, 28, 18, 28, 46, 7, 8, 9, 21, 12);
NotLessThan18<Integer> isAdult = new NotLessThan18<>();
ages.stream().filter(isAdult).forEach(System.out::println);
}
}
class NotLessThan18<E> implements Predicate<Integer> {
@Override
public boolean test(Integer v) {
Integer ADULT = 18;
return v >= ADULT;
}
}
出力は次のとおりです。
18 19 28 18 28 46 21
Java 8 述語メソッド
Predicate インターフェイスにはいくつかのメソッドがあります。- boolean test(T t) は、指定された引数の述語を評価します。
- デフォルトの Predicate<T> and(Predicate<? super T> other) は、この述語と別の述語の短絡論理 AND を表す述語を返します。
- デフォルトの Predicate<T> または、この述語と別の述語の短絡論理 OR を表す合成述語を返します。
- デフォルトの Predicate<T> negate() は、この述語と論理的に反対の述語を返します。
- デフォルトの Predicate<T> isEqual(Object targetRef) は、Objects.equals(Object, Object)に従って 2 つの引数が等しいかどうかをテストした結果を返します。
ブール値テスト(T t)
これは、指定された引数が述語の条件を満たすかどうかを評価する Java 述語の関数メソッドです。例: ここでは、18 歳以上のすべての人を対象とした成人の述語を作成します。test()メソッドは整数値を取得してチェックします。
import java.util.function.Predicate;
public class PredicateTestTest {
public static void main(String[] args) {
Predicate<Integer> adult = i -> i >= 18;
System.out.println(adult.test(12));
System.out.println(adult.test(19));
System.out.println(adult.test(21));
}
}
上記のコードの出力はどうなるでしょうか? 最初のケースでは、12 は 18 より小さいため、偽になります。2 番目と 3 番目のシナリオについては、条件が満たされているため、リターンは true になります。
偽 真 真
デフォルトのPredicate.and()
このメソッドは「and」演算子を表します。そのため、与えられた述語の 1 つが設定された条件を満たさない場合、他の述語は評価されません。例: Java で述語を作成し、and()を使用してすでに成人であるが 65 歳未満であるすべての人々をフィルタリングしてみましょう。predicate.add ()を使用して、これらの条件に対してラムダを使用して Java 述語を記述してみましょう。条件が true の場合、アプリは次のステートメントを返します。
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
Predicate<Integer> adultYet = i -> i >= 18;
Predicate<Integer> adultStill = i -> i < 65;
System.out.println(adultYet.and(adultStill).test(5));
System.out.println(adultYet.and(adultStill).test(38));
System.out.println(adultYet.and(adultStill).test(90));
}
}
出力は次のとおりです。
偽真偽
デフォルトのPredicate.or()
Predicate.or()メソッドは「OR」演算子を表します。これは、2 つの述語のうちの 1 つが true で、もう 1 つが false であっても、条件は true のままであることを意味します。例: 文字列を評価してみましょう。OR メソッドを使用して、部分文字列「my」または「crayon」を含むすべてのフレーズを並べ替えてみます。
import java.util.function.Predicate;
public class PredicateDemo2 {
public static void main(String[] args) {
Predicate<String> containsA = t -> t.contains("crayon");
Predicate<String> containsB = t -> t.contains("my");
System.out.println(containsA.or(containsB).test("here is my crayon"));
System.out.println(containsA.or(containsB).test("here is my pencil"));
System.out.println(containsA.or(containsB).test("here is John's crayon"));
System.out.println(containsA.or(containsB).test("here is John's pencil"));
}
}
出力は次のとおりです。
true true true false
デフォルトの述語 negate()
negate()メソッドは、事前定義された基準に準拠しないすべての値を収集するために使用されます。例: クラス「トマト」を並べ替えて、「赤」ではないすべてのエントリを見つけたい場合は、述語を作成してシーケンス全体をすばやくスキャンできます。このコードを自分で書いてみて、完了したらソリューションと照らし合わせて確認してください。
import java.util.function.Predicate;
public class PredicateDemo3 {
public static void main(String[] args) {
Predicate<Integer> adult = i -> i >= 18;
System.out.println(adult.negate().test(7)); System.out.println(adult.negate().test(19))
}
}
出力は次のとおりです。
真/偽
静的述語 isEqual(Object targetRef)
このメソッドは、2 つのオブジェクトが Objects.equals() のパラメーターとして定義された値と等しいかどうかを判断する場合に非常に役立ちます。この方法は、同様のテスト結果を比較する必要がある場合に特に便利です。例: 2 台の梨の荷台を比較し、両方の果実が標準の重さと色のものかどうかを確認したいとします。この場合、静的 Predicate isEqual(Object targetRef) がまさに必要なメソッドです。isEqual が2 つの文字列の等価性を どのようにチェックするかを見てみましょう。
import java.util.function.Predicate;
public class PredicateDemo2 {
public static void main(String[] args) {
Predicate<String> i = Predicate.isEqual("here is my crayon");
System.out.println(i.test("here is my pencil"));
System.out.println(i.test("here is my crayon"));
}
}
分析しているオブジェクトが標準条件に準拠している場合、関数は true を返します。出力は次のとおりです。
真偽
Java IntPredicate
Java IntPredicate は関数型インターフェイスであるため、ラムダ式またはメソッド参照の代入ターゲットとして使用できます。IntPredicate は整数を操作し、条件に基づいて述語の値を返します。Predicate インターフェイスなど、 IntPredicate にもtest()、and()、negate()、or()メソッドがあります。IntPredicate の例を次に示します。また、配列からすべての大人 (18 歳以上) をフィルターします。
import java.util.Arrays;
import java.util.function.IntPredicate;
public class IntPredicateExample {
public static void main(String[] args) {
int[] ages = { 18, 28, 18, 46, 90, 45, 2, 3, 1, 5, 7, 21, 12 };
IntPredicate p = n -> n >= 18;
Arrays.stream(ages).filter(p).forEach(System.out::println);
}
}
出力は次のとおりです。
18 28 18 46 90 45 21
Java でクリーンな述語を作成する
Java 述語は非常に機能的で、楽しく操作できます。ただし、作成したラムダ式がコードにどのような影響を与えるかを意識していないと、述語が乱雑になりコードの保守性が低下するリスクがあります。ここでは、関数インターフェイスを管理しやすく読みやすくするために役立つ簡単な実践方法をいくつか紹介します。- 自分自身を繰り返さない - 複数回繰り返される値、メソッド、条件を含む述語を Java で作成しないでください。このようにすると、生産的な時間が無駄になり、コードが煩雑になります。
- テスト容易性を確保するために、アプリのコードから述語を分離します。それ以外は、述語単体テストのスケジュールを作成し、それに従ってください。
- インポートと構成パターンを使用して、クラスが肥大化せず、管理しやすい状態を維持します。
- Java 述語をヘルパー クラスに移動することを検討してください。これにより、コードの再利用性が向上し、メンテナンスが容易になります。
- 読みやすさ — 可能な限り、複雑な述語よりも 1 行のステートメントを優先します。複雑な関数インターフェイスについての理解を誇示したくなるかもしれません。ただし、メンテナンスに関しては、少ない方が良いです。
GO TO FULL VERSION