যদি সন্ধান করা প্রথম উপাদানটি নাল হয় তবে ফাইন্ড ফার্স্ট () কেন নালপয়েন্টার এক্সেক্সশন ফেলে দেয়?


90

কেন এটি একটি নিক্ষেপ করে java.lang.NullPointerException?

List<String> strings = new ArrayList<>();
        strings.add(null);
        strings.add("test");

        String firstString = strings.stream()
                .findFirst()      // Exception thrown here
                .orElse("StringWhenListIsEmpty");
                //.orElse(null);  // Changing the `orElse()` to avoid ambiguity

প্রথম আইটেমটি stringsহ'ল nullযা একদম গ্রহণযোগ্য মান। তদ্ব্যতীত, findFirst()একটি .চ্ছিক প্রদান করে , যা এসকেfindFirst() পরিচালনা করতে সক্ষম হওয়ার জন্য আরও বেশি অর্থবোধ করে null

সম্পাদনা: orElse()কম অস্পষ্ট হতে আপডেট হয়েছে ।


4
নাল পুরোপুরি গ্রহণযোগ্য মান নয় ... পরিবর্তে "" ব্যবহার করুন
মিশেল ল্যাকোর্ট

4
@ মিশেললাকার্ট যদিও আমি এখানে ব্যবহার করছি String, যদি এটি ডিবিতে একটি কলাম প্রতিনিধিত্ব করে এমন একটি তালিকা থাকে? এই কলামটির জন্য প্রথম সারির মান হতে পারে null
neverendingqs

হ্যাঁ তবে জাভাতে নাল গ্রহণযোগ্য নয় .. ডিবিতে নাল সেট করতে কোয়েরি ব্যবহার করুন
মিশেল ল্যাকোর্ট

10
@ মিশেলল্যাকোর্ট, nullসাধারণত জাভাতে একটি উপযুক্ত গ্রহণযোগ্য মান। বিশেষত এটি একটি এর জন্য একটি বৈধ উপাদান ArrayList<String>। অন্য যে কোনও মানের মতো তবে এর সাথে কী করা যায় তার সীমাবদ্ধতা রয়েছে। "কখনও ব্যবহার করবেন না null" দরকারী পরামর্শ নয়, কারণ আপনি এড়াতে পারবেন না।
জন বলিঞ্জার

@ নাথান হিউজেস - আমি সন্দেহ করি যে আপনি কল করার সময় আপনি findFirst()আর কিছু করতে চান না।
neverendingqs

উত্তর:


72

এর কারণটি হ'ল Optional<T>রিটার্নে ব্যবহার করা । Ptionচ্ছিক ধারণের অনুমতি নেই null। মূলত, এটি পরিস্থিতি "এটি সেখানে নেই" এবং "এটি সেখানে রয়েছে, তবে এটি সেট করা আছে" পার্থক্য করার কোনও উপায় সরবরাহ করে না null

এই কারণেই ডকুমেন্টেশনnull নির্বাচনের ক্ষেত্রে পরিস্থিতি স্পষ্টভাবে নিষিদ্ধ করে findFirst():

নিক্ষেপ:

NullPointerException - যদি নির্বাচিত উপাদানটি হয় null


4
এটি ট্র্যাক করা সহজ হবে যদি এর কোনও উদাহরণগুলির মধ্যে কোনও ব্যক্তিগত বুলিয়ান সহ কোনও মান বিদ্যমান থাকে Optional। যাইহোক, আমি মনে করি আমি রেটিংয়ের সীমানা সীমানা করছি - ভাষা যদি এটি সমর্থন না করে তবে এটি সমর্থন করে না।
neverendingqs

4
নিঃসন্দেহে, booleanএই দুটি পরিস্থিতিতে পার্থক্য করার জন্য একটি ব্যবহার করে নিখুঁত ধারণা তৈরি করা যেতে পারে। আমার কাছে মনে হচ্ছে এখানকার ব্যবহার Optional<T>প্রশ্নবিদ্ধ পছন্দ ছিল।
সের্গেই কালিনিচেনকো

4
@neverendingqs আমি এই কোনো সুন্দর বিকল্প মনে করতে পারেন না ব্যতীত আপনার নিজের নাল ঘূর্ণায়মান , যা আদর্শ পারেন নয়।
সের্গেই কালিনিচেনকো

4
আমি একটি প্রাইভেট পদ্ধতি লিখে শেষ করেছি যা কোনও Iterableধরণের, চেকগুলি থেকে পুনরাবৃত্তির অধিকারী হয় hasNext()এবং উপযুক্ত মানটি প্রদান করে।
neverendingqs

4
আমি মনে করি findFirst
পিওর

48

ইতিমধ্যে আলোচিত হিসাবে , এপিআই ডিজাইনাররা ধরে নিবেন না যে বিকাশকারী nullমান এবং অনুপস্থিত মানগুলিকে একইভাবে আচরণ করতে চায় ।

আপনি যদি এখনও এটি করতে চান তবে আপনি ক্রমটি প্রয়োগ করে এটি স্পষ্টভাবে করতে পারেন

.map(Optional::ofNullable).findFirst().flatMap(Function.identity())

প্রবাহে ফলাফল যদি উভয় ক্ষেত্রেই খালি alচ্ছিক হয়, যদি কোনও প্রথম উপাদান না থাকে বা যদি প্রথম উপাদান থাকে null। সুতরাং আপনার ক্ষেত্রে, আপনি ব্যবহার করতে পারেন

String firstString = strings.stream()
    .map(Optional::ofNullable).findFirst().flatMap(Function.identity())
    .orElse(null);

nullযদি প্রথম উপাদানটি অনুপস্থিত বা থাকে তবে একটি মান পেতে null

আপনি যদি এই কেসের মধ্যে পার্থক্য করতে চান তবে আপনি কেবল flatMapপদক্ষেপটি বাদ দিতে পারেন :

Optional<String> firstString = strings.stream()
    .map(Optional::ofNullable).findFirst().orElse(null);
System.out.println(firstString==null? "no such element":
                   firstString.orElse("first element is null"));

এটি আপনার আপডেট হওয়া প্রশ্নের চেয়ে আলাদা নয় different আপনাকে কেবল "no such element"সাথে "StringWhenListIsEmpty"এবং "first element is null"সাথে প্রতিস্থাপন করতে হবে null। তবে আপনি যদি শর্তসাপেক্ষ পছন্দ না করেন তবে আপনি এটির মতো অর্জনও করতে পারেন:

String firstString = strings.stream().skip(0)
    .map(Optional::ofNullable).findFirst()
    .orElseGet(()->Optional.of("StringWhenListIsEmpty"))
    .orElse(null);

এখন, firstStringএটি হবে nullযদি কোনও উপাদান উপস্থিত থাকে তবে তা থাকে nullএবং "StringWhenListIsEmpty"যখন কোনও উপাদান উপস্থিত না থাকে।


দুঃখিত আমি বুঝতে পেরেছি যে আমার প্রশ্নটি ইঙ্গিত করেছে যে আমি null1 এর জন্য ফিরে আসতে চেয়েছিলাম ) প্রথম উপাদানটি হয় null2) তালিকার ভিতরে কোনও উপাদান বিদ্যমান নেই exist অস্পষ্টতা অপসারণ করতে আমি প্রশ্নটি আপডেট করেছি।
neverendingqs

4
তৃতীয় কোড স্নিপেটে, একটিতে Optionalনির্ধারিত হতে পারে null। যেহেতু Optionalএকটি "মানের ধরণ" হওয়ার কথা, তাই এটি কখনই শূন্য হওয়া উচিত নয়। এবং একটি ptionচ্ছিক কখনও তুলনা করা উচিত নয় ==। কোডটি জাভা 10 :) এ ব্যর্থ হতে পারে বা কখন-কখন মূল্য মান জাভাতে প্রবর্তিত হবে।
ঝোংইউ

4
@ বায়ো.ইও: ডকুমেন্টেশনটি বলে না যে মান ধরণের উল্লেখগুলি হতে পারে না nullএবং উদাহরণগুলির সাথে কখনই তুলনা করা উচিত নয় ==, রেফারেন্সটি পরীক্ষা করার একমাত্র উপায় হিসাবে এটি nullব্যবহারের জন্য পরীক্ষা করা যেতে পারে । বিদ্যমান কোডের জন্য "কখনই নয় " এ জাতীয় রূপান্তর কীভাবে কাজ করবে তা আমি দেখতে পাচ্ছি না যেমন সমস্ত দৃষ্টান্ত ভেরিয়েবল এবং অ্যারের উপাদানগুলির জন্য ডিফল্ট মান । স্নিপেট অবশ্যই সেরা কোড নয় তবে এর বর্তমান মান হিসাবে বিবেচনা করার কাজও নয়। ==nullnullnullnull
হোলার

দেখতে জন গোলাপ - না এটা "==" অপারেটর না, এমনকি একটি নাল সঙ্গে তুলনা করা যেতে পারে
ZhongYu

4
যেহেতু এই কোড একটি জেনেরিক API ব্যবহার করে করা হবে, এই কি ধারণা একটি কল হয় বাক্সযুক্ত উপস্থাপনা যা হতে পারে null। তবে, যেহেতু এই ধরনের অনুমানের ভাষা পরিবর্তন সংকলককে এখানে ত্রুটি জারি করবে (কোডটি নীরবে ভাঙ্গবে না), তাই আমি এই সত্যের সাথে বেঁচে থাকতে পারি, সম্ভবত এটি জাভা ১০-এর সাথে মানিয়ে নিতে হবে। আমি মনে করি, Streamএপিআই পাশাপাশি বেশ অন্যরকম চেহারা ...
হোলার

20

আপনি java.util.Objects.nonNullসন্ধানের আগে তালিকাটি ফিল্টার করতে ব্যবহার করতে পারেন

কিছুটা এইরকম

list.stream().filter(Objects::nonNull).findFirst();

4
আমি firstStringহতে চাই nullযদি প্রথম আইটেমটি stringsহয় null
neverendingqs

4
দুর্ভাগ্যক্রমে এটি ব্যবহার করে Optional.ofযা নাল নিরাপদ নয়। আপনি ব্যবহার করতে mapপারেন Optional.ofNullable এবং তারপরেও findFirstআপনি শেষ করতে পারবেন anচ্ছিক একটি with
মাত্তোস

15

নিম্নলিখিত কোডটি প্রতিস্থাপন findFirst()করে limit(1)এবং এর সাথে প্রতিস্থাপন orElse()করে reduce():

String firstString = strings.
   stream().
   limit(1).
   reduce("StringWhenListIsEmpty", (first, second) -> second);

limit()কেবলমাত্র 1 টি উপাদান পৌঁছানোর অনুমতি দেয় reduceBinaryOperatorপ্রেরণ reduceআয় 1 উপাদান বা অন্য "StringWhenListIsEmpty"কোন উপাদান পৌঁছানোর যদি reduce

এই সমাধানটির সৌন্দর্যটি Optionalহ'ল বরাদ্দ নেই এবং BinaryOperatorল্যাম্বদা কিছু বরাদ্দ দিচ্ছে না।


1

Ptionচ্ছিক একটি "মান" ধরণের বলে মনে করা হচ্ছে। ( জ্যাভডোকে সূক্ষ্ম মুদ্রণটি পড়ুন :) জেভিএম এমনকি সমস্ত বক্সিং এবং আনবক্সিং ব্যয়গুলি সরিয়ে, Optional<Foo>কেবলমাত্র দিয়ে সমস্ত প্রতিস্থাপন করতে পারে Foo। একটি nullফু মানে একটি খালি Optional<Foo>

কোনও বুলিয়ান পতাকা যুক্ত না করে নাল মান সহ ptionচ্ছিককে অনুমতি দেওয়া এটি একটি সম্ভাব্য নকশা sent (এমনকি thisসেন্ডিনেল হিসাবে ব্যবহার করতে পারে ; থ্রোয়েবল.কস দেখুন)

Decisionচ্ছিক নালকে মোড়তে পারে না এমন সিদ্ধান্ত রানটাইম ব্যয়ের ভিত্তিতে নয়। এটি একটি বিশাল বিতর্কিত সমস্যা ছিল এবং আপনাকে মেলিং তালিকা খনন করতে হবে। সিদ্ধান্তটি সবার কাছে বিশ্বাসযোগ্য নয়।

যে কোনও ক্ষেত্রে, যেহেতু ptionচ্ছিক নাল মানটি মোড়তে পারে না, তাই এটি আমাদের ক্ষেত্রে কোনও কোণে ঠেলা দেয় findFirst। তারা অবশ্যই যুক্তিযুক্ত থাকতে পারে যে নাল মানগুলি খুব বিরল (এটি এমনকি স্ট্রিমের নাল মানকে বার করা উচিত বলে মনে করা হত), তাই খালি স্ট্রিমগুলির পরিবর্তে নাল মানগুলিতে ব্যতিক্রম করা আরও সুবিধাজনক।

একটি workaround বাক্সে হয় null, যেমন

class Box<T>
    static Box<T> of(T value){ .. }

Optional<Box<String>> first = stream.map(Box::of).findFirst();

(তারা বলেছে যে প্রতিটি ওওপি সমস্যার সমাধান হ'ল অন্য ধরণের প্রবর্তন করা :)


4
অন্য Boxধরণের তৈরি করার দরকার নেই । Optionalটাইপ নিজেই এই উদ্দেশ্যে পরিবেশন করতে পারেন। একটি উদাহরণের জন্য আমার উত্তর দেখুন ।
হলগার

@ হোলজার - হ্যাঁ, তবে এটি বিভ্রান্তিকর হতে পারে কারণ এটি ptionচ্ছিক উদ্দেশ্য নয়। ওপি'র ক্ষেত্রে, nullএটি অন্য যে কোনও বৈধ মান, এটির জন্য কোনও বিশেষ চিকিত্সা। (কিছুক্ষণ পরে :) :)
ঝং ইয়ু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.