জাভা 8 স্ট্রিম থেকে বিরতি বা ফিরে আসা?


312

ব্যবহার করার সময় বহিরাগত পুনরাবৃত্তির কোনো ওভার Iterableআমরা ব্যবহার breakবা returnজন্য-প্রতিটি যেমন লুপ উন্নত থেকে:

for (SomeObject obj : someObjects) {
   if (some_condition_met) {
      break; // or return obj
   }
}

কীভাবে আমরা breakবা জাভা 8 ল্যাম্বডা এক্সপ্রেশনটিতে অভ্যন্তরীণ পুনরাবৃত্তিটিreturn ব্যবহার করতে পারি :

someObjects.forEach(obj -> {
   //what to do here?
})

6
আপনি পারবেন না। শুধু একটি সত্য forবিবৃতি ব্যবহার করুন ।
বোয়ান


অবশ্যই এটা হল সম্ভব forEach()। সমাধান সুন্দর না, কিন্তু এটা হয় সম্ভব। আমার উত্তর নীচে দেখুন।
হনজা জিদেক

অন্য পদ্ধতির বিবেচনা করুন, আপনি কেবল কোডটি কার্যকর করতে চান না , সুতরাং, ইচ্ছার ifঅভ্যন্তরের একটি সাধারণ শর্তটি forEachকৌশলটি করবে।
টমাস ডিকোক্স

উত্তর:


373

আপনার যদি এটির প্রয়োজন হয় তবে আপনার ব্যবহার করা উচিত নয় forEach, তবে স্ট্রিমগুলিতে উপলভ্য অন্য পদ্ধতিগুলির মধ্যে একটি; কোনটি, আপনার লক্ষ্য কী তার উপর নির্ভর করে।

উদাহরণস্বরূপ, যদি এই লুপটির লক্ষ্যটি হ'ল প্রথম উপাদানটি খুঁজে পাওয়া যায় যা কিছু প্রাকটিকের সাথে মেলে:

Optional<SomeObject> result =
    someObjects.stream().filter(obj -> some_condition_met).findFirst();

(দ্রষ্টব্য: এটি পুরো সংগ্রহটি পুনরাবৃত্তি করবে না, কারণ স্ট্রিমগুলি অলসভাবে মূল্যায়ন করা হয় - এটি শর্তের সাথে মেলে এমন প্রথম অবজেক্টে থামবে)।

আপনি যদি কেবল জানতে চান যে সংগ্রহে এমন কোনও উপাদান রয়েছে যার জন্য শর্তটি সত্য, আপনি এটি ব্যবহার করতে পারেন anyMatch:

boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);

7
এই কাজ করে খোঁজার একটি বস্তু উদ্দেশ্য ছিল, কিন্তু যে লক্ষ্য সাধারণত একটি দ্বারা পরিবেশিত হয় returnএকটি থেকে বিবৃতি findSomethingপদ্ধতি। breakআরো সাধারণত একটি সঙ্গে যুক্ত করা হয় নিতে সময় -kind অপারেশন।
মার্কো তোপোলনিক

1
@ মারকোটোপলনিক হ্যাঁ, আসল পোস্টারটি সঠিক লক্ষ্যটি কী তা জানার জন্য আমাদের পর্যাপ্ত তথ্য দেয়নি; আমি উল্লেখ করা দুটি ছাড়া একটি "টেক ওয়েট" তৃতীয় সম্ভাবনা। (স্ট্রিমগুলির সাথে "কিছুক্ষণ" নেওয়ার কোনও সহজ উপায় আছে কি?)।
জেস্পার

3
আচরণটি বাতিল করার সঠিকভাবে কার্যকর করার লক্ষ্য কী? যখন আমরা খেয়াল করি যে ব্যবহারকারী একটি বাতিল করার অনুরোধ করেছে তখন আমরা forEach ল্যাম্বডায় একটি রানটাইম ব্যতিক্রম ছড়িয়ে দিতে কেবল সেরা কাজটিই কি করতে পারি?
ব্যবহারকারী 2163960

1
@ হোনজাজিদেক সম্পাদিত, তবে বিষয়টি সম্ভব কিনা তা সম্ভব নয়, তবে জিনিসগুলি করার সঠিক উপায় কী। আপনার এটির জন্য জোর করে বলার চেষ্টা করা উচিত নয় forEach; পরিবর্তে আপনার আরও একটি উপযুক্ত পদ্ধতি ব্যবহার করা উচিত।
জেস্পার

1
@ জেস্পার আমি আপনার সাথে একমত, আমি লিখেছি যে "ব্যতিক্রম সমাধান" আমার পছন্দ হয়নি। তবে আপনার শব্দটি "এটি দিয়ে সম্ভব নয় forEach" প্রযুক্তিগতভাবে ভুল ছিল। আমি আপনার সমাধানটিকেও প্রাধান্য দিই তবে আমি যেসব ক্ষেত্রে আমার উত্তরে প্রদত্ত সমাধানটি পছন্দনীয় সেগুলি ব্যবহারের কল্পনা করতে পারি: যখন আসল ব্যতিক্রমের কারণে লুপটি শেষ করা উচিত । আমি সম্মত হই যে প্রবাহ নিয়ন্ত্রণ করতে আপনার ব্যতিক্রমগুলি সাধারণত ব্যবহার করা উচিত নয় ।
হনজা জিদেক

53

এই হল সম্ভব Iterable.forEach()(কিন্তু নির্ভরযোগ্যভাবে না সঙ্গে Stream.forEach())। সমাধান সুন্দর না, কিন্তু এটা হয় সম্ভব।

সতর্কতা : আপনার ব্যবসার যুক্তি নিয়ন্ত্রণের জন্য এটি ব্যবহার করা উচিত নয়, তবে খালি কার্যকর করার সময় ঘটে যাওয়া ব্যতিক্রমী পরিস্থিতি পরিচালনার জন্য forEach()। যেমন কোনও উত্স হঠাৎ অ্যাক্সেসযোগ্য হয়ে যাওয়া বন্ধ করে দেয়, প্রক্রিয়াজাত জিনিসগুলির মধ্যে একটি চুক্তি লঙ্ঘন করছে (উদাহরণস্বরূপ চুক্তি বলে যে স্ট্রিমের সমস্ত উপাদান অবশ্যই হওয়া উচিত নয় nullতবে হঠাৎ এবং অপ্রত্যাশিতভাবে সেগুলির মধ্যে একটি null) ইত্যাদি etc.

ডকুমেন্টেশন অনুসারে Iterable.forEach():

Iterable যতক্ষণ না সমস্ত উপাদান প্রক্রিয়া না করা হয় বা ক্রিয়াটি একটি ব্যতিক্রম ছুঁড়ে না দেয় ততক্ষণ প্রতিটি উপাদানের জন্য প্রদত্ত ক্রিয়াটি সম্পাদন করে ... ক্রিয়া দ্বারা নিক্ষিপ্ত ব্যতিক্রম কলারের কাছে রিলে করা হয় না।

সুতরাং আপনি একটি ব্যতিক্রম নিক্ষেপ করুন যা অবিলম্বে অভ্যন্তরীণ লুপটি ভেঙে দেবে।

কোডটি এরকম কিছু হবে - আমি এটি পছন্দ করতে পারি না তবে এটি কার্যকর হয়। আপনি নিজের শ্রেণি তৈরি করেন BreakExceptionযা প্রসারিত হয় RuntimeException

try {
    someObjects.forEach(obj -> {
        // some useful code here
        if(some_exceptional_condition_met) {
            throw new BreakException();
       }
    }
}
catch (BreakException e) {
    // here you know that your condition has been met at least once
}

লক্ষ করুন যে, try...catchহয় না প্রায় ল্যামডা অভিব্যক্তি পুরো, বরং প্রায় forEach()পদ্ধতি। এটি আরও দৃশ্যমান করার জন্য নীচের কোডটির প্রতিলিপি দেখুন যা এটি আরও স্পষ্টভাবে দেখায়:

Consumer<? super SomeObject> action = obj -> {
    // some useful code here
    if(some_exceptional_condition_met) {
        throw new BreakException();
    }
});

try {
    someObjects.forEach(action);
}
catch (BreakException e) {
    // here you know that your condition has been met at least once
}

37
আমি মনে করি এটি একটি খারাপ অনুশীলন এবং সমস্যার সমাধান হিসাবে বিবেচনা করা উচিত নয়। এটি বিপজ্জনক কারণ এটি কোনও নবজাতকের পক্ষে বিভ্রান্তিকর হতে পারে। কার্যকর জাভা 2 য় সংস্করণ অনুসারে, অধ্যায় 9, আইটেম 57: 'কেবলমাত্র ব্যতিক্রমী অবস্থার জন্য ব্যতিক্রমগুলি ব্যবহার করুন'। তদতিরিক্ত 'প্রোগ্রামিং ত্রুটিগুলি নির্দেশ করতে রানটাইম ব্যতিক্রমগুলি ব্যবহার করুন'। চূড়ান্তভাবে, আমি এই সমাধানটি বিবেচনা করে কাউকে @ জেসার সমাধানটি সন্ধানের জন্য দৃ strongly়ভাবে উত্সাহিত করি।
লুই এফ

15
@LouisF। আমি স্পষ্টভাবে বলেছি "আমি বলতে পছন্দ করতে পারি না এটি আমার পছন্দ তবে এটি কার্যকর"। ওপিতে "ফর (প্রতিটি ()) থেকে কীভাবে বিরতি নেওয়ার প্রশ্ন করা হয়েছিল এবং এটি একটি উত্তর। আমি সম্পূর্ণরূপে সম্মত হই যে এটি ব্যবসায়ের যুক্তি নিয়ন্ত্রণ করতে ব্যবহার করা উচিত নয়। তবে আমি কিছু দরকারী ব্যবহারের ক্ষেত্রে কল্পনা করতে পারি, যেমন একটি উত্সের সাথে সংযোগ হঠাৎ forEach () বা এর মাঝখানে পাওয়া যায় না, যার জন্য ব্যতিক্রম ব্যবহার খারাপ অভ্যাস নয়। আমার উত্তরটি পরিষ্কার হওয়ার জন্য আমি একটি অনুচ্ছেদ যুক্ত করেছি।
হনজা জিদেক

1
আমি মনে করি এটি একটি সূক্ষ্ম সমাধান। "জাভা ব্যতিক্রমগুলি" এবং "সর্বাধিক অনুশীলন" বা "চেক না করা" ইত্যাদি আরও কয়েকটি শব্দ সহ অন্যান্য অনুসন্ধানগুলির জন্য গুগল অনুসন্ধান করার পরে, আমি দেখি কীভাবে ব্যতিক্রমগুলি ব্যবহার করবেন সে সম্পর্কে বিতর্ক রয়েছে। আমি এই কোডটি আমার কোডটিতে ব্যবহার করেছি কারণ স্ট্রিমটি এমন একটি মানচিত্র সম্পাদন করছে যা কয়েক মিনিট সময় নেয়। আমি চেয়েছিলাম যে ব্যবহারকারী টাস্কটি বাতিল করতে সক্ষম হবেন তাই পতাকাটির জন্য প্রতিটি "গণনা" ব্যবহারের জন্য প্রথম গণনাটি পরীক্ষা করে দেখেছি এবং সত্য হলে ব্যতিক্রম ছুঁড়েছি। এটি পরিষ্কার, ব্যতিক্রম কোডটি কোডের ছোট অংশে বিচ্ছিন্ন, এবং এটি কাজ করে।
জেসন

2
লক্ষ্য করুন Stream.forEachনেই না ব্যতিক্রম সম্পর্কে একই শক্তিশালী গ্যারান্টি প্রদান, কলারের কাছে রিলে হচ্ছে তাই একটি ব্যতিক্রম নিক্ষেপ জন্য এই ভাবে কাজ করতে নিশ্চিত করা হয় না Stream.forEach
রেডিওডেফ

1
@ রেডিওডেফ এটি একটি বৈধ পয়েন্ট, ধন্যবাদ। মূল পোস্টটি প্রায় ছিল Iterable.forEach(), তবে আমি আপনার পয়েন্টটি কেবল সম্পূর্ণতার জন্য আমার পাঠ্যে যুক্ত করেছি।
হনজা জিদেক

43

ল্যাম্বডায় ফিরে আসা প্রতিটি জন্য সমাপ্তির সমান, তবে বিরতির সমান হয় না is আপনি চালিয়ে যাওয়ার জন্য কেবল একটি রিটার্ন করতে পারেন:

someObjects.forEach(obj -> {
   if (some_condition_met) {
      return;
   }
})

2
সাধারণ প্রয়োজনের সমাধান করার জন্য দুর্দান্ত এবং অজ্ঞাতসুলভ সমাধান। গৃহীত উত্তর প্রয়োজনীয়তা বহন করে।
ডেভিডএক্সএক্সএক্সএক্স

6
অন্য কথায় এটি "জাভা 8 স্ট্রিম ফর ইচ থেকে বিরতি বা ফিরে আসবে না" যা আসল প্রশ্ন ছিল
জারোস্লাভ জারুবা

1
এটি উত্স স্ট্রিমের মাধ্যমে এখনও "টান" রেকর্ডগুলি রাখবে, যদি আপনি কোনও ধরণের দূরবর্তী ডেটাসেটের মাধ্যমে পেজিং করেন তবে তা খারাপ।
অ্যাড্রিয়ান বেকার

23

নীচে আপনি কোনও প্রকল্পে আমি যে সমাধানটি ব্যবহার করেছি তা সন্ধান করুন। পরিবর্তে forEachকেবল ব্যবহার করুন allMatch:

someObjects.allMatch(obj -> {
    return !some_condition_met;
});

11

হয় আপনাকে এমন একটি পদ্ধতি ব্যবহার করতে হবে যা চালিয়ে যাওয়া চালিয়ে যাবে কিনা তা নির্দেশ করে একটি প্রিকেট ব্যবহার করে (সুতরাং এর পরিবর্তে এর বিরতি রয়েছে) অথবা আপনাকে একটি ব্যতিক্রম ছোঁড়াতে হবে - এটি অবশ্যই খুব কুরুচিপূর্ণ পদ্ধতির।

সুতরাং আপনি forEachConditionalএই জাতীয় পদ্ধতি লিখতে পারেন:

public static <T> void forEachConditional(Iterable<T> source,
                                          Predicate<T> action) {
    for (T item : source) {
        if (!action.test(item)) {
            break;
        }
    }
}

পরিবর্তে Predicate<T>, আপনি একই সাধারণ পদ্ধতির সাথে নিজের ক্রিয়াকলাপের ইন্টারফেসটি সংজ্ঞায়িত করতে চাইতে পারেন (কিছু নেওয়ার Tএবং প্রত্যাবর্তনকারী কিছু bool) তবে এমন নাম সহ যা প্রত্যাশাটিকে আরও স্পষ্টভাবে নির্দেশ করে - Predicate<T>এখানে আদর্শ নয়।


1
আমি পরামর্শ দিচ্ছি যে জাভা 8 কোনওভাবেই ব্যবহার করা হচ্ছে তবে এই স্ট্রিমস এপিআই এবং এখানে কার্যকরী পদ্ধতির ব্যবহারটি এই সহায়ক পদ্ধতিটি তৈরি করার চেয়ে পছন্দনীয়।
স্কিভি

3
এটি ক্লাসিক takeWhileঅপারেশন এবং এই প্রশ্নটি তাদের মধ্যে একজন যারা স্ট্রিমস এপিআইতে এর অভাবটি কতটা অনুভূত হয়েছে তা প্রদর্শন করে।
মার্কো টপলনিক

2
@ মারকো: টেকওহিল আরও অনুভব করে যে এটি কোনও ক্রিয়াকলাপ না করে আইটেম ফল দেওয়ার একটি অপারেশন হবে। অবশ্যই .NET- এ লিনকিতে পার্শ্ব-প্রতিক্রিয়া সহ অ্যাকশন সহ টেকহাইল ব্যবহার করা খারাপ ব্যবহার হবে।
জন স্কিটি

9

আপনি java8 + rxjava ব্যবহার করতে পারেন ।

//import java.util.stream.IntStream;
//import rx.Observable;

    IntStream intStream  = IntStream.range(1,10000000);
    Observable.from(() -> intStream.iterator())
            .takeWhile(n -> n < 10)
            .forEach(n-> System.out.println(n));

8
জাভা 9 স্ট্রিমগুলিতে টেকওহাইল অপারেশনের জন্য সমর্থন সরবরাহ করবে।
পিসারুক

6

সমান্তরাল অপারেশনে সর্বাধিক পারফরম্যান্সের জন্য FindAny () অনুসন্ধান করুন যা ফাইন্ড ফার্স্ট () এর সমান।

Optional<SomeObject> result =
    someObjects.stream().filter(obj -> some_condition_met).findAny();

তবে যদি কোনও স্থিতিশীল ফলাফল পছন্দ হয় তবে পরিবর্তে ফাইন্ডফার্স () ব্যবহার করুন।

এছাড়াও নোট করুন যে মিলের প্যাটার্নগুলি (যে কোনও ম্যাচ () / অলম্যাচ) কেবল বুলিয়ানই ফিরিয়ে দেবে, আপনি মিলিত অবজেক্টটি পাবেন না।


6

জাভা 9+ এর সাথে আপডেট করুন takeWhile:

MutableBoolean ongoing = MutableBoolean.of(true);
someobjects.stream()...takeWhile(t -> ongoing.value()).forEach(t -> {
    // doing something.
    if (...) { // want to break;
        ongoing.setFalse();
    }
});

3

আমি এরকম কিছু দ্বারা অর্জন করেছি

  private void doSomething() {
            List<Action> actions = actionRepository.findAll();
            boolean actionHasFormFields = actions.stream().anyMatch(actionHasMyFieldsPredicate());
            if (actionHasFormFields){
                context.addError(someError);
            }
        }
    }

    private Predicate<Action> actionHasMyFieldsPredicate(){
        return action -> action.getMyField1() != null;
    }

3

আপনি পিক (..) এবং যে কোনও ম্যাচ (..) এর মিশ্রণ ব্যবহার করে এটি অর্জন করতে পারেন।

আপনার উদাহরণ ব্যবহার করে:

someObjects.stream().peek(obj -> {
   <your code here>
}).anyMatch(obj -> !<some_condition_met>);

অথবা কেবল একটি জেনেরিক ব্যবহার পদ্ধতি লিখুন:

public static <T> void streamWhile(Stream<T> stream, Predicate<? super T> predicate, Consumer<? super T> consumer) {
    stream.peek(consumer).anyMatch(predicate.negate());
}

এবং তারপরে এটি ব্যবহার করুন:

streamWhile(someObjects.stream(), obj -> <some_condition_met>, obj -> {
   <your code here>
});

0

এটা কেমন:

final BooleanWrapper condition = new BooleanWrapper();
someObjects.forEach(obj -> {
   if (condition.ok()) {
     // YOUR CODE to control
     condition.stop();
   }
});

কোথায় BooleanWrapperএকটি বর্গ আপনি প্রবাহ নিয়ন্ত্রণ করতে বাস্তবায়ন করতে হবে।


3
নাকি অ্যাটমিকবুলিয়ান?
কোকজে

1
!condition.ok()যাইহোক এটি যাইহোক forEach()সমস্ত বস্তুর উপর লুপিং করা থেকে বিরত রাখে না তখন এই বস্তুর প্রক্রিয়াকরণ এড়িয়ে যায়। যদি ধীর অংশটি forEach()পুনরাবৃত্তি হয় এবং এটির ভোক্তা নয় (যেমন, এটি ধীর নেটওয়ার্ক সংযোগ থেকে বস্তু পায়) তবে এই পদ্ধতিটি খুব কার্যকর নয়।
জাকম্যাক

হ্যাঁ আপনি ঠিক বলেছেন, আমার উত্তরটি এক্ষেত্রে বেশ ভুল।
টমাস ডিকাক্স

0
int valueToMatch = 7;
Stream.of(1,2,3,4,5,6,7,8).anyMatch(val->{
   boolean isMatch = val == valueToMatch;
   if(isMatch) {
      /*Do whatever you want...*/
       System.out.println(val);
   }
   return isMatch;
});

এটি কেবল অপারেশন করবে যেখানে এটি মিলবে এবং এটি মিলের পরে এটি পুনরাবৃত্তি বন্ধ করবে।


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