কীভাবে কোনও পদ্ধতি রেফারেন্স প্রাকটিকে উপেক্ষা করবেন neg


330

জাভা 8-এ, আপনি কোনও স্ট্রিম ফিল্টার করার জন্য একটি পদ্ধতি রেফারেন্স ব্যবহার করতে পারেন, উদাহরণস্বরূপ:

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

কোনও পদ্ধতির রেফারেন্স তৈরির জন্য কি এমন কোনও উপায় আছে যা বিদ্যমান বিদ্যমানটিকে অস্বীকার করে, যেমন:

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

আমি notনীচের মতো পদ্ধতিটি তৈরি করতে পারতাম তবে আমি ভাবছিলাম যে জেডিকে অনুরূপ কিছু দেওয়া হয়েছিল কিনা।

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

6
JDK-8050818 একটি স্ট্যাটিক Predicate.not(Predicate)পদ্ধতির সংযোজনকে কভার করে । তবে এই সমস্যাটি এখনও খোলা রয়েছে তাই আমরা এটি জাভা 12-এর প্রথম দিকে (যদি কখনও হয়) দেখব।
স্টিফান জোবেল

1
এই উত্তরটির মতো মনে হচ্ছে জেডিকে / ১১-তেও অভিযোজিত চূড়ান্ত সমাধান হতে পারে।
নমন

2
আমি সত্যিই এই কেসের জন্য একটি বিশেষ পদ্ধতির রেফারেন্স সিনট্যাক্স দেখতে চাই: s.filter (স্ট্রিং ::! ইম্পতি)
মাইক টোয়েন

উত্তর:



214

আমি পদ্ধতিটি রেফারেন্সটিকে ইনলাইনে ব্যবহারের অনুমতি দেওয়ার জন্য স্থিতিশীল আমদানি করার পরিকল্পনা করছি:

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

যেমন

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

আপডেট : জাভা -11 থেকে শুরু করে, জেডিকেঅন্তর্নির্মিত একই ধরণের সমাধান সরবরাহ করে


9
@SaintHill কিন্তু তারপর আপনি, এটি লিখতে হবে পরামিতি একটি নাম দেওয়ার
flup



149

একটি পদ্ধতি রেফারেন্স রচনা করার একটি উপায় রয়েছে যা বর্তমান পদ্ধতি রেফারেন্সের বিপরীত। নীচে @ ভ্ল্যাকের উত্তর দেখুন যা দেখায় যে কীভাবে স্পষ্টভাবে কোনও পদ্ধতির রেফারেন্সটি কাস্ট করে Predicateএবং তারপরে এটি negateফাংশনটি ব্যবহার করে রূপান্তর করে । এটি করা খুব ঝামেলাজনক কিছু উপায়গুলির মধ্যে একটি উপায়।

এর বিপরীত:

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();

অথবা, যদি সংগ্রহ বা অ্যারে থাকে তবে কেবল একটি লুপ ব্যবহার করুন যা সাধারণ, কম ওভারহেড রয়েছে এবং * ** দ্রুত হতে পারে:

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

* যদি আপনি কী দ্রুত তা জানতে চান, তবে জেএমএইচ http://openjdk.java.net/projects/code-tools/jmh ব্যবহার করুন , এবং হ্যান্ড বেঞ্চমার্ক কোডটি সমস্ত জেভিএম অপ্টিমাইজেশন এড়ানো না হলে - জাভা 8 দেখুন: স্ট্রিমের পারফরম্যান্স দেখুন বনাম সংগ্রহ

** ফর-লুপ কৌশলটি দ্রুততর হওয়ার পরামর্শ দেওয়ার জন্য আমি ঝাঁকুনি পাচ্ছি। এটি একটি স্ট্রিম তৈরিটিকে সরিয়ে দেয়, এটি অন্য পদ্ধতি কল (প্রিডিকেটের জন্য নেতিবাচক ফাংশন) ব্যবহার করে বাদ দেয় এবং এটি একটি অস্থায়ী সঞ্চয়ের তালিকা / কাউন্টারকে সরিয়ে দেয়। তাই শেষের নির্মাণের দ্বারা সংরক্ষিত কয়েকটি জিনিস যা এটি আরও দ্রুত তৈরি করতে পারে।

আমি মনে করি এটি সহজ এবং সুন্দর যদিও দ্রুত না হলেও। যদি কাজটি হাতুড়ি এবং পেরেকের জন্য কল করে তবে একটি চেইনসো এবং আঠালো আনবে না! আমি জানি আপনারা কেউ কেউ এটি নিয়ে ইস্যু নেন।

wish-list: আমি জাভা Streamফাংশনগুলি এখন একটু বিবর্তিত হতে দেখতে চাই যে জাভা ব্যবহারকারীরা তাদের সাথে আরও পরিচিত। উদাহরণস্বরূপ, স্ট্রিমের 'কাউন্ট' পদ্ধতিটি এমন কোনও গ্রহণ Predicateকরতে পারে যাতে এটি সরাসরি এভাবে করা যায়:

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

or

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

কেন আপনি বলেন যে এটি অনেক দ্রুত ?
জোসে আন্দিয়াস

@ জোসআন্ডিয়াস (1) এটি দ্রুত বা 'অনেক দ্রুত'? (২) যদি তাই হয় তবে কেন? আপনি কি স্থির করেছেন?
সমন্বয়কারী

3
আমি আপনাকে "দৌড়তে খুব দ্রুত" এর বিস্তারিত জানাতে বলছি। প্রশ্নগুলি: (1) এটি দ্রুত বা 'অনেক দ্রুত'? (২) যদি তাই হয় তবে কেন? আপনি কি স্থির করেছেন? বিবৃতি রচয়িতা, আপনার দ্বারা আরও ভাল উত্তর দেওয়া হয়েছে। আমি এটিকে দ্রুত বা ধীর বলে বিবেচনা করছি না। ধন্যবাদ
জোসে আন্দিয়াস

2
তারপরে আমি আপনার বিবেচনার জন্য এটি ছুঁড়ে দেব - এটি একটি স্ট্রিম তৈরিটি সরিয়ে দেয়, এটি অন্য পদ্ধতি কল (প্রিডিকেটের জন্য নেতিবাচক ফাংশন) ব্যবহার করে, এবং এটি একটি অস্থায়ী সঞ্চয়ের তালিকা / কাউন্টারকে সরিয়ে দেয়। তাই শেষের নির্মাণের দ্বারা সংরক্ষিত কয়েকটি জিনিস। আমি নিশ্চিত না এটি দ্রুত বা কত দ্রুত, তবে আমি ধরে নিয়েছি এটি 'অনেকটা' দ্রুত। তবে সম্ভবত 'প্রচুর' বিষয়গত বিষয়। নেতিবাচক ভবিষ্যদ্বাণীগুলি এবং স্ট্রেট গণনা করার জন্য স্ট্রিমগুলি তৈরি করার চেয়ে পরে কোড করা সহজ। আমার পছন্দ।
সমন্বয়কারী

4
নেগেট () একটি আদর্শ সমাধান বলে মনে হচ্ছে। দুঃখজনক বিষয় এটিকে স্থির নয় বলে বোঝায় castালাই Predicate.negate(String::isEmpty);ছাড়াই।
জোয়েল শেমতোভ

91

Predicateপদ্ধতি আছে and, orএবং negate

তবে এটি String::isEmptyএকটি নয় Predicate, এটি কেবল একটি String -> Booleanল্যাম্বডা এবং এটি এখনও কিছু হতে পারে, যেমন Function<String, Boolean>টাইপ অনুমান যা প্রথমে হওয়া দরকার happen filterপদ্ধতি infers টাইপ পরোক্ষভাবে । তবে আপনি যদি এটি আর্গুমেন্ট হিসাবে পাস করার আগে এটিকে অবহেলা করেন তবে তা আর হয় না। @ অ্যাক্সট্যাভ্ট হিসাবে উল্লেখ করা হয়েছে, সুস্পষ্ট অনুমানকে কুৎসিত উপায় হিসাবে ব্যবহার করা যেতে পারে:

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 এবং এফ 1 ঠিক জরিমানা কাজ করে, প্রতিটিই আলাদা ধরণের অনুমান করে
  • অবজেক্ট 2 একটি Predicateথেকে Object- নিখুঁত তবে বৈধ ts
  • F2 রানটাইম এ ব্যর্থ - আপনি নিক্ষেপ করতে পারবে না Predicateথেকে Function, এটা কোনো ব্যাপার অনুমান সম্পর্কে
  • f3 কাজ করে - আপনি প্রিডিকেট এর পদ্ধতিটিকে কল করেন testযা এর ল্যাম্বদা দ্বারা সংজ্ঞায়িত হয়েছে
  • P2 কম্পাইল করে না - Integerনেই isEmptyপদ্ধতি
  • p3 হয় কোনও সংকলন করে না - যুক্তি String::isEmptyসহ কোনও স্থির পদ্ধতি নেইInteger

আমি আশা করি যে এটি টাইপ ইনফেরেন্স কীভাবে কাজ করে তার আরও কিছুটা অন্তর্দৃষ্টি পেতে সহায়তা করে।


45

অন্যের উত্তর এবং ব্যক্তিগত অভিজ্ঞতার ভিত্তিতে:

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

4
আকর্ষণীয় - আপনি ::যেমনটি চান তার মতো ফাংশনাল রেফারেন্সটি ইনলাইন করতে পারবেন না ( String::isEmpty.negate()) তবে আপনি যদি প্রথমে কোনও চলককে (বা Predicate<String>প্রথমে কাস্ট করা ) অর্পণ করেন তবে তা কার্যকর হয় । আমি মনে করি লাম্বদা ডাব্লু / !বেশিরভাগ ক্ষেত্রে সর্বাধিক পঠনযোগ্য, তবে কী কী সংকলন করতে পারে এবং কী করতে পারে তা জেনে রাখা সহায়ক।
জোশুয়া গোল্ডবার্গ

2
@ জোশুয়া গোল্ডবার্গ আমি আমার উত্তরে ব্যাখ্যা করেছিলাম: পদ্ধতির উল্লেখটি নিজেই কোনও পূর্বানুমান নয়। এখানে, ভেরিয়েবল দ্বারা ingালাই করা হয়।
Vlasec

17

অন্য বিকল্পটি হ'ল ল্যাম্বদা ingালাইকে অবিশ্বাস্য প্রসঙ্গে একটি শ্রেণিতে ব্যবহার করা:

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())

1
আমি প্রকৃতপক্ষে এই কাজগুলিকে অবাক করে দিয়েছি - তবে মনে হয় যে জেডি কে ফাংশন <টি, বুলিয়ান> এর চেয়ে পূর্বানুমান <টি> এর পক্ষে। তবে আপনি লাম্বদাসকে ফাংশন <টি, বুলিয়ান> এ কোনও কিছু দেওয়ার জন্য পাবেন না।
ভ্লাস্যাক

এটি স্ট্রিংয়ের জন্য কাজ করে তবে তালিকার জন্য নয়: ত্রুটি: (20, 39) জাভা: হিসাবে উল্লেখ করা হয়েছে উভয় পদ্ধতি <T> হিসাবে (java.util.function.Conumer <T>) com.strands.sbs.function এ। Com.strands.sbs.function.Lambdas ম্যাচে লাম্বডাস এবং পদ্ধতি <টি, আর> হিসাবে (java.util.function.Function <টি, আর>)
ড্যানিয়েল পিনিয়োল

ড্যানিয়েল, আপনি যদি ওভারলোডেড পদ্ধতিটি ব্যবহার করার চেষ্টা করছেন তবে এটি ঘটতে পারে :)
আসকার কল্যাভক

এখন যেহেতু আমি প্রকারের তুলনায় টাইপ ইনফারেন্স বুঝতে পারছি, আমি বুঝতে পারি যে এটি কীভাবে কাজ করে। মূলত, এটি কেবল কাজ করে এমন একমাত্র বিকল্পটি আবিষ্কার করে। আকর্ষণীয় দেখায়, আমি ঠিক জানি না এমন কোনও আরও ভাল নাম আছে যা বয়লারপ্লেট সৃষ্টি করে না।
ভ্ল্যাক

12

Predicate#negateআপনি যা খুঁজছেন তা হওয়া উচিত নয় ?


আপনার Predicateপ্রথম হওয়া দরকার।
সোটিরিওস ডেলিমনোলিস

21
আপনি আগে নিক্ষেপ String::isEmpty()করতে Predicate<String>হবে - এটি খুব কদর্য।
axtavt

3
হিসেবে ব্যবহার করবেন @assylias Predicate<String> p = (Predicate<String>) String::isEmpty;এবং p.negate()
সোটিরিওস ডেলিমানলিস 19

8
@SotiriosDelimanolis আমি জানি, কিন্তু যে নষ্ট উদ্দেশ্য - আমি বরং লিখতে চাই s -> !s.isEmpty()যে ক্ষেত্রে!
Assylias

@ এ্যাসিয়ালিয়াস: হ্যাঁ, আমি বিশ্বাস করি এটি আসলে ধারণা; ল্যাম্বডা লংহ্যান্ডকে কেবল লেখার উদ্দেশ্য হ'ল ফলব্যাক।
লুই ওয়াসারম্যান

8

এই ক্ষেত্রে আপনি ব্যবহার org.apache.commons.lang3.StringUtilsএবং করতে পারেন

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

6
নং প্রশ্নটি কোনও পদ্ধতির রেফারেন্সকে কীভাবে অস্বীকার করা যায় এবং এটি String::isEmptyউদাহরণ হিসাবে গ্রহণ করে । এটি যদি আপনার ব্যবহারের ক্ষেত্রে থাকে তবে এটি এখনও প্রাসঙ্গিক তথ্য, তবে এটি যদি কেবল স্ট্রিং ব্যবহারের ক্ষেত্রে উত্তর দেয় তবে তা গ্রহণ করা উচিত নয়।
অ্যান্টনি ড্রাগন

4

আমি একটি সম্পূর্ণ ইউটিলিটি ক্লাস লিখেছি (আসকারের প্রস্তাব দ্বারা অনুপ্রাণিত) যা জাভা 8 লাম্বদা এক্সপ্রেশন নিতে পারে এবং তাদের (প্রযোজ্য ক্ষেত্রে) প্যাকেজে সংজ্ঞায়িত কোনও টাইপ করা স্ট্যান্ডার্ড জাভা 8 ল্যাম্বডায় রূপান্তর করতে পারে java.util.function। আপনি উদাহরণস্বরূপ করতে পারেন:

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

যেহেতু সমস্ত স্থির পদ্ধতিগুলি কেবল নামকরণ করা হলে অসংখ্য অস্পষ্টতা থাকবে 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...
}

4

আপনি 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()

দ্রষ্টব্য: আমি গ্রহন গ্রাহক সংগ্রহের একজন সহযোগী।



0

আপনি যদি স্প্রিং বুট (২.০.০+) ব্যবহার করেন তবে আপনি এটি ব্যবহার করতে পারেন:

import org.springframework.util.StringUtils;

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

যা আছে: return (str != null && !str.isEmpty());

সুতরাং এটির জন্য প্রয়োজনীয় অবহেলা প্রভাব পড়বে isEmpty

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.