কখন একটি অবৈধআর্গুমেন্টএক্সেপশন নিক্ষেপ করা উচিত?


98

আমি উদ্বিগ্ন যে এটি রানটাইম ব্যতিক্রম তাই সম্ভবত এটি খুব কম ব্যবহার করা উচিত।
স্ট্যান্ডার্ড ব্যবহারের কেস:

void setPercentage(int pct) {
    if( pct < 0 || pct > 100) {
         throw new IllegalArgumentException("bad percent");
     }
}

তবে মনে হয় এটি নিম্নলিখিত নকশাকে বাধ্য করবে:

public void computeScore() throws MyPackageException {
      try {
          setPercentage(userInputPercent);
      }
      catch(IllegalArgumentException exc){
           throw new MyPackageException(exc);
      }
 }

এটিকে চেক করা ব্যতিক্রম হিসাবে ফিরে পেতে।

ঠিক আছে, তবে এর সাথে চলুন। আপনি যদি খারাপ ইনপুট দেন তবে আপনি রানটাইম ত্রুটি পাবেন। সুতরাং প্রথমত এটি একইরূপে বাস্তবায়ন করা মোটামুটি কঠিন নীতি, কারণ আপনাকে একেবারে বিপরীত রূপান্তর করতে হতে পারে:

public void scanEmail(String emailStr, InputStream mime) {
    try {
        EmailAddress parsedAddress = EmailUtil.parse(emailStr);
    }
    catch(ParseException exc){
        throw new IllegalArgumentException("bad email", exc);
    }
}

এবং আরও খারাপ - 0 <= pct && pct <= 100ক্লায়েন্ট কোডটি পরীক্ষা করার সময় স্থিতিশীলভাবে প্রত্যাশা করা যেতে পারে, এটি আরও উন্নত ডেটার যেমন ইমেল ঠিকানা, বা আরও খারাপ কোনও ডেটাবেসের বিরুদ্ধে যাচাই করতে হয় না, তাই সাধারণ ক্লায়েন্ট কোডটি প্রাক- বৈধ করা।

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

উত্তর:


80

এর জন্য এপিআই ডক IllegalArgumentException:

কোনও পদ্ধতিতে একটি অবৈধ বা অনুপযুক্ত যুক্তি পাস করা হয়েছে তা বোঝাতে ছুড়ে দেওয়া হয়েছিল।

এটি জেডিকে পাঠাগারগুলিতে কীভাবে ব্যবহৃত হয় তা দেখার থেকে আমি বলব:

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

  • এটি এমন ক্ষেত্রে ব্যবহার করা হয় যেখানে চেক করা ব্যতিক্রম ছোঁড়া খুব বিরক্তিকর হবে (যদিও এটি java.lang.reflect কোডে উপস্থিত হয়েছে, যেখানে চেক-ব্যতিক্রম-ছোঁড়ার হাস্যকর স্তর সম্পর্কে উদ্বেগ অন্যথায় স্পষ্ট নয়)।

আমি IllegalArgumentExceptionসাধারণ ইউটিলিটিগুলি (জেডিকে ব্যবহারের সাথে সামঞ্জস্য রাখার চেষ্টা করছি) সর্বশেষ খাঁজ প্রতিরক্ষামূলক যুক্তি পরীক্ষা করতে ব্যবহার করব use বা যেখানে প্রত্যাশাটি একটি খারাপ যুক্তি একটি প্রোগ্রামার ত্রুটি, একটি অনুরূপ NullPointerException। আমি ব্যবসায়িক কোডে বৈধতা প্রয়োগ করতে এটি ব্যবহার করব না। আমি অবশ্যই এটি ইমেলের উদাহরণের জন্য ব্যবহার করব না।


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

22

"খারাপ ইনপুট" সম্পর্কে কথা বলার সময়, আপনাকে ইনপুটটি কোথা থেকে আসছে তা বিবেচনা করা উচিত।

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

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


4
"আপনার কখনই চেক করা ব্যতিক্রমগুলি ধরা উচিত নয়"?
Koray Tugay

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

4
Because an unchecked exception is meant to be thrown as a result of a programming errorআমাকে আমার মাথায় প্রচুর পরিমাণে জিনিস পরিষ্কার করতে সহায়তা করেছে, আপনাকে ধন্যবাদ :)
স্বরোগ

14

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

যদি পুনরুদ্ধারের কোনও আশা না থাকে তবে চেক করা ব্যতিক্রমগুলি নির্দ্বিধায় ব্যবহার করুন; তাদের ধরার কোনও মানে নেই, তাই এটি পুরোপুরি ঠিক।

যদিও আপনার উদাহরণে এই উদাহরণটি আপনার কোডটিতে রয়েছে তা আপনার উদাহরণ থেকে এটি 100% স্পষ্ট নয়।


আমি "যুক্তিযুক্তভাবে পুনরুদ্ধার প্রত্যাশিত" ওয়েজলি বলে মনে করি। যে কোনও অপারেশন এর foo(data)অংশ হিসাবে ঘটতে পারে for(Data data : list) foo(data);যার মধ্যে কলার কিছু তথ্য ত্রুটিযুক্ত থাকা সত্ত্বেও যতটা সম্ভব সফল হতে পারে। প্রোগ্রামেটিক ত্রুটিগুলিও অন্তর্ভুক্ত করে, যদি আমার অ্যাপ্লিকেশন ব্যর্থ হয় তবে কোনও লেনদেন সম্ভবত সবচেয়ে ভাল হয় না, যদি এর অর্থ পারমাণবিক শীতলতা অফলাইনে চলে যায় তবে এটি খারাপ।
djechlin

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

4
পারমাণবিক শীতলকরণের অ্যাপ্লিকেশনটিতে, প্রোগ্রামার ভেবেছিলেন যে কোনও বিষয় অলক্ষিতভাবে পাস করা অসম্ভব, এমন একটি মামলার অনুমতি দেওয়ার চেয়ে আমি পরীক্ষায় কঠোরভাবে ব্যর্থ হব।
লুই ওয়াসারম্যান

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

5

ওরাকল অফিসিয়াল টিউটোরিয়ালে যেমন উল্লেখ করা হয়েছে, এতে বলা হয়েছে:

কোনও ক্লায়েন্ট যদি যুক্তিযুক্তভাবে ব্যতিক্রম থেকে পুনরুদ্ধার আশা করা যায়, তবে এটি একটি চেক করা ব্যতিক্রম করুন। যদি কোনও ক্লায়েন্ট ব্যতিক্রম থেকে পুনরুদ্ধার করতে কিছু করতে না পারে, তবে এটি একটি চেক করা ব্যতিক্রম করুন।

যদি আমার কাছে ডেটাবেস ব্যবহার করে কোনও অ্যাপ্লিকেশন ইন্টারঅ্যাক্ট করে থাকে JDBCএবং আমার কাছে এমন একটি পদ্ধতি রয়েছে যা আর্গুমেন্টটিকে int itemএবং হিসাবে গ্রহণ করে double pricepriceজন্য সংশ্লিষ্ট আইটেমটি ডাটাবেস সারণি থেকে পড়া হয়। আমি সহজেই মূল্যের itemসাথে কেনা মোট সংখ্যাকে গুণ করি priceএবং ফলাফলটি ফিরে পাই । যদিও আমি সর্বদা আমার শেষে (অ্যাপ্লিকেশন শেষে) নিশ্চিত যে টেবিলের মূল্য ক্ষেত্রের মানটি কখনও নেতিবাচক হতে পারে না ut তবে দামের মানটি যদি নেতিবাচক হয়ে আসে তবে কী হবে ? এটি দেখায় যে ডাটাবেস পক্ষের সাথে একটি গুরুতর সমস্যা রয়েছে। অপারেটর দ্বারা সম্ভবত ভুল মূল্য প্রবেশ। এটি সেই ধরণের সমস্যা যা প্রয়োগের অন্য অংশটি সেই পদ্ধতিটিকে কল করে তা প্রত্যাশা করতে পারে না এবং এ থেকে পুনরুদ্ধার করতে পারে না। এটি BUGআপনার ডাটাবেসে একটি। তাই এবংIllegalArguementException()এই ক্ষেত্রে যা ছুঁড়ে ফেলা উচিত the price can't be negative
আমি আশা করি যে আমি আমার বক্তব্য পরিষ্কারভাবে প্রকাশ করেছি ..


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

5

যে কোনও এপিআই এর কার্যকর করার আগে যে কোনও পাবলিক পদ্ধতির প্রতিটি প্যারামিটারের বৈধতা পরীক্ষা করতে হবে:

void setPercentage(int pct, AnObject object) {
    if( pct < 0 || pct > 100) {
        throw new IllegalArgumentException("pct has an invalid value");
    }
    if (object == null) {
        throw new IllegalArgumentException("object is null");
    }
}

তারা অ্যাপ্লিকেশনটির ত্রুটিগুলির 99.9% উপস্থাপন করে কারণ এটি অসম্ভব ক্রিয়াকলাপের জন্য জিজ্ঞাসা করছে তাই শেষ পর্যন্ত তারা বাগগুলি রয়েছে যাতে অ্যাপ্লিকেশনটি ক্র্যাশ করা উচিত (সুতরাং এটি একটি অ-পুনরুদ্ধারযোগ্য ত্রুটি)।

এই ক্ষেত্রে এবং দ্রুত ব্যর্থতার পদ্ধতির অনুসরণ করে আপনার অ্যাপ্লিকেশন স্থিতিকে কলুষিত করা এড়াতে অ্যাপ্লিকেশনটি শেষ করতে হবে।


বিপরীতে, যদি কোনও এপিআই ক্লায়েন্ট আমাকে একটি খারাপ ইনপুট দেয় তবে আমার পুরো API সার্ভারটি ক্রাশ করা উচিত নয়
djechlin

4
অবশ্যই এটি আপনার এপিআই সার্ভার ক্র্যাশ হওয়া উচিত নয় তবে কলারের কাছে একটি ব্যতিক্রম ফিরিয়ে আনতে হবে যা ক্লায়েন্ট ব্যতীত অন্য কোনও ক্র্যাশ না করে।
ইগনাসিও সোলার গার্সিয়া

মন্তব্যে আপনি যা লিখেছেন তা উত্তরে যা লিখেছেন তা নয়।
djechlin

4
আমাকে ব্যাখ্যা করতে দাও, যদি কোনও তৃতীয় পক্ষের ক্লায়েন্ট ভুল প্যারামিটারগুলির সাথে (একটি বাগ) এপিআইতে কল করেন তবে ক্লায়েন্টটির ক্রাশ হওয়া উচিত। যদি এটি এপিআই সার্ভার হ'ল ভুল পরামিতিগুলির সাথে পদ্ধতিতে কল করার মতো একটি বাগ থাকে তবে এপিআই সার্ভারটি ক্রাশ হওয়া উচিত। চেক করুন: এন.ইইউইকিপিডিয়া.আরউইকি
ইগনাসিও সোলার গার্সিয়া

2

আচরণ IllegalArgumentExceptionহিসেবে পূর্বশর্ত চেক এবং নকশা নীতি বিবেচনা করুন: একটি সর্বজনীন পদ্ধতি উভয় জানি এবং সর্বজনীনভাবে নিজস্ব পূর্বশর্ত নথি করা উচিত নয়।

আমি এই উদাহরণটি সঠিক বলে সম্মত হব:

void setPercentage(int pct) {
    if( pct < 0 || pct > 100) {
         throw new IllegalArgumentException("bad percent");
     }
}

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

import com.someoneelse.EmailUtil;

public void scanEmail(String emailStr, InputStream mime) throws ParseException {
    EmailAddress parsedAddress = EmailUtil.parseAddress(emailStr);
}

যদি ইমেইল ইউটিটি স্বচ্ছ হয় , উদাহরণস্বরূপ সম্ভবত এটি কোনও ব্যক্তিগত পদ্ধতি যা প্রশ্নাবদ্ধ শ্রেণীর মালিকানাধীন, IllegalArgumentExceptionসঠিক এবং যদি কেবলমাত্র তার পূর্বশর্তগুলি ফাংশন ডকুমেন্টেশনে বর্ণনা করা যায়। এটিও একটি সঠিক সংস্করণ:

/** @param String email An email with an address in the form abc@xyz.com
 * with no nested comments, periods or other nonsense.
 */
public String scanEmail(String email)
  if (!addressIsProperlyFormatted(email)) {
      throw new IllegalArgumentException("invalid address");
  }
  return parseEmail(emailAddr);
}
private String parseEmail(String emailS) {
  // Assumes email is valid
  boolean parsesJustFine = true;
  // Parse logic
  if (!parsesJustFine) {
    // As a private method it is an internal error if address is improperly
    // formatted. This is an internal error to the class implementation.
    throw new AssertError("Internal error");
  }
}

এই নকশা যেভাবে যেতে পারে।

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

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

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