স্ট্রিম :: ফ্ল্যাটম্যাপ সহ জাভা 8 এর Oচ্ছিক ব্যবহার করা


240

নতুন জাভা 8 স্ট্রিম ফ্রেমওয়ার্ক এবং বন্ধুরা কিছু খুব সংক্ষিপ্ত জাভা কোড তৈরি করে, তবে আমি একটি আপাতদৃষ্টিতে-সহজ পরিস্থিতিটি দেখতে পেয়েছি যা সংক্ষিপ্তভাবে করা জটিল।

বিবেচনা a List<Thing> things এবং পদ্ধতিOptional<Other> resolve(Thing thing) । আমি Thingএস এর মানচিত্র তৈরি করতে Optional<Other>এবং প্রথম পেতে চাই Other। সুস্পষ্ট সমাধানটি ব্যবহার করা হবে things.stream().flatMap(this::resolve).findFirst()তবে এটি flatMapপ্রয়োজন যে আপনি কোনও স্ট্রিম ফিরিয়ে দিন এবং এর Optionalকোনও stream()পদ্ধতি নেই (বা এটি একটি Collectionবা এটি রূপান্তর করার জন্য কোনও পদ্ধতি সরবরাহ করে বা এটি হিসাবে দেখুন Collection)।

আমি যে সেরাটির সাথে আসতে পারি তা হ'ল:

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .findFirst();

তবে এটি খুব সাধারণ ক্ষেত্রে বলে মনে হচ্ছে এটি অত্যন্ত ভয়ঙ্কর বলে মনে হচ্ছে। কারও ভাল ধারণা আছে?


আপনার উদাহরণের সাথে কিছুটা কোড করার পরে, আমি প্রকৃতপক্ষে স্পষ্টভাবে প্রকাশিত সংস্করণটির থেকে বেশি পঠনযোগ্য এটি .flatMap(Optional::toStream)দেখতে পাই, এটির উপস্থিতি থাকলে , আপনার সংস্করণ সহ আপনি দেখতে পাচ্ছেন যা চলছে।
স্কিভি

19
@ স্কিভি ওয়েল, Optional.streamএখন জেডিকে 9-তে রয়েছে ....
স্টুয়ার্ট মার্কস

আমি কৌতূহল করছি যেখানে এটি নথিভুক্ত করা হয়েছে এবং এটি কীভাবে প্রবর্তন করার প্রক্রিয়াটি ছিল। কিছু অন্যান্য পদ্ধতি রয়েছে যা সত্যই মনে হচ্ছে তাদের উপস্থিতি থাকা উচিত এবং আমি আগ্রহী যেখানে এপিআই পরিবর্তনগুলির জন্য আলোচনা চলছে।
যোনা অ্যাপলেট্রি


10
মজার বিষয় হ'ল জেডিকে -8050820 আসলে তার বিবরণে এই প্রশ্নটিকে বোঝায়!
দিদিয়ের এল

উত্তর:


265

জাভা 9

Optional.stream জেডিকে ৯-এ যুক্ত করা হয়েছে এটি কোনও সহায়ক পদ্ধতির প্রয়োজন ছাড়াই আপনাকে নিম্নলিখিতগুলি করতে সক্ষম করে:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(Optional::stream)
          .findFirst();

জাভা 8

হ্যাঁ, এটি এপিআই-এর একটি ছোট গর্ত ছিল, এটিকে Optional<T>একটি শূন্য বা এক-দৈর্ঘ্যে রূপান্তর করা কিছুটা অসুবিধে Stream<T>। আপনি এটি করতে পারেন:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
          .findFirst();

এর ভিতরে টেরিনারি অপারেটরটি থাকা flatMapকিছুটা জটিল, যদিও এটি করার জন্য একটু সহায়ক ফাংশনটি লেখার চেয়ে ভাল হতে পারে:

/**
 * Turns an Optional<T> into a Stream<T> of length zero or one depending upon
 * whether a value is present.
 */
static <T> Stream<T> streamopt(Optional<T> opt) {
    if (opt.isPresent())
        return Stream.of(opt.get());
    else
        return Stream.empty();
}

Optional<Other> result =
    things.stream()
          .flatMap(t -> streamopt(resolve(t)))
          .findFirst();

এখানে, আমি resolve()পৃথক map()অপারেশন না করে কলটি ইনডিল করেছি , তবে এটি স্বাদের বিষয়।


2
আমি মনে করি না এপিআই এখন জাভা 9 অবধি পরিবর্তন হতে পারে।
Assylias

5
@ হাইফার ধন্যবাদ .ফিল্টার ()। মানচিত্র () কৌশলটি খুব খারাপ নয় এবং সহায়ক পদ্ধতির উপর নির্ভরশীলতা এড়িয়ে চলে। 'যদিও আরও সংক্ষিপ্ত উপায় থাকলে দ্বিগুণ হ'ল। আমি অপশনাল.স্ট্রিম () যুক্ত করে তদন্ত করব।
স্টুয়ার্ট

43
আমি পছন্দ করি:static <T> Stream<T> streamopt(Optional<T> opt) { return opt.map(Stream::of).orElse(Stream.empty()); }
kubek2k

5
আমি আশা করি তারা কেবলমাত্র একটি Optionalওভারলোড যুক্ত করে Stream#flatMap... আপনি কেবল লিখতে পারতেনstream().flatMap(this::resolve)
ফ্লাকস

4
@ ফ্লাক্স হ্যাঁ আমরা এই ধারণাটি সম্পর্কে লাথি মেরেছি, তবে এখন এটি (জেডিকে 9-এ) যে পরিমাণ মূল্য রয়েছে তা এতটা যুক্ত করবে বলে মনে হয় না Optional.stream()
স্টুয়ার্ট

69

আমি ব্যবহারকারী দ্বারা প্রস্তাবিত সম্পাদনার উপরে ভিত্তি করে এই দ্বিতীয় উত্তর যোগ করছি srborlongan করতে আমার অন্যান্য জবাব । আমি মনে করি প্রস্তাবিত কৌশলটি আকর্ষণীয় ছিল, তবে এটি আমার উত্তরের সম্পাদনা হিসাবে উপযুক্ত ছিল না। অন্যরা সম্মত হন এবং প্রস্তাবিত সম্পাদনাটি ভোট বাতিল হয়ে যায়। (আমি ভোটারদের মধ্যে একজন ছিলাম না।) যদিও কৌশলটির যোগ্যতা রয়েছে। শ্রাবরলংগান তার নিজের উত্তর পোস্ট করলে ভাল হত best এটি এখনও ঘটেনি, এবং আমি চাইনি যে স্ট্যাক ওভারফ্লো এর সম্পাদনা ইতিহাস প্রত্যাখাত হয়ে গেছে তার কৌশলগুলি হারিয়ে যেতে পারে, তাই আমি নিজেই এটি একটি পৃথক উত্তর হিসাবে উপস্থাপন করার সিদ্ধান্ত নিয়েছি।

মূলত কৌশলটি হ'ল Optionalকোনও টেরিনারি অপারেটর ( ? :) বা যদি / অন্য বিবৃতি ব্যবহার না করা হয় তবে এ জন্য কয়েকটি কৌশলকে চতুর উপায়ে ব্যবহার করা ।

আমার ইনলাইন উদাহরণটি এইভাবে আবার লেখা হবে:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
          .findFirst();

আমার উদাহরণ যা সহায়ক সহায়ক পদ্ধতি ব্যবহার করে সেগুলি এইভাবেই আবার লিখিত হবে:

/**
 * Turns an Optional<T> into a Stream<T> of length zero or one depending upon
 * whether a value is present.
 */
static <T> Stream<T> streamopt(Optional<T> opt) {
    return opt.map(Stream::of)
              .orElseGet(Stream::empty);
}

Optional<Other> result =
    things.stream()
          .flatMap(t -> streamopt(resolve(t)))
          .findFirst();

ধারাভাষ্য

আসুন মূল বনাম পরিবর্তিত সংস্করণগুলি সরাসরি তুলনা করুন:

// original
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())

// modified
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))

মূলটি যদি সরল থাকে তবে কাজের লোকের মতো দৃষ্টিভঙ্গি: আমরা একটি পাই Optional<Other>; যদি এর কোনও মান থাকে তবে আমরা সেই মানটি সহ একটি স্ট্রিম ফিরিয়ে দেব এবং যদি এর কোনও মূল্য না থাকে তবে আমরা খালি প্রবাহটি ফিরিয়ে দেব। খুব সহজ এবং ব্যাখ্যা করা সহজ।

পরিবর্তনটি চতুর এবং এতে সুবিধা রয়েছে যে এটি শর্তযুক্ত এড়ায়। (আমি জানি যে কিছু লোক টার্নারি অপারেটরকে অপছন্দ করে। এটির অপব্যবহার করা হলে কোডটি বোঝা সত্যিই শক্ত করে তুলবে)) তবে, কখনও কখনও জিনিসগুলি খুব চালাক হতে পারে। পরিবর্তিত কোডটি একটি দিয়ে শুরু হয় Optional<Other>। তারপরে এটি কল করে Optional.mapযা নিম্নলিখিত হিসাবে সংজ্ঞায়িত হয়েছে:

যদি কোনও মান উপস্থিত থাকে তবে এটিতে প্রদত্ত ম্যাপিং ফাংশনটি প্রয়োগ করুন এবং ফলাফলটি যদি শূন্য হয় তবে ফলাফলটি বর্ণনা করে একটি ptionচ্ছিক ফিরিয়ে দিন। অন্যথায় একটি খালি returnচ্ছিক ফিরে আসুন।

map(Stream::of)কল করবেন তা একটি ফেরৎ Optional<Stream<Other>>। Aচ্ছিক ইনপুটটিতে কোনও মান উপস্থিত থাকলে, প্রত্যাশিত ptionচ্ছিকটিতে একটি স্ট্রিম থাকে যা একক অন্যান্য ফলাফল ধারণ করে। তবে মানটি উপস্থিত না থাকলে ফলাফলটি একটি খালি ptionচ্ছিক।

এরপরে, কলটি orElseGet(Stream::empty)প্রকারের মান প্রদান করে Stream<Other>। যদি এর ইনপুট মানটি উপস্থিত থাকে তবে এটি মানটি পায় যা একক-উপাদান Stream<Other>। অন্যথায় (যদি ইনপুট মানটি অনুপস্থিত থাকে) এটি একটি খালি দেয় Stream<Other>। সুতরাং ফলাফলটি সঠিক, মূল শর্তাধীন কোডের মতো।

প্রত্যাখাত সম্পাদনা সম্পর্কে আমার উত্তরে আলোচনা করা মন্তব্যে আমি এই কৌশলটিকে "আরও সংক্ষিপ্ত তবে আরও অস্পষ্ট" হিসাবে বর্ণনা করেছি। আমি এর পাশে দাঁড়িয়ে আছি। এটি কী করছে তা নির্ধারণ করতে আমার কিছুটা সময় লেগেছে, এবং এটি কী করছে তার উপরের বর্ণনাটি লিখতে আমার কিছুটা সময় লেগেছে। কী তনিমা থেকে রূপান্তর হয় Optional<Other>থেকে Optional<Stream<Other>>। একবার আপনি এটাকে ছাঁটাই করে ফেললে তা বোঝা যায়, তবে তা আমার কাছে স্পষ্ট ছিল না।

যদিও আমি স্বীকার করব যে প্রাথমিকভাবে অস্পষ্ট বিষয়গুলি সময়ের সাথে সাথে মূর্তিমান হয়ে উঠতে পারে। এটি হতে পারে যে এই কৌশলটি ব্যবহারের সর্বোত্তম উপায় হিসাবে শেষ হয়, অন্তত Optional.streamযোগ না হওয়া অবধি (যদি এটি কখনও না ঘটে)।

আপডেট: Optional.stream জেডিকে 9 এ যুক্ত করা হয়েছে।


16

আপনি ইতিমধ্যে যা করছেন আপনি এটি আরও সংক্ষিপ্ত করতে পারবেন না।

আপনি দাবি করেন যে আপনি চান না .filter(Optional::isPresent) এবং .map(Optional::get)

এটি @ স্টার্টমার্কস বর্ণনা করার পদ্ধতি দ্বারা সমাধান করা হয়েছে, তবে ফলস্বরূপ আপনি এখন এটিকে ম্যাপ করেন Optional<T>, সুতরাং এখন আপনাকে ব্যবহারের প্রয়োজন এবং শেষ পর্যন্ত .flatMap(this::streamopt)একটি দরকার get()

সুতরাং এটি এখনও দুটি বিবৃতি নিয়ে গঠিত এবং আপনি এখন নতুন পদ্ধতিতে ব্যতিক্রম পেতে পারেন! কারণ, যদি প্রতিটি alচ্ছিক খালি থাকে? তারপরে findFirst()একটি খালি alচ্ছিকটি ফিরে আসবে এবং আপনার get()ব্যর্থ হবে!

সুতরাং আপনার যা আছে:

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .findFirst();

হয় আসলে সবচেয়ে ভালো উপায় সম্পন্ন করার জন্য আপনি যা চান তা, এবং যে আপনি একটি যেমন ফলাফলের সংরক্ষণ করতে চান হয় Tএকটি হিসেবে নয়, Optional<T>

আমি একটি CustomOptional<T>ক্লাস তৈরির স্বাধীনতা গ্রহণ করেছি যা Optional<T>একটি অতিরিক্ত পদ্ধতি সরবরাহ করে, এবং flatStream()। নোট করুন যে আপনি প্রসারিত করতে পারবেন না Optional<T>:

class CustomOptional<T> {
    private final Optional<T> optional;

    private CustomOptional() {
        this.optional = Optional.empty();
    }

    private CustomOptional(final T value) {
        this.optional = Optional.of(value);
    }

    private CustomOptional(final Optional<T> optional) {
        this.optional = optional;
    }

    public Optional<T> getOptional() {
        return optional;
    }

    public static <T> CustomOptional<T> empty() {
        return new CustomOptional<>();
    }

    public static <T> CustomOptional<T> of(final T value) {
        return new CustomOptional<>(value);
    }

    public static <T> CustomOptional<T> ofNullable(final T value) {
        return (value == null) ? empty() : of(value);
    }

    public T get() {
        return optional.get();
    }

    public boolean isPresent() {
        return optional.isPresent();
    }

    public void ifPresent(final Consumer<? super T> consumer) {
        optional.ifPresent(consumer);
    }

    public CustomOptional<T> filter(final Predicate<? super T> predicate) {
        return new CustomOptional<>(optional.filter(predicate));
    }

    public <U> CustomOptional<U> map(final Function<? super T, ? extends U> mapper) {
        return new CustomOptional<>(optional.map(mapper));
    }

    public <U> CustomOptional<U> flatMap(final Function<? super T, ? extends CustomOptional<U>> mapper) {
        return new CustomOptional<>(optional.flatMap(mapper.andThen(cu -> cu.getOptional())));
    }

    public T orElse(final T other) {
        return optional.orElse(other);
    }

    public T orElseGet(final Supplier<? extends T> other) {
        return optional.orElseGet(other);
    }

    public <X extends Throwable> T orElseThrow(final Supplier<? extends X> exceptionSuppier) throws X {
        return optional.orElseThrow(exceptionSuppier);
    }

    public Stream<T> flatStream() {
        if (!optional.isPresent()) {
            return Stream.empty();
        }
        return Stream.of(get());
    }

    public T getTOrNull() {
        if (!optional.isPresent()) {
            return null;
        }
        return get();
    }

    @Override
    public boolean equals(final Object obj) {
        return optional.equals(obj);
    }

    @Override
    public int hashCode() {
        return optional.hashCode();
    }

    @Override
    public String toString() {
        return optional.toString();
    }
}

আপনি দেখতে পাবেন যে আমি flatStream()এখানে যুক্ত করেছি:

public Stream<T> flatStream() {
    if (!optional.isPresent()) {
        return Stream.empty();
    }
    return Stream.of(get());
}

হিসাবে ব্যবহার:

String result = Stream.of("a", "b", "c", "de", "fg", "hij")
        .map(this::resolve)
        .flatMap(CustomOptional::flatStream)
        .findFirst()
        .get();

আপনাকে এখনওStream<T> এখানে ফিরে আসতে হবে , যেমন আপনি ফিরতে পারবেন না T, কারণ যদি !optional.isPresent()তাই হয় T == nullতবে আপনি যদি এটির ঘোষণা দেন তবে আপনার প্রবাহে .flatMap(CustomOptional::flatStream)যুক্ত nullকরার চেষ্টা করা হবে এবং এটি সম্ভব নয়।

উদাহরণ স্বরূপ:

public T getTOrNull() {
    if (!optional.isPresent()) {
        return null;
    }
    return get();
}

হিসাবে ব্যবহার:

String result = Stream.of("a", "b", "c", "de", "fg", "hij")
        .map(this::resolve)
        .map(CustomOptional::getTOrNull)
        .findFirst()
        .get();

NullPointerExceptionস্ট্রিম ক্রিয়াকলাপগুলির ভিতরে এখন একটি ছোঁড়াবে।

উপসংহার

আপনি যে পদ্ধতিটি ব্যবহার করেছেন, তা আসলে সেরা পদ্ধতি।


6

একটি সামান্য সংক্ষিপ্ত সংস্করণ ব্যবহার করে reduce:

things.stream()
  .map(this::resolve)
  .reduce(Optional.empty(), (a, b) -> a.isPresent() ? a : b );

আপনি হ্রাস ফাংশনটি একটি স্থিতিশীল ইউটিলিটি পদ্ধতিতেও সরিয়ে নিতে পারেন এবং তারপরে এটি হয়ে যায়:

  .reduce(Optional.empty(), Util::firstPresent );

6
আমি এটি পছন্দ করি, তবে এটি উল্লেখ করার মতো যে এটি স্ট্রিমের প্রতিটি আইটেমকে মূল্যায়ন করবে, যদিও ফাইন্ডফার্স () কেবল উপস্থিত আইটেমটি না পাওয়া পর্যন্ত মূল্যায়ন করবে।
ডানকান ম্যাকগ্রিগোর

1
এবং দুর্ভাগ্যক্রমে, প্রতিটি সংকল্প কার্যকর করাই একটি চুক্তি-বিভক্তকারী। তবে এটি চালাক।
ইওনা অ্যাপলেট্রি

5

আমার পূর্ববর্তী উত্তরটি খুব জনপ্রিয় না হিসাবে দেখা গেছে, আমি এটিকে আরও একবার দেব।

একটি সংক্ষিপ্ত উত্তর:

আপনি বেশিরভাগই সঠিক পথে রয়েছেন। আপনার কাঙ্ক্ষিত আউটপুটটিতে পৌঁছানোর জন্য সবচেয়ে সংক্ষিপ্ত কোডটি হ'ল এটি হ'ল:

things.stream()
      .map(this::resolve)
      .filter(Optional::isPresent)
      .findFirst()
      .flatMap( Function.identity() );

এটি আপনার সমস্ত প্রয়োজনীয়তার সাথে খাপ খায়:

  1. এটি প্রথম প্রতিক্রিয়াটি খুঁজে পাবে যা কোনও মীমাংসার সমাধান না করে Optional<Result>
  2. এটি this::resolveপ্রয়োজন হিসাবে অলস কল
  3. this::resolve প্রথম খালি ফলাফলের পরে ডাকা হবে না
  4. এটি ফিরে আসবে Optional<Result>

দীর্ঘ উত্তর

ওপি প্রাথমিক সংস্করণের তুলনায় একমাত্র পরিবর্তন হ'ল আমি .map(Optional::get)কল করার আগে সরিয়েছি .findFirst()এবং .flatMap(o -> o)চেইনে শেষ কল হিসাবে যুক্ত করেছি ।

ডাবল-ptionচ্ছিক থেকে মুক্তি পাওয়ার এটির দুর্দান্ত প্রভাব রয়েছে, যখনই স্ট্রিম সত্যিকারের ফলাফল খুঁজে পায়।

আপনি জাভাতে এর চেয়ে কম সংক্ষেপে যেতে পারবেন না।

আরও প্রচলিত forলুপ কৌশলটি ব্যবহার করে কোডের বিকল্প স্নিপেটটি প্রায় একই সংখ্যার কোডের লাইন হতে চলেছে এবং আপনার কমপক্ষে একই ক্রম এবং ক্রিয়াকলাপের সংখ্যা থাকতে হবে:

  1. কলিং this.resolve,
  2. উপর ভিত্তি করে ফিল্টারিং Optional.isPresent
  3. ফলাফল ফিরে এবং
  4. নেতিবাচক ফলাফল মোকাবেলার কিছু উপায় (যখন কিছুই খুঁজে পাওয়া যায় নি)

আমার সমাধান বিজ্ঞাপন হিসাবে কাজ করে তা প্রমাণ করার জন্য, আমি একটি ছোট পরীক্ষা প্রোগ্রাম লিখেছিলাম:

public class StackOverflow {

    public static void main( String... args ) {
        try {
            final int integer = Stream.of( args )
                    .peek( s -> System.out.println( "Looking at " + s ) )
                    .map( StackOverflow::resolve )
                    .filter( Optional::isPresent )
                    .findFirst()
                    .flatMap( o -> o )
                    .orElseThrow( NoSuchElementException::new )
                    .intValue();

            System.out.println( "First integer found is " + integer );
        }
        catch ( NoSuchElementException e ) {
            System.out.println( "No integers provided!" );
        }
    }

    private static Optional<Integer> resolve( String string ) {
        try {
            return Optional.of( Integer.valueOf( string ) );
        }
        catch ( NumberFormatException e )
        {
            System.out.println( '"' + string + '"' + " is not an integer");
            return Optional.empty();
        }
    }

}

(এটিতে ডিবাগিং এবং যাচাই করার জন্য কয়েকটি অতিরিক্ত লাইন রয়েছে যা কেবলমাত্র যতগুলি কল প্রয়োজন হিসাবে সমাধান করার জন্য ...)

কমান্ড লাইনে এটি সম্পাদন করে আমি নিম্নলিখিত ফলাফল পেয়েছি:

$ java StackOferflow a b 3 c 4
Looking at a
"a" is not an integer
Looking at b
"b" is not an integer
Looking at 3
First integer found is 3

আমি রোল্যান্ড টেপ হিসাবে একই মনে হয়। কেন কেউ <স্ট্রিম <? >> স্ট্রিম তৈরি করতে এবং যখন আপনি কেবলমাত্র একটি বিকল্পের সাথে <ফ্ল্যাট করতে পারেন <বিকল্প>? >>
ইয়ং হায়ুন ইয়ু

3

যদি আপনি কোনও তৃতীয় পক্ষের লাইব্রেরি ব্যবহার করতে আপত্তি না করেন তবে আপনি জাভাসল্যাং ব্যবহার করতে পারেন । এটি স্কালার মতো তবে জাভাতে প্রয়োগ করা হয়েছে।

এটি একটি সম্পূর্ণ অপরিবর্তনীয় সংগ্রহের পাঠাগার সহ আসে যা স্কালার সাথে পরিচিত। এই সংগ্রহগুলি জাভা সংগ্রহ এবং জাভা 8 এর স্ট্রিম প্রতিস্থাপন করে। এটি অপশনের নিজস্ব বাস্তবায়নও করে।

import javaslang.collection.Stream;
import javaslang.control.Option;

Stream<Option<String>> options = Stream.of(Option.some("foo"), Option.none(), Option.some("bar"));

// = Stream("foo", "bar")
Stream<String> strings = options.flatMap(o -> o);

প্রাথমিক প্রশ্নের উদাহরণের জন্য এখানে একটি সমাধান রয়েছে:

import javaslang.collection.Stream;
import javaslang.control.Option;

public class Test {

    void run() {

        // = Stream(Thing(1), Thing(2), Thing(3))
        Stream<Thing> things = Stream.of(new Thing(1), new Thing(2), new Thing(3));

        // = Some(Other(2))
        Option<Other> others = things.flatMap(this::resolve).headOption();
    }

    Option<Other> resolve(Thing thing) {
        Other other = (thing.i % 2 == 0) ? new Other(i + "") : null;
        return Option.of(other);
    }

}

class Thing {
    final int i;
    Thing(int i) { this.i = i; }
    public String toString() { return "Thing(" + i + ")"; }
}

class Other {
    final String s;
    Other(String s) { this.s = s; }
    public String toString() { return "Other(" + s + ")"; }
}

দাবি অস্বীকার: আমি জাভাসলং এর নির্মাতা।


3

পার্টিতে দেরিতে, তবে কী হবে

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .findFirst().get();

আপনি যদি ম্যানুয়ালি স্ট্রিমে alচ্ছিক রূপান্তর করতে কোনও ব্যবহার পদ্ধতি তৈরি করেন তবে আপনি সর্বশেষ প্রাপ্ত () থেকে মুক্তি পেতে পারেন:

things.stream()
    .map(this::resolve)
    .flatMap(Util::optionalToStream)
    .findFirst();

আপনি যদি আপনার সমাধানের কাজটি থেকে সরাসরি স্রোত ফিরে পান তবে আপনি আরও একটি লাইন সংরক্ষণ করেন।


3

আমি কার্যকরী এপিআইয়ের জন্য সহায়ক তৈরির জন্য কারখানার পদ্ধতিগুলি প্রচার করতে চাই :

Optional<R> result = things.stream()
        .flatMap(streamopt(this::resolve))
        .findFirst();

কারখানার পদ্ধতি:

<T, R> Function<T, Stream<R>> streamopt(Function<T, Optional<R>> f) {
    return f.andThen(Optional::stream); // or the J8 alternative:
    // return t -> f.apply(t).map(Stream::of).orElseGet(Stream::empty);
}

রিজনিং:

  • ল্যাম্বডা এক্সপ্রেশনগুলির তুলনায় সাধারণভাবে পদ্ধতির উল্লেখগুলির সাথে আপনি দুর্ঘটনাক্রমে অ্যাক্সেসযোগ্য সুযোগ থেকে কোনও পরিবর্তনশীল ক্যাপচার করতে পারবেন না, যেমন:

    t -> streamopt(resolve(o))

  • এটি কম্পোজেবল, আপনি উদাহরণস্বরূপ Function::andThenকারখানার পদ্ধতির ফলাফলটিতে কল করতে পারেন :

    streamopt(this::resolve).andThen(...)

    যদিও ল্যাম্বদার ক্ষেত্রে আপনাকে প্রথমে এটি castালাই করা দরকার:

    ((Function<T, Stream<R>>) t -> streamopt(resolve(t))).andThen(...)



3

আপনি যদি জাভা 8 এর সাথে আটকে থাকেন তবে পেয়ারা 21.0 বা আরও নতুন অ্যাক্সেস পান তবে আপনি একটি alচ্ছিককে Streams.streamএকটি স্ট্রিমে রূপান্তর করতে ব্যবহার করতে পারেন ।

সুতরাং, দেওয়া

import com.google.common.collect.Streams;

তুমি লিখতে পারো

Optional<Other> result =
    things.stream()
        .map(this::resolve)
        .flatMap(Streams::stream)
        .findFirst();

0

ওটা সম্পর্কে কি?

private static List<String> extractString(List<Optional<String>> list) {
    List<String> result = new ArrayList<>();
    list.forEach(element -> element.ifPresent(result::add));
    return result;
}

https://stackoverflow.com/a/58281000/3477539


আপনি যখন স্ট্রিম এবং সংগ্রহ করতে পারেন তখন এটি কেন করবেন?
ওয়ান ক্রিকেটার

return list.stream().filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList())), ঠিক যেমন প্রশ্নের (এবং আপনার লিঙ্কযুক্ত উত্তরটি) রয়েছে ...
ওয়ানক্রিষ্টের

আমি ভুল হতে পারি, তবে আমি ইস্প্রেসেট () ব্যবহার করে বিবেচনা করি এবং তারপরে () পাওয়া ভাল অভ্যাস নয়। তাই আমি এ থেকে দূরে সরে যাওয়ার চেষ্টা করি।
রাস্তামান

আপনি যদি .get() এটি ব্যবহার না করে ব্যবহার করেন isPresent()তবে আপনি
ইন্টেলিজজে

-5

সম্ভবত আপনি এটি ভুল করছেন।

জাভা 8 ptionচ্ছিক এই উপায় ব্যবহার করা বোঝানো হয় না। এটি কেবলমাত্র টার্মিনাল স্ট্রিম ক্রিয়াকলাপের জন্য সংরক্ষিত থাকে যা উদাহরণ হিসাবে যেমন কোনও মান ফেরত দিতে পারে বা নাও পারে।

আপনার ক্ষেত্রে এটি সমাধানযোগ্য যে আইটেমগুলি ফিল্টার করার জন্য প্রথমে সস্তা উপায় খুঁজে বের করার চেষ্টা করা ভাল এবং তারপরে প্রথম আইটেমটিকে alচ্ছিক হিসাবে পাওয়া এবং এটি শেষ অপারেশন হিসাবে সমাধান করা ভাল। আরও ভাল - ফিল্টারিংয়ের পরিবর্তে, প্রথম সমাধানযোগ্য আইটেমটি সন্ধান করুন এবং এটি সমাধান করুন।

things.filter(Thing::isResolvable)
      .findFirst()
      .flatMap(this::resolve)
      .get();

থাম্বের নিয়ম হ'ল আপনি স্ট্রিমের আইটেমগুলিকে অন্য কোনও কিছুতে রূপান্তরিত করার আগে তাদের সংখ্যা হ্রাস করার চেষ্টা করা উচিত। অবশ্যই ওয়াইএমএমভি।


6
আমি ভাবি যে ওপি'র সমাধান () পদ্ধতিটি returningচ্ছিক <অন্যথায়> ফেরত দেওয়া ptionচ্ছিকের একটি সঠিকভাবে বোধগম্য ব্যবহার। আমি অবশ্যই ওপি'র সমস্যা ডোমেনের সাথে কথা বলতে পারি না, তবে এটি এমন হতে পারে যে কোনও কিছু সমাধানযোগ্য কিনা তা নির্ধারণের উপায় এটি সমাধানের চেষ্টা করা। যদি তা হয় তবে ptionচ্ছিক একটি রেজুলেশনযোগ্য "এর সমাধানযোগ্য" এর একটি বুলিয়ান ফলাফলকে একক এপিআই কলগুলিতে ফিউজ করে successful
স্টুয়ার্ট

2
স্টুয়ার্ট মূলত সঠিক। আমার কাছে কাম্য পদক্ষেপের ক্রম অনুসারে অনুসন্ধানের পদগুলির একটি সেট রয়েছে এবং আমি প্রথমটির ফলাফলটি সন্ধান করছি যা কিছু ফিরিয়ে দেয়। তাই মূলত Optional<Result> searchFor(Term t)। এটি ptionচ্ছিকের উদ্দেশ্য অনুসারে ফিট করে fit এছাড়াও, স্ট্রিম (s গুলি) অলসভাবে মূল্যায়ন করা উচিত, সুতরাং প্রথম মিলের কোনও অতিরিক্ত কাজ সংশোধনের শর্তাবলীর উপস্থিতি হওয়া উচিত নয়।
যোনার অ্যাপলেট্রি

প্রশ্নটি পুরোপুরি বুদ্ধিমান এবং flatচ্ছিক সহ ফ্ল্যাটম্যাপ ব্যবহার করা প্রায়শই অন্যান্য, অনুরূপ প্রোগ্রামিং ভাষায় যেমন স্কালায় অনুশীলন করা হয়।
ডিজেএস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.