web-dev-qa-db-ja.com

メソッド参照述語を否定する方法

Java 8では、メソッド参照を使用してストリームをフィルタリングできます。次に例を示します。

Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();

既存のものの否定である、すなわち次のようなものであるメソッド参照を作成する方法はありますか?

long nonEmptyStrings = s.filter(not(String::isEmpty)).count();

私は以下のようにnotメソッドを作成することができましたが、JDKが似たようなものを提供してくれるかどうか疑問に思いました。

static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
276
assylias

Java-11 は新しい方法を提供します 述語#not

そのため、メソッド参照を無効にすることができます。

Stream<String> s = ...;
long nonEmptyStrings = s.filter(Predicate.not(String::isEmpty)).count();
86
Anton Balaniuc

メソッド参照をインラインで使用できるように、以下を静的インポートすることを計画しています。

public static <T> Predicate<T> not(Predicate<T> t) {
    return t.negate();
}

例えば.

Stream<String> s = ...;
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();

アップデート: - JDK/11は 同様の解決策を提供している可能性があります も同様です。

184
davidillsley

現在のメソッド参照とは反対のメソッド参照を作成する方法があります。以下の@ vlasecの回答を参照してください。これは、メソッド参照をPredicateに明示的にキャストしてから、negate関数を使用して変換する方法を示しています。それは、他のいくつかの方法の中の1つですが、それを実行するのは面倒なことではありません。

これの反対:

Stream<String> s = ...;
int emptyStrings = s.filter(String::isEmpty).count();

これは:

Stream<String> s = ...;
int notEmptyStrings = s.filter(((Predicate<String>) String::isEmpty).negate()).count()

またはこれ:

Stream<String> s = ...;
int notEmptyStrings = s.filter( it -> !it.isEmpty() ).count();

個人的には、長い冗長な明示的キャストよりit -> !it.isEmpty()を読んだ後に否定するほうが明確であると思うので、私は後者の手法を好みます。

述語を作り、それを再利用することもできます。

Predicate<String> notEmpty = (String it) -> !it.isEmpty();

Stream<String> s = ...;
int notEmptyStrings = s.filter(notEmpty).count();

あるいは、コレクションや配列を持っている場合は、単純で、オーバーヘッドが少なく、*高速**のようにforループを使用するだけです。

int notEmpty = 0;
for(String s : list) if(!s.isEmpty()) notEmpty++;

*何が速いのか知りたい場合は、JMH http://openjdk.Java.net/projects/code-tools/jmh を使用してください。すべてのJVM最適化を回避しない限り、手動のベンチマークコードは避けてください。 Java 8:Streams vs Collectionsのパフォーマンスを参照してください

** for-loopテクニックが速いことを示唆したことで、私は気まぐれになっています。それはストリームの作成を排除し、それは別のメソッド呼び出し(述語に対する負の関数)の使用を排除し、そしてそれは一時的なアキュムレータリスト/カウンタを排除する。そのため、最後の構成要素によって節約されるいくつかの点で、速度が上がる可能性があります。

私はそれがもっと速くなくても、もっとシンプルでより良いと思います。仕事がハンマーと釘を要求するならば、チェーンソーを持って来て、接着剤を使わないでください!私はあなたの何人かがそれを問題にしているのを知っています。

wish-list:Javaユーザーが慣れ親しんだ今、JavaのStream関数が少し進化するのを見たいです。たとえば、Streamの 'count'メソッドはPredicateを受け取ることができるので、これは次のように直接実行できます。

Stream<String> s = ...;
int notEmptyStrings = s.count(it -> !it.isEmpty());

or

List<String> list = ...;
int notEmptyStrings = lists.count(it -> !it.isEmpty());
139
The Coordinator

Predicateには、メソッドandor、およびnegateがあります。

しかし、String::isEmptyPredicateではなく、単なるString -> Booleanラムダであり、それでも何かになる可能性があります。 Function<String, Boolean>型推論が最初に起こる必要があるものです。 filterメソッドは型を暗黙的にと推測します。しかし、引数として渡す前にそれを否定すると、それは起こりません。 @axtavtが述べたように、explicit推論は醜い方法として使用できます。

s.filter(((Predicate<String>) String::isEmpty).negate()).count()

他の答えでは他にもアドバイスがありますが、静的notメソッドとラムダが最も良い考えです。 これでtl; drセクションが終わります。


しかし、ラムダ型推論についてもっと深く理解したいのであれば、例を使ってもう少し詳しく説明したいと思います。これらを見て、何が起こるのか把握しよう。

Object obj1                  = String::isEmpty;
Predicate<String> p1         = s -> s.isEmpty();
Function<String, Boolean> f1 = String::isEmpty;
Object obj2                  = p1;
Function<String, Boolean> f2 = (Function<String, Boolean>) obj2;
Function<String, Boolean> f3 = p1::test;
Predicate<Integer> p2        = s -> s.isEmpty();
Predicate<Integer> p3        = String::isEmpty;
  • obj1はコンパイルされません - ラムダは機能的インタフェースを推論する必要があります(= 1つの抽象メソッドで)
  • p1とf1はうまく働き、それぞれ異なる型を推論します。
  • obj2はPredicateObjectにキャストします - ばかげているが有効
  • f2は実行時に失敗します - PredicateFunctionにキャストすることはできません
  • f3は動作します - ラムダによって定義される述語のメソッドtestを呼び出します
  • p2はコンパイルされません - IntegerisEmptyメソッドを持っていません
  • p3もコンパイルされません - Integer引数を持つString::isEmpty静的メソッドはありません

これが型推論がどのように機能するのかについてのさらなる洞察を得るのに役立つことを願っています。

81
Vlasec

他人の答えと個人的な経験に基づいて構築する:

Predicate<String> blank = String::isEmpty;
content.stream()
       .filter(blank.negate())
43
Jose Alban

もう1つの選択肢は、あいまいでないコンテキストで1つのクラスにラムダキャストを利用することです。

public static class Lambdas {
    public static <T> Predicate<T> as(Predicate<T> predicate){
        return predicate;
    }

    public static <T> Consumer<T> as(Consumer<T> consumer){
        return consumer;
    }

    public static <T> Supplier<T> as(Supplier<T> supplier){
        return supplier;
    }

    public static <T, R> Function<T, R> as(Function<T, R> function){
        return function;
    }

}

...その後、ユーティリティクラスを静的にインポートします。

stream.filter(as(String::isEmpty).negate())
16
Askar Kalykov

Predicate#negate はあなたが探しているものではないはずですか?

11
Marco13

この場合、uはorg.Apache.commons.lang3.StringUtilsを使用できます。

int nonEmptyStrings = s.filter(StringUtils::isNotEmpty).count();
8
outofBounds

Eclipseコレクション から 述語 を使用できます。

MutableList<String> strings = Lists.mutable.empty();
int nonEmptyStrings = strings.count(Predicates.not(String::isEmpty));

Listから文字列を変更できない場合:

List<String> strings = new ArrayList<>();
int nonEmptyStrings = ListAdapter.adapt(strings).count(Predicates.not(String::isEmpty));

String.isEmpty()の否定だけが必要な場合は、StringPredicates.notEmpty()を使うこともできます。

注:私はEclipseコレクションの寄稿者です。

4

私は(Askarの提案に触発された)完全なユーティリティクラスを書きました。それはJava 8ラムダ式を取り(もしあれば)パッケージJava.util.functionで定義された任意の型付き標準Java 8ラムダに変換できます。あなたは例えばすることができます:

  • asPredicate(String::isEmpty).negate()
  • asBiPredicate(String::equals).negate()

すべての静的メソッドにas()という名前を付けると、あいまいさが非常に多くなるため、「as」に続けて返される型を呼び出すことにしました。これにより、ラムダ解釈を完全に制御できます。以下は、使用されているパターンを明らかにした(多少大きい)ユーティリティクラスの最初の部分です。

ここで 完全なクラスを見てください (要点)。

public class FunctionCastUtil {

    public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
        return biConsumer;
    }

    public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
        return biFunction;
    }

     public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
        return binaryOperator;
    }

    ... and so on...
}
3

あなたは長いemptyStrings = s.filter(s->!s.isEmpty()).count();としてこれを達成することができます

Spring Boot(2.0.0+)を使っているのなら、

import org.springframework.util.StringUtils;

...
.filter(StringUtils::hasLength)
...

それは:return (str != null && !str.isEmpty());

それでisEmptyに必要な否定効果があります

0
Gilad Peleg