নাল চেক চেইন বনাম নুলপয়েন্টারএক্সসেপশন


118

একটি ওয়েব পরিষেবা একটি বিশাল এক্সএমএল ফিরিয়ে দেয় এবং এর গভীরভাবে নেস্টেড ক্ষেত্রগুলিতে আমার প্রবেশ করা দরকার। উদাহরণ স্বরূপ:

return wsObject.getFoo().getBar().getBaz().getInt()

সমস্যা হল getFoo(), getBar(), getBaz()সব ফেরত দিতে পারেন null

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

if (wsObject.getFoo() == null) return -1;
if (wsObject.getFoo().getBar() == null) return -1;
// maybe also do something with wsObject.getFoo().getBar()
if (wsObject.getFoo().getBar().getBaz() == null) return -1;
return wsObject.getFoo().getBar().getBaz().getInt();

এটা কি গ্রহণযোগ্য?

try {
    return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
    return -1;
}

বা এন্টিপ্যাটার্ন হিসাবে বিবেচিত হবে?


29
ইতিমধ্যে কোড গন্ধ হওয়ায় আমি nullচেকগুলি তেমন কিছু মনে করব না wsObject.getFoo().getBar().getBaz().getInt()"লিমিটারের আইন" কী তা পড়ুন এবং সেই অনুযায়ী আপনার কোডটি রিফ্যাক্টর করতে পছন্দ করুন। তারপরে nullচেকগুলির সমস্যাটিও পাশাপাশি চলে যাবে। এবং ব্যবহার সম্পর্কে চিন্তা করুন Optional
টম

9
এক্সপ্যাথ ব্যবহার এবং এটি তাদের মূল্যায়নে রেখে যাওয়ার বিষয়ে কী ?
জোপ এগজেন

15
এই কোডটি সম্ভবত দ্বারা উত্পাদিত হয়েছে wsdl2java, যা ডেমিটারের আইনের প্রতি সম্মান রাখে না।
এড্রিয়ান কক্স

উত্তর:


143

ক্যাচিং NullPointerExceptionকরা সত্যিই সমস্যাযুক্ত জিনিস কারণ এটি যে কোনও জায়গায় ঘটতে পারে। এটি একটি বাগ থেকে পাওয়া খুব সহজ, দুর্ঘটনার দ্বারা এটি ধরতে এবং যেমন সবকিছু স্বাভাবিক হয় এমনভাবে চালিয়ে যাওয়া, এভাবে একটি বাস্তব সমস্যা লুকিয়ে থাকে। এটি মোকাবেলা করা এতটাই জটিল তাই সম্পূর্ণরূপে এড়ানো ভাল। (উদাহরণস্বরূপ, নালীর অটো-আনবক্সিং সম্পর্কে ভাবেন Integer))

আমি আপনাকে Optionalপরিবর্তে ক্লাসটি ব্যবহার করার পরামর্শ দিচ্ছি । আপনি যখন উপস্থিত বা অনুপস্থিত মানগুলির সাথে কাজ করতে চান তখন এটি প্রায়শই সেরা পন্থা।

এটি ব্যবহার করে আপনি আপনার কোডটি এভাবে লিখতে পারেন:

public Optional<Integer> m(Ws wsObject) {
    return Optional.ofNullable(wsObject.getFoo()) // Here you get Optional.empty() if the Foo is null
        .map(f -> f.getBar()) // Here you transform the optional or get empty if the Bar is null
        .map(b -> b.getBaz())
        .map(b -> b.getInt());
        // Add this if you want to return null instead of an empty optional if any is null
        // .orElse(null);
        // Or this if you want to throw an exception instead
        // .orElseThrow(SomeApplicationException::new);
}

Optionচ্ছিক কেন?

অনুপস্থিত হতে পারে এমন মানগুলির Optionalপরিবর্তে গুলি ব্যবহার করা nullসেই বিষয়টি পাঠকদের কাছে অত্যন্ত দৃশ্যমান এবং স্পষ্ট করে তোলে এবং টাইপ সিস্টেমটি নিশ্চিত করে তোলে যে আপনি দুর্ঘটনাক্রমে এটিকে ভুলে যাবেন না।

এছাড়াও আপনি আরো সুবিধামত এমন মান কাজ মত পদ্ধতি অ্যাক্সেস পেতে mapএবং orElse


অনুপস্থিতি বৈধ না ত্রুটি?

তবে মধ্যবর্তী পদ্ধতির নাল ফেরার জন্য এটি কোনও বৈধ ফলাফল কিনা বা এটি কোনও ত্রুটির চিহ্ন হিসাবেও ভেবে দেখুন। যদি এটি সর্বদা ত্রুটি হয় তবে কোনও বিশেষ মূল্য ফেরত না দেওয়া বা মধ্যবর্তী পদ্ধতিগুলির জন্য তারা ব্যতিক্রম ছোঁড়ার চেয়ে সম্ভবত ব্যতিক্রম ছুঁড়ে ফেলা ভাল।


আরও বিকল্প হতে পারে?

যদি অন্যদিকে মধ্যবর্তী পদ্ধতিগুলি থেকে অনুপস্থিত মানগুলি বৈধ হয়, তবে আপনি Optionalতাদের জন্য এটি পরিবর্তন করতে পারেন ?

তারপরে আপনি তাদের এগুলি ব্যবহার করতে পারেন:

public Optional<Integer> mo(Ws wsObject) {
    return wsObject.getFoo()
        .flatMap(f -> f.getBar())
        .flatMap(b -> b.getBaz())
        .flatMap(b -> b.getInt());        
}

Optionচ্ছিক নয় কেন?

আমি ব্যবহার না করার জন্য কেবলমাত্র কারণটি Optionalহ'ল যদি এটি কোডের সত্যিকারের পারফরম্যান্সের সমালোচনামূলক অংশে থাকে এবং যদি আবর্জনা সংগ্রহের ওভারহেড কোনও সমস্যা হিসাবে দেখা দেয়। এর কারণ হল কয়েক হল Optionalবস্তু প্রতিটি সময় কোড সঞ্চালিত হয় বরাদ্দ করা হয়, এবং VM- র পারে সেই দূরে নিখুত করতে সক্ষম নাও হতে। সেক্ষেত্রে আপনার আসল যদি পরীক্ষাগুলি আরও ভাল হয়।


খুব ভাল উত্তর। এটি উল্লেখ করা উচিত যে যদি অন্য সম্ভাব্য ব্যর্থতার শর্তাদি থাকে এবং আপনার মধ্যে তাদের পার্থক্য করা দরকার, আপনি Tryপরিবর্তে ব্যবহার করতে পারেন Optional। যদিও নেই Tryজাভা API এ, অনেক লিব, এক প্রদানের যেমন হয় javaslang.io , github.com/bradleyscollins/try4j , functionaljava.org বা github.com/jasongoodwin/better-java-monads
Landei

8
FClass::getBarইত্যাদি খাটো হবে।
বোরিস স্পাইডার

1
@ বোরিস্টস্পাইডার: সম্ভবত কিছুটা তবে আমি সাধারণত পদ্ধতিগুলির রেফের তুলনায় ল্যাম্বডাস পছন্দ করি কারণ প্রায়শই শ্রেণীর নামগুলি দীর্ঘ হয় এবং আমি ল্যাম্বডাসকে পড়তে একটু সহজ মনে করি।
লী

6
@ লাই যথেষ্ট ন্যায্য, তবে মনে রাখবেন যে কোনও পদ্ধতি রেফারেন্সটি খুব সামান্য দ্রুত হতে পারে, কারণ ল্যাম্বডায় আরও জটিল সংকলনের সময় গঠনের প্রয়োজন হতে পারে। ল্যাম্বডায় একটি staticপদ্ধতির প্রজন্মের প্রয়োজন হবে , যার ফলে খুব সামান্য জরিমানা হবে।
বোরিস দ্য স্পাইডার

1
@ লি আমি পদ্ধতির উল্লেখগুলি আরও পরিষ্কার এবং আরও বর্ণনামূলক বলে মনে করি, এমনকি সেগুলি কিছুটা দীর্ঘ হলেও।
shmosel

14

আমি বিবেচনা পরামর্শ Objects.requireNonNull(T obj, String message)। আপনি প্রতিটি ব্যতিক্রমের মতো বিশদ বার্তা সহ চেইনগুলি তৈরি করতে পারেন, যেমন

requireNonNull(requireNonNull(requireNonNull(
    wsObject, "wsObject is null")
        .getFoo(), "getFoo() is null")
            .getBar(), "getBar() is null");

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

নিক্ষেপ NullPointerExceptionকরাও সেরা বিকল্প নয়। আপনি আপনার নিজের ব্যতিক্রম প্রদান করতে পারে (এটা উপার্জন চেক করা গ্যারান্টি যে এটি একটি ব্যবহারকারী বা দ্বারা পরিচালিত হবে অবারিত একটি সহজ ভাবে এটি প্রক্রিয়া) অথবা আপনি ব্যবহার করছেন এক্সএমএল পার্সার থেকে একটি নির্দিষ্ট ব্যতিক্রম ব্যবহার করুন।


1
Objects.requireNonNullঅবশেষে ছুড়ে ফেলে NullPointerException। সুতরাং এটি পরিস্থিতি এর চেয়ে আলাদা করে তোলে নাreturn wsObject.getFoo().getBar().getBaz().getInt()
আরকা ঘোষ

1
@ আরকাঘোষ, ifওপি যেমন দেখিয়েছে তা প্রচুর পরিমাণে এড়িয়ে চলেছে
অ্যান্ড্রু টবিলকো

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

1
বৈধ ফেরতের মূল্যের অনুপস্থিতির সংকেত দিতে ব্যতিক্রমগুলি ব্যবহার করার শর্তহীন পরামর্শটি খুব ভাল নয়। কোনও পদ্ধতি এমনভাবে ব্যর্থ হয় যখন কলারের পক্ষে পুনরুদ্ধার করা শক্ত এবং প্রোগ্রামটির অন্য কোনও অংশে ট্রাই-ক্যাচ-স্টেটমেন্টে আরও ভালভাবে পরিচালনা করা হয় তখন ব্যতিক্রমগুলি কার্যকর হয়। কোনও রিটার্ন মানের অভাবে কেবল সংকেত জানাতে Optionalক্লাসটি ব্যবহার করা আরও ভাল , বা হতে পারে কোনও প্রত্যাবর্তন ফিরিয়ে দেওয়াInteger
Lii

6

শ্রেণি কাঠামোটি সত্যই আমাদের নিয়ন্ত্রণের বাইরে রয়েছে বলে ধরে নেওয়া যায়, যেমনটি মনে হয়, এনপিইর প্রশ্নের উত্তর অনুযায়ী ধরা আসলেই একটি যুক্তিসঙ্গত সমাধান, যদি না পারফরম্যান্স বড় উদ্বেগ না হয়। একটি ছোট উন্নতি হতে পারে বিশৃঙ্খলা এড়ানোর জন্য নিক্ষেপ / ধরার যুক্তি গুটিয়ে রাখা:

static <T> T get(Supplier<T> supplier, T defaultValue) {
    try {
        return supplier.get();
    } catch (NullPointerException e) {
        return defaultValue;
    }
}

এখন আপনি সহজভাবে করতে পারেন:

return get(() -> wsObject.getFoo().getBar().getBaz().getInt(), -1);

return get(() -> wsObject.getFoo().getBar().getBaz().getInt(), "");সংকলন সময়ে একটি ত্রুটি দেয় না যা সমস্যাযুক্ত হতে পারে।
ফিলিপ জিওসিফি

5

মন্তব্য হিসাবে টম দ্বারা ইতিমধ্যে ইঙ্গিত হিসাবে ,

নিম্নলিখিত বিবৃতিটি ডেমিটারের আইন অমান্য করে ,

wsObject.getFoo().getBar().getBaz().getInt()

আপনি যা চান তা হ'ল intএবং আপনি এটি থেকে পেতে পারেন Fooলিমিটার অফ ডেমিটার বলেছেন, কখনও অপরিচিত লোকের সাথে কথা বলবেন না । আপনার ক্ষেত্রে জন্য আপনি ফণা অধীন প্রকৃত বাস্তবায়ন লুকিয়ে রাখতে পারেন Fooএবং Bar

এখন, আপনি পদ্ধতি তৈরি করতে পারেন Fooআনতে intথেকে Baz। শেষ পর্যন্ত, Fooথাকবে Barএবং Barআমরা সরাসরি সরাসরি Intপ্রকাশ না করেই অ্যাক্সেস করতে পারি । সুতরাং, নাল চেকগুলি সম্ভবত বিভিন্ন শ্রেণিতে বিভক্ত করা হয়েছে এবং কেবল প্রয়োজনীয় বৈশিষ্ট্যগুলি ক্লাসগুলির মধ্যে ভাগ করা হবে।BazFoo


4
এটি বিতর্কযোগ্য যদি এটি ডেমিটারের আইন অমান্য করে যেহেতু ডাব্লুএসবজেক্ট সম্ভবত কেবলমাত্র একটি ডেটা কাঠামো। : এখানে দেখুন stackoverflow.com/a/26021695/1528880
Derm

2
@ ডেরম হ্যাঁ, এটি সম্ভব, তবে যেহেতু ওপিতে ইতিমধ্যে তার এক্সএমএল ফাইলটি বিশ্লেষণকারী কিছু রয়েছে তাই তিনি প্রয়োজনীয় ট্যাগগুলির জন্য উপযুক্ত মডেল ক্লাস তৈরি করার বিষয়েও ভাবতে পারেন, যাতে পার্সিং লাইব্রেরি সেগুলি ম্যাপ করতে পারে। তারপরে এই মডেল ক্লাসগুলির nullনিজস্ব সাব ট্যাগগুলির একটি চেক করার জন্য যুক্তি ধারণ করে ।
টম

4

আমার উত্তরটি @ জাঙ্কির মতো প্রায় একই লাইনে চলেছে তবে আমি কোড স্নিপেটটি নীচের মত কিছুটা সংশোধন করতে চাই:

if (wsObject.getFoo() != null && wsObject.getFoo().getBar() != null && wsObject.getFoo().getBar().getBaz() != null) 
   return wsObject.getFoo().getBar().getBaz().getInt();
else
   return something or throw exception;

আপনি wsObjectযদি সেইসাথে নাল চেক যোগ করতে পারেন তবে যদি সেই বস্তুর শূন্য হওয়ার কোনও সম্ভাবনা থাকে।


4

আপনি বলছেন যে কিছু পদ্ধতি "ফিরে আসতে পারে null" তবে তারা কোন পরিস্থিতিতে ফিরে আসে তা বলবেন না null। আপনি বলছেন যে আপনি ধরেন NullPointerExceptionকিন্তু আপনি কেন তা ধরেন না। তথ্যের এই অভাব পরামর্শ দেয় যে ব্যতিক্রমগুলি কী এবং তারা বিকল্পের চেয়ে কেন উচ্চতর সে সম্পর্কে আপনার পরিষ্কার ধারণা নেই।

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

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

সুতরাং, সেই পদ্ধতিগুলি যে ফিরে আসে null

  • কোনও nullমান কি আপনার কোডটিতে একটি বাগ নির্দেশ করে? যদি এটি হয় তবে আপনার ব্যতিক্রমটি মোটেও ধরা উচিত নয়। এবং আপনার কোডটি নিজেই দ্বিতীয় অনুমান করার চেষ্টা করা উচিত নয়। যা স্পষ্ট তা সংক্ষিপ্ত এবং সংক্ষিপ্ত আকারে লিখুন যে এটি কার্যকর হবে। পদ্ধতি শৃঙ্খলা কল কি পরিষ্কার এবং সংক্ষিপ্ত? তারপরে এগুলি ব্যবহার করুন।
  • একটি nullমান আপনার প্রোগ্রামে অবৈধ ইনপুট নির্দেশ করে? যদি এটি হয় তবে এটি NullPointerExceptionনিক্ষেপ করার উপযুক্ত ব্যতিক্রম নয়, কারণ প্রচলিতভাবে এটি বাগগুলি নির্দেশ করার জন্য সংরক্ষিত। আপনি সম্ভবত থেকে উদ্ভূত একটি কাস্টম ব্যতিক্রম রাখার বিষয়ে IllegalArgumentException(যদি আপনি একটি চান অবারিত ব্যতিক্রম ) অথবা IOException(যদি আপনি একটি চেক করা ব্যতিক্রম চান)। যখন আপনার প্রোগ্রামটিতে অবৈধ ইনপুট রয়েছে তখন কি বিশদ সিনট্যাক্স ত্রুটি বার্তাগুলি সরবরাহ করা প্রয়োজন? যদি তা হয় তবে, প্রতিটি পদ্ধতির nullফেরতের মানের জন্য পরীক্ষা করা হয় তবে উপযুক্ত ডায়াগনস্টিক ব্যতিক্রম ছুঁড়ে ফেলা হ'ল এটিই আপনি করতে পারেন। যদি আপনার প্রোগ্রামটির বিশদ ডায়াগনস্টিকগুলির প্রয়োজন না হয়, পদ্ধতিটি কল করে একসাথে চলা, কোনওটি ধরা NullPointerExceptionএবং তারপরে আপনার কাস্টম ব্যতিক্রম ছোঁড়াটি পরিষ্কার এবং সবচেয়ে সংক্ষিপ্ত।

উত্তরের একটিতে দাবি করা হয়েছে যে শিকলযুক্ত পদ্ধতি কলগুলি ডেমিটারের লঙ্ঘন করে এবং এইভাবে খারাপ thus সেই দাবি ভুল হয়েছে is

  • যখন প্রোগ্রাম ডিজাইনের কথা আসে তখন কোনটি ভাল এবং কোনটি খারাপ সে সম্পর্কে সত্যই কোনও নিরপেক্ষ নিয়ম নেই। এখানে কেবলমাত্র হিউরিস্টিকস রয়েছে: নিয়ম যা সেই সময়ের অনেক বেশি (এমনকি প্রায় সমস্ত)। প্রোগ্রামিংয়ের দক্ষতার অংশটি জেনে রাখা হয় যে কখন এই ধরণের নিয়ম ভাঙা ঠিক হয়। সুতরাং একটি সংক্ষিপ্ত বক্তব্য যে "এটি X এর বিপরীতে বিরোধী " আসলে কোনও উত্তর নয়। নিয়ম ভাঙা উচিত এমন কি এমন পরিস্থিতি ?
  • Demeter আইন সত্যিই API বা বর্গ ইন্টারফেস ডিজাইন সম্পর্কে একটি নিয়ম আছে। ক্লাস ডিজাইন করার সময় , অ্যাবস্ট্রাকশনগুলির শ্রেণিবদ্ধতা রাখা দরকারী। আপনার নিম্ন স্তরের ক্লাস রয়েছে যা ভাষা অপারেশনগুলি সরাসরি ক্রিয়াকলাপ সম্পাদনের জন্য ব্যবহার করে এবং কোনও বিমূর্ততায় বস্তুর প্রতিনিধিত্ব করে যা ভাষা আদিমদের চেয়ে উচ্চতর স্তর। আপনার মাঝারি স্তরের শ্রেণি রয়েছে যা নিম্ন স্তরের শ্রেণিতে প্রতিনিধিত্ব করে এবং নিম্ন স্তরের শ্রেণীর চেয়ে উচ্চতর স্তরে অপারেশন এবং উপস্থাপনা প্রয়োগ করে। আপনার উচ্চ স্তরের শ্রেণি রয়েছে যা মাঝারি স্তরের শ্রেণিতে প্রতিনিধি হয় এবং এখনও উচ্চ স্তরের ক্রিয়াকলাপ এবং বিমূর্ততা প্রয়োগ করে। (আমি এখানে বিমূর্ত মাত্র তিনটি স্তরের কথা বলেছি, তবে আরও বেশি কিছু সম্ভব)। এটি আপনার কোডকে প্রতিটি স্তরে উপযুক্ত বিমূর্ততার ক্ষেত্রে নিজেকে প্রকাশ করতে দেয়, যার ফলে জটিলতা লুকিয়ে থাকে। আইন শৃঙ্খলা রক্ষার জন্য যুক্তিযদি আপনার কাছে পদ্ধতি কলগুলির একটি শৃঙ্খলা থাকে তবে এটি আপনাকে নিম্ন স্তরের বিশদটি সরাসরি মোকাবেলা করার জন্য একটি মাঝারি স্তরের শ্রেণীর মাধ্যমে একটি উচ্চ স্তরের শ্রেণি পৌঁছানোর পরামর্শ দেয় এবং তাই আপনার মাঝারি স্তরের শ্রেণি একটি মাঝারি স্তরের বিমূর্ত ক্রিয়াকলাপ সরবরাহ করে নি that যে উচ্চ স্তরের শ্রেণীর প্রয়োজন। কিন্তু মনে হচ্ছে যে হয় না পরিস্থিতি এখানে আছে: আপনি পদ্ধতি কল শৃঙ্খল ক্লাস ডিজাইন করা হয়নি, তারা কিছু স্বয়ংক্রিয়ভাবে তৈরি এক্সএমএল ধারাবাহিকতাতে কোড (? ডান) ফল, এবং কলের শৃঙ্খল সাজানো নয় অ্যাবস্ট্রাকশন হায়ারার্কির মধ্য দিয়ে কারণ ডেস-সিরিয়ালাইজড এক্সএমএল সমস্ত অ্যাবস্ট্রাকশন হায়ারার্কির একই স্তরে (ডান?)?

3

পঠনযোগ্যতা উন্নত করতে আপনি একাধিক ভেরিয়েবল ব্যবহার করতে চাইতে পারেন

Foo theFoo;
Bar theBar;
Baz theBaz;

theFoo = wsObject.getFoo();

if ( theFoo == null ) {
  // Exit.
}

theBar = theFoo.getBar();

if ( theBar == null ) {
  // Exit.
}

theBaz = theBar.getBaz();

if ( theBaz == null ) {
  // Exit.
}

return theBaz.getInt();

এটি আমার মতে খুব কম পঠনযোগ্য। এটি পদ্ধতিটিকে প্রকৃত যুক্তি থেকে সম্পূর্ণ অপ্রাসঙ্গিক যা নাল-চেকিং লজিকের পুরো গুচ্ছ দিয়ে পদ্ধতিটি লিটারে লিটার করে দেয়।
বিকাশকারী

2

ধরবেন না NullPointerException। আপনি জানেন না যে এটি কোথা থেকে আসছে (আমি জানি এটি আপনার ক্ষেত্রে সম্ভবত সম্ভাব্য নয় তবে সম্ভবত অন্য কোনও কিছু এটি ছুঁড়ে দিয়েছে) এবং এটি ধীর গতিতে। আপনি নির্দিষ্ট ক্ষেত্রটি অ্যাক্সেস করতে চান এবং এর জন্য প্রতিটি অন্যান্য ক্ষেত্র শূন্য করা উচিত নয়। প্রতিটি ক্ষেত্র পরীক্ষা করার জন্য এটি একটি সঠিক বৈধ কারণ। আমি সম্ভবত এটি একবারে পরীক্ষা করে দেখব এবং তারপরে পাঠযোগ্যতার জন্য একটি পদ্ধতি তৈরি করব। অন্যরা ইতিমধ্যে ইঙ্গিত করেছে যে -1 ফিরে আসা খুব পুরানো স্কুল, তবে আপনার এটির কারণ আছে কি না তা আমি জানি না (যেমন অন্য সিস্টেমের সাথে কথা বলা)।

public int callService() {
    ...
    if(isValid(wsObject)){
        return wsObject.getFoo().getBar().getBaz().getInt();
    }
    return -1;
}


public boolean isValid(WsObject wsObject) {
    if(wsObject.getFoo() != null &&
        wsObject.getFoo().getBar() != null &&
        wsObject.getFoo().getBar().getBaz() != null) {
        return true;
    }
    return false;
}

সম্পাদনা: এটি বিতর্কযোগ্য যদি এটি ডেমিটারের আইন অমান্য করে কারণ ডাব্লুএসবজেক্ট সম্ভবত কেবলমাত্র একটি ডেটা কাঠামো ( https://stackoverflow.com/a/26021695/1528880 দেখুন )।


2

আপনি যদি কোডটি রিফ্যাক্টর করতে না চান এবং আপনি জাভা 8 ব্যবহার করতে পারেন তবে পদ্ধতি উল্লেখগুলি ব্যবহার করা সম্ভব use

প্রথমে একটি সাধারণ ডেমো (স্থির অভ্যন্তর শ্রেণিগুলি ক্ষমা করুন)

public class JavaApplication14 
{
    static class Baz
    {
        private final int _int;
        public Baz(int value){ _int = value; }
        public int getInt(){ return _int; }
    }
    static class Bar
    {
        private final Baz _baz;
        public Bar(Baz baz){ _baz = baz; }
        public Baz getBar(){ return _baz; }   
    }
    static class Foo
    {
        private final Bar _bar;
        public Foo(Bar bar){ _bar = bar; }
        public Bar getBar(){ return _bar; }   
    }
    static class WSObject
    {
        private final Foo _foo;
        public WSObject(Foo foo){ _foo = foo; }
        public Foo getFoo(){ return _foo; }
    }
    interface Getter<T, R>
    {
        R get(T value);
    }

    static class GetterResult<R>
    {
        public R result;
        public int lastIndex;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) 
    {
        WSObject wsObject = new WSObject(new Foo(new Bar(new Baz(241))));
        WSObject wsObjectNull = new WSObject(new Foo(null));

        GetterResult<Integer> intResult
                = getterChain(wsObject, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);

        GetterResult<Integer> intResult2
                = getterChain(wsObjectNull, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);


        System.out.println(intResult.result);
        System.out.println(intResult.lastIndex);

        System.out.println();
        System.out.println(intResult2.result);
        System.out.println(intResult2.lastIndex);

        // TODO code application logic here
    }

    public static <R, V1, V2, V3, V4> GetterResult<R>
            getterChain(V1 value, Getter<V1, V2> g1, Getter<V2, V3> g2, Getter<V3, V4> g3, Getter<V4, R> g4)
            {
                GetterResult result = new GetterResult<>();

                Object tmp = value;


                if (tmp == null)
                    return result;
                tmp = g1.get((V1)tmp);
                result.lastIndex++;


                if (tmp == null)
                    return result;
                tmp = g2.get((V2)tmp);
                result.lastIndex++;

                if (tmp == null)
                    return result;
                tmp = g3.get((V3)tmp);
                result.lastIndex++;

                if (tmp == null)
                    return result;
                tmp = g4.get((V4)tmp);
                result.lastIndex++;


                result.result = (R)tmp;

                return result;
            }
}

আউটপুট

241
4

নাল
2

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

পদ্ধতিটি getterChainহ'ল একটি সহজ, বয়লারপ্লেট কোডের টুকরো, যা স্বয়ংক্রিয়ভাবে উত্পন্ন করা যায় (বা প্রয়োজনের সময় ম্যানুয়ালি)।
আমি কোডটি এমনভাবে তৈরি করেছি যাতে পুনরাবৃত্তি হওয়া ব্লকটি স্বতঃস্ফূর্ত হয়।


এটি একটি নিখুঁত সমাধান নয় কারণ আপনাকে এখনও getterChainপ্রতি সংখ্যক যাত্রীর জন্য একটি ওভারলোড বোঝাতে হবে।

পরিবর্তে আমি কোডটি রিফ্যাক্টর করব, তবে যদি আপনি খুঁজে না পান এবং দীর্ঘ গেটর চেইন ব্যবহার করে আপনি নিজের স্ব আবিষ্কার করেন তবে প্রায়শই আপনি 2 থেকে 10, গেটার, ওভারলোডগুলি নিয়ে ক্লাস তৈরির বিষয়টি বিবেচনা করতে পারেন।


2

অন্যরা যেমন বলেছে, ডেমিটারের আইনকে সম্মান করা অবশ্যই সমাধানের অংশ। আর একটি অংশ, যেখানেই সম্ভব, সেই শিকলযুক্ত পদ্ধতিগুলি পরিবর্তন করা যাতে তারা ফিরে আসতে না পারে null। আপনি nullখালি String, একটি খালি Collection, বা অন্য কোনও ডামি অবজেক্টের পরিবর্তে ফিরে যাওয়া এড়াতে পারবেন যার অর্থ কলারের সাথে যা কিছু করবে বা করবে null


2

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

এমন হাজার হাজার মামলা রয়েছে যেখানে আপনার কোডটি ভুল হতে পারে: ডাটাবেসে সংযুক্ত হতে পারে না, আইও ব্যতিক্রম, নেটওয়ার্ক ত্রুটি ... আপনি যদি একে একে তাদের সাথে ডিল করেন (এখানে নাল চেক করার মতো), এটি খুব ঝামেলা হবে।

কোডে:

wsObject.getFoo().getBar().getBaz().getInt();

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

এক্সেনরোসের উত্তরের মতো, আমি কাস্টম চেক করা ব্যতিক্রম ব্যবহার করে প্রস্তাব দেব । উদাহরণস্বরূপ, এই পরিস্থিতিতে: ফু নাল (বৈধ ডেটা) হতে পারে, তবে বার এবং বাজ কখনই নাল হবে না (অবৈধ ডেটা)

কোডটি আবার লেখা যেতে পারে:

void myFunction()
{
    try 
    {
        if (wsObject.getFoo() == null)
        {
          throw new FooNotExistException();
        }

        return wsObject.getFoo().getBar().getBaz().getInt();
    }
    catch (Exception ex)
    {
        log.error(ex.Message, ex); // Write log to track whatever exception happening
        throw new OperationFailedException("The requested operation failed")
    }
}


void Main()
{
    try
    {
        myFunction();
    }
    catch(FooNotExistException)
    {
        // Show error: "Your foo does not exist, please check"
    }
    catch(OperationFailedException)
    {
        // Show error: "Operation failed, please contact our support"
    }
}

চেক করা ব্যতিক্রমগুলি ইঙ্গিত দেয় যে প্রোগ্রামার এপিআই-র অপব্যবহার করছে। "ডাটাবেসের সাথে সংযোগ স্থাপন করতে পারে না, আইও এক্সেপশন, নেটওয়ার্ক ত্রুটি" এর মতো বাহ্যিক সমস্যাগুলি পরীক্ষিত ব্যতিক্রমগুলি দ্বারা নির্দেশিত হওয়া উচিত।
কেভিন ক্রামউইদে

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

কলকারীদের চেক করা ব্যতিক্রমগুলি ধরতে এবং পুনরায় নিক্ষেপ করতে হবে না, কেবল তাদের ছুঁড়ে ফেলার ঘোষণা করুন।
কেভিন ক্রামউইদে

@ কেভিন ক্রুউইউইডি: আপনি সঠিক, আমাদের কেবলমাত্র ব্যতিক্রম ছুঁড়ে ফেলার ঘোষণা করা দরকার। আমাদের এখনও ঘোষণা করতে হবে। সম্পাদনা: এটিতে দ্বিতীয়বার দেখে, চেক করা বনাম চেক করা ব্যতিক্রম ব্যতীত ব্যবহারগুলি (যেমন: প্রোগ্রামার্স.স্ট্যাকেক্সচেঞ্জ / প্রশ্ন / 121328/… ) সম্পর্কে প্রচুর বিতর্ক রয়েছে ।
হোং লং

2

NullPointerException রান-টাইম ব্যতিক্রম, সুতরাং সাধারণত কথা বলার জন্য এটি ধরা বাঞ্ছনীয় নয়, তবে এড়াতে।

আপনি যে পদ্ধতিতে কল করতে চান সেখানে আপনাকে ব্যতিক্রম করতে হবে (বা এটি স্ট্যাকটি প্রচার করবে)। তবুও, যদি আপনার ক্ষেত্রে আপনি ফলাফলটির সাথে মান -1 দিয়ে কাজ চালিয়ে যেতে পারেন এবং আপনি নিশ্চিত যে এটি প্রচার করবে না কারণ আপনি কোনও "টুকরো" ব্যবহার করছেন না যা বাতিল হতে পারে, তবে এটি আমার কাছে সঠিক বলে মনে হচ্ছে এটি ধর

সম্পাদনা:

আমি @xenteros এর পরবর্তী উত্তরের সাথে একমত , আপনার নিজের ব্যতিক্রম প্রবর্তনের পরিবর্তে -1 ফেরার চেয়ে ভাল হবে আপনি InvalidXMLExceptionউদাহরণস্বরূপ এটিকে কল করতে পারেন ।


3
"আপনি যদি এটি ধরেন তবে তা কোডের অন্যান্য অংশেও প্রচার করতে পারে" এর অর্থ কী?
হাল্ক

যদি নালটি এই বাক্যটিতে থাকে তবে wsObject.getFoo () এবং কোডটির পরবর্তী অংশগুলিতে আপনি আবার সেই ক্যোয়ারি চালান বা wsObject.getFoo ()। GetBar () ব্যবহার করুন (উদাহরণস্বরূপ) এটি আবার একটি নালপয়েন্টার এক্সসেপশন উত্থাপন করবে।
স্কাউটো

এটি একটি অস্বাভাবিক শব্দ যা "যেখানেই আপনি পদ্ধতিটি কল করতে চান সেখানে আপনাকে ব্যতিক্রম করতে হবে (বা এটি স্ট্যাকটি প্রচার করবে)" for যদি আমি সঠিকভাবে বুঝতে পারি আমি এটির সাথে একমত (এবং এটি কোনও সমস্যা হতে পারে), আমি কেবল শব্দটি বিভ্রান্তিকর বলে মনে করি।
হাল্ক

আমি এটিকে ঠিক করব, দুঃখিত, ইংরেজি আমার প্রথম ভাষা নয় তাই এটি কখনও কখনও ঘটতে পারে :) ধন্যবাদ
এসকিউটো

2

গতকাল থেকে এই পোস্ট অনুসরণ করা হয়।

আমি মন্তব্য / মন্তব্য করা হয়েছে যা মন্তব্য করে যে এনপিই ধরা খারাপ। এখানে আমি কেন এটি করা হয়।

package com.todelete;

public class Test {
    public static void main(String[] args) {
        Address address = new Address();
        address.setSomeCrap(null);
        Person person = new Person();
        person.setAddress(address);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            try {
                System.out.println(person.getAddress().getSomeCrap().getCrap());
            } catch (NullPointerException npe) {

            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime - startTime) / 1000F);
        long startTime1 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            if (person != null) {
                Address address1 = person.getAddress();
                if (address1 != null) {
                    SomeCrap someCrap2 = address1.getSomeCrap();
                    if (someCrap2 != null) {
                        System.out.println(someCrap2.getCrap());
                    }
                }
            }
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println((endTime1 - startTime1) / 1000F);
    }
}

  public class Person {
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

package com.todelete;

public class Address {
    private SomeCrap someCrap;

    public SomeCrap getSomeCrap() {
        return someCrap;
    }

    public void setSomeCrap(SomeCrap someCrap) {
        this.someCrap = someCrap;
    }
}

package com.todelete;

public class SomeCrap {
    private String crap;

    public String getCrap() {
        return crap;
    }

    public void setCrap(String crap) {
        this.crap = crap;
    }
}

আউটপুট

3,216

0.002

আমি এখানে একটি পরিষ্কার বিজয়ী দেখতে পাচ্ছি। ব্যতিক্রমগুলি ধরার চেয়ে চেকগুলি পাওয়া খুব ব্যয়বহুল। আমি দেখেছি যে জাভা -8 করার উপায়। বিবেচনা করে যে বর্তমান অ্যাপ্লিকেশনগুলির 70% এখনও জাভা -7 এ চলছে আমি এই উত্তরটি যুক্ত করছি।

নীচের লাইন যে কোনও মিশনের সমালোচনামূলক অ্যাপ্লিকেশনগুলির জন্য, এনপিই হ্যান্ডলিং ব্যয়বহুল।


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

@ জিরোয়নমাস্টার্ট: চেক / মিলিয়ন প্রতি 3 সেকেন্ড সুতরাং, চেকের সংখ্যা ব্যয় বাড়িয়ে
তুলবে

সত্য। এমনকি এর সাথে আমি এখনও এটি "প্রোফাইল প্রথম" এর একটি মামলা বিবেচনা করব, যদিও। অনুরোধটি পুরো মিলিসেকেন্ড অতিরিক্ত নেওয়ার আগে আপনাকে একটি অনুরোধে 300 টিরও বেশি চেকের প্রয়োজন হবে। ডিজাইনের বিবেচনাগুলি তার চেয়ে অনেক তাড়াতাড়ি আমার আত্মায় ওজন করবে।
জেরোইন মোস্টার্ট

@ জিরোয়ানমাস্টার্ট: :) সম্মত! আমি ফলাফলটির সাথে এটি প্রোগ্রামারের কাছে রেখে দিতে চাই এবং তাদের কোনও কল দিতে দাও!
নিউ ইউজার

1

দক্ষতা যদি কোনও সমস্যা হয় তবে 'ক্যাচ' বিকল্পটি বিবেচনা করা উচিত। যদি 'ধরা' কারণ এটা সঞ্চারিত হবে ব্যবহার করা যাবে না (যেমন 'SCouto' দ্বারা উল্লিখিত) পরে স্থানীয় বিকল্পগুলি ব্যবহার পদ্ধতি একাধিক কল এড়াতে getFoo(), getBar()এবং getBaz()


1

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

try {
    return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
    throw new MyOperationFailedException();
}

সম্পাদনা করুন:

মন্তব্যে আলোচনা অনুযায়ী আমাকে আমার আগের চিন্তাগুলিতে কিছু যোগ করতে দিন। এই কোডে দুটি সম্ভাবনা রয়েছে। একটি হ'ল আপনি নাল গ্রহণ করেন এবং অন্যটি হ'ল এটি একটি ত্রুটি।

যদি এটি একটি ত্রুটি হয় এবং এটি ঘটে থাকে, ব্রেকপয়েন্টগুলি পর্যাপ্ত না হলে আপনি ডিবাগিং উদ্দেশ্যে অন্যান্য কাঠামো ব্যবহার করে আপনার কোডটি ডিবাগ করতে পারেন।

যদি এটি গ্রহণযোগ্য হয় তবে এই নালটি কোথায় উপস্থিত হয়েছে সে সম্পর্কে আপনি চিন্তা করবেন না। যদি আপনি তা করেন তবে আপনার অবশ্যই এই অনুরোধগুলি চেইন করা উচিত নয়।


2
আপনি কি মনে করেন না যে ব্যতিক্রমটি দমন করা খারাপ ধারণা? রিয়েলটাইমে, আমরা যদি একটি ব্যতিক্রমের চিহ্নটি হারিয়ে ফেলি তবে এর বাস্তব ব্যথা হ'ল কী ঘটছে তা খুঁজে বের করার জন্য! আমি সবসময় চেইন ব্যবহার না করার পরামর্শ দেব। দ্বিতীয় সমস্যাটি আমি দেখতে পাচ্ছি: এই কোডটি সময়ে সময়ে মঞ্জুরি দিতে পারে না, যার ফলাফলটি শূন্য ছিল।
নিউ ইউজার

নাহ, আপনার ব্যতিক্রমটিতে একটি বার্তা থাকতে পারে যা অবশ্যই এটি যেখানে ছুঁড়েছিল সেখানে নির্দেশ করবে। আমি সম্মতি
জানলাম শৃঙ্খলাই

3
নাহ, এটি কেবল লাইন নম্বর সম্পর্কে বলবে। সুতরাং, চেইনের কোনও কলই ব্যতিক্রম হতে পারে।
নিউ ইউজার

"যদি এটি একটি ত্রুটি হয় এবং এটি ঘটে তবে আপনি আপনার কোডটি ডিবাগ করতে পারেন" - উত্পাদনে নয়। আমি তার চেয়ে অনেক বেশি জানতে পারি যখন আমার সমস্ত কিছু লগই ছিল যা ব্যর্থ হওয়ার কারণ হয়ে divineশ্বরের চেষ্টা করার চেয়ে। সেই পরামর্শটি (এবং সেই কোড) দিয়ে আপনি যা যা সত্যিই জানেন তা হ'ল 4 টির মধ্যে একটি জিনিস শূন্য ছিল তবে কোনটি বা কেন তা নয়।
VLAZ

1

আপনার কাছে থাকা পদ্ধতিটি দীর্ঘ, তবে খুব পঠনযোগ্য। আমি যদি আপনার কোড বেসে নতুন বিকাশকারী হয়ে থাকি তবে আমি দেখতে পেতাম যে আপনি মোটামুটি কী করছেন। অন্যান্য উত্তরগুলির বেশিরভাগ (ব্যতিক্রম ধরা সহ) মনে হয় না যে জিনিসগুলি আরও পাঠযোগ্য এবং কিছু কিছু এটি আমার মতে কম পাঠযোগ্য করে তুলছে।

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

private int getFooBarBazInt() {
    if (wsObject.getFoo() == null) return -1;
    if (wsObject.getFoo().getBar() == null) return -1;
    if (wsObject.getFoo().getBar().getBaz() == null) return -1;
    return wsObject.getFoo().getBar().getBaz().getInt();
}

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

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

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

public static class MyFoo {

    private int barBazInt;

    public MyFoo(Foo foo) {
        this.barBazInt = parseBarBazInt();
    }

    public int getBarBazInt() {
        return barBazInt;
    }

    private int parseFooBarBazInt(Foo foo) {
        if (foo() == null) return -1;
        if (foo().getBar() == null) return -1;
        if (foo().getBar().getBaz() == null) return -1;
        return foo().getBar().getBaz().getInt();
    }

}

1
return wsObject.getFooBarBazInt();

আইন প্রয়োগকারীর আইন প্রয়োগ করে,

class WsObject
{
    FooObject foo;
    ..
    Integer getFooBarBazInt()
    {
        if(foo != null) return foo.getBarBazInt();
        else return null;
    }
}

class FooObject
{
    BarObject bar;
    ..
    Integer getBarBazInt()
    {
        if(bar != null) return bar.getBazInt();
        else return null;
    }
}

class BarObject
{
    BazObject baz;
    ..
    Integer getBazInt()
    {
        if(baz != null) return baz.getInt();
        else return null;
    }
}

class BazObject
{
    Integer myInt;
    ..
    Integer getInt()
    {
        return myInt;
    }
}

0

উত্তর দেওয়া যা অন্য সবার থেকে আলাদা বলে মনে হচ্ছে।

আমি আপনার জন্য চেক করতে সুপারিশ NULLমধ্যে ifগুলি।

কারণ:

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

আপনার কোডটি পড়তে সহজ করার জন্য শর্তাদি পরীক্ষা করার জন্য এটি ব্যবহার করে দেখুন:

if (wsObject.getFoo() == null || wsObject.getFoo().getBar() == null || wsObject.getFoo().getBar().getBaz() == null) 
   return -1;
else 
   return wsObject.getFoo().getBar().getBaz().getInt();

সম্পাদনা:

এখানে আপনি এই মান সংরক্ষণ করতে প্রয়োজন wsObject.getFoo(), wsObject.getFoo().getBar(), wsObject.getFoo().getBar().getBaz()কিছু ভেরিয়েবল হবে। আমি এটি করছি না কারণ আমি ফাংশনগুলির রিটার্নের ধরনগুলি জানি না।

কোন পরামর্শ প্রশংসা করা হবে .. !!


আপনি getFoo () কে খুব টাইমকনসুমিং অপারেশন হিসাবে বিবেচনা করেছেন? আপনার পরিবর্তনশীলগুলিতে ফিরে আসা মানগুলি সংরক্ষণ করা উচিত, তবে এটি মেমরির অপচয় নয় a আপনার পদ্ধতি সি প্রোগ্রামিংয়ের জন্য উপযুক্ত।
xenteros

তবে কোনও এক মুহুর্তে 1 মিলিসেকেন্ড দেরী হওয়া ভাল তবে প্রোগ্রামটি @xenteros ক্র্যাশ হচ্ছে .. !!
জানকি গাধিয়া

getFoo () অন্য মহাদেশে অবস্থিত কোনও সার্ভার থেকে একটি মান পেতে পারে। এটি যে কোনও সময় স্থায়ী হতে পারে: মিনিট / ঘন্টা ...
xenteros

wsObjectওয়েবসার্ভিস থেকে ফেরত মান থাকবে .. !! পরিষেবাটি ইতিমধ্যে কল করা wsObjectহবে এবং একটি ওয়েব সার্ভিস XMLপ্রতিক্রিয়া হিসাবে একটি দীর্ঘ তথ্য পাবেন .. !! সুতরাং অন্য মহাদেশে অবস্থিত সার্ভারের মতো কিছুই নেই কারণ getFoo()কেবলমাত্র একটি উপাদান প্রাপ্তির পদ্ধতিটি ওয়েব সার্ভিস কল নয় .. !! @ এক্সেনরোস
জাঙ্কি গধিয়া

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

0

আমি একটি ক্লাস লিখেছি Snagযা আপনাকে বস্তুর গাছের মধ্যে দিয়ে নেভিগেট করার জন্য একটি পথ নির্ধারণ করতে দেয়। এটির ব্যবহারের উদাহরণ এখানে:

Snag<Car, String> ENGINE_NAME = Snag.createForAndReturn(Car.class, String.class).toGet("engine.name").andReturnNullIfMissing();

এর অর্থ হ'ল উদাহরণটি ENGINE_NAMEকার্যকরভাবে যে উদাহরণটি দিয়েছিল তা কল Car?.getEngine()?.getName()করবে এবং nullকোনও রেফারেন্স যদি ফিরে আসে null:

final String name =  ENGINE_NAME.get(firstCar);

এটি মাভেনে প্রকাশিত হয়নি তবে যদি কেউ এটি দরকারী খুঁজে পান তবে এটি এখানে রয়েছে (অবশ্যই কোনও ওয়ারেন্টি নেই!)

এটি কিছুটা বেসিক তবে মনে হয় কাজটি করছে। স্পষ্টতই এটি জাভা এবং অন্যান্য JVM ভাষাগুলির আরও সাম্প্রতিক সংস্করণগুলি সহ নিরাপদ নেভিগেশন সমর্থন করে বা আরও অপ্রচলিত Optional

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