জাভা চেক ব্যাতিক্রমের জন্য workaround


49

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

    Arrays.asList(p.getClass().getFields()).forEach(
        f -> System.out.println(f.get(p))
    );

তবুও, যেহেতু getপদ্ধতিটি একটি পরীক্ষিত ব্যতিক্রম ছুঁড়ে ফেলতে পারে, যা Consumerইন্টারফেস চুক্তির সাথে একমত নয় , তাই আমাকে অবশ্যই এই ব্যতিক্রমটি ধরতে হবে এবং নিম্নলিখিত কোডটি লিখতে হবে:

    Arrays.asList(p.getClass().getFields()).forEach(
            f -> {
                try {
                    System.out.println(f.get(p));
                } catch (IllegalArgumentException | IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                }
            }
    );

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

সুতরাং, চেক করা ব্যতিক্রম বিরক্তির জন্য আমি আমার বিতর্কিত কর্মকাণ্ড সম্পর্কে আপনার মতামত রাখতে চাই। সে লক্ষ্যে, আমি একটি সহায়ক ইন্টারফেস ConsumerCheckException<T>এবং একটি ইউটিলিটি ফাংশন তৈরি করেছি rethrow( ডোভালের মন্তব্য অনুসারে আপডেট করা হয়েছে ):

  @FunctionalInterface
  public interface ConsumerCheckException<T>{
      void accept(T elem) throws Exception;
  }

  public class Wrappers {
      public static <T> Consumer<T> rethrow(ConsumerCheckException<T> c) {
        return elem -> {
          try {
            c.accept(elem);
          } catch (Exception ex) {
            /**
             * within sneakyThrow() we cast to the parameterized type T. 
             * In this case that type is RuntimeException. 
             * At runtime, however, the generic types have been erased, so 
             * that there is no T type anymore to cast to, so the cast
             * disappears.
             */
            Wrappers.<RuntimeException>sneakyThrow(ex);
          }
        };
      }

      /**
       * Reinier Zwitserloot who, as far as I know, had the first mention of this
       * technique in 2009 on the java posse mailing list.
       * http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
       */
      public static <T extends Throwable> T sneakyThrow(Throwable t) {
          throw (T) t;
      }
  }

এবং এখন আমি কেবল লিখতে পারি:

    Arrays.asList(p.getClass().getFields()).forEach(
            rethrow(f -> System.out.println(f.get(p)))
    );

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



2
রবার্টের লিঙ্কের পাশাপাশি, স্নাকিলি থ্রোইং চেকড ব্যতিক্রমগুলিও একবার দেখুন । আপনি যদি চান, আপনি এটি sneakyThrowভিতরে rethrowমোড়ক না করে মূল, চেক ব্যতিক্রমটি ছুঁড়ে ফেলার জন্য ভিতরে ব্যবহার করতে পারেন RuntimeException। বিকল্পভাবে আপনি প্রকল্প লম্বোক@SneakyThrows থেকে টীকাগুলি ব্যবহার করতে পারেন যা একই কাজ করে।
ডোভাল

1
এছাড়াও মনে রাখবেন Consumers এ forEachযখন সমান্তরাল ব্যবহার সমান্তরাল ফ্যাশন মৃত্যুদন্ড কার্যকর করা যেতে পারে Streamসে। গ্রাহকের সাথে যোগ দেওয়া থেকে উত্থাপিত একটি নিক্ষেপকারী কলিং থ্রেডে প্রচার করবে, যা 1) অন্য একযোগে চলমান গ্রাহকরা থামবে না, যা উপযুক্ত বা উপযুক্ত নাও হতে পারে, এবং 2) যদি একাধিক ভোক্তা কিছু ফেলে দেয় তবে কেবল থ্রোয়েবলগুলির মধ্যে একটি কলিং থ্রেড দ্বারা দেখা যাবে।
জুনাস পুলক্কা


2
লাম্বদাস তাই কুরুচিপূর্ণ।
তুলিনস কর্ডোভা

উত্তর:


16

আপনার কৌশলটির সুবিধাগুলি, অসুবিধাগুলি এবং সীমাবদ্ধতাগুলি:

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

    public void test(Object p) throws IllegalAccessException {
        Arrays.asList(p.getClass().getFields()).forEach(rethrow(f -> System.out.println(f.get(p))));
    }
    
  • যদি কলিং-কোডটি ইতিমধ্যে চেক করা ব্যতিক্রমটি পরিচালনা করে তবে সংকলকটি আপনাকে স্ট্রিমটি উপস্থিত পদ্ধতি ঘোষণায় থ্রোস ক্লজ যুক্ত করার জন্য স্মরণ করিয়ে দেবে (যদি আপনি এটি না বলেন, ব্যতিক্রমটি কখনও কখনও চেষ্টা করার অনুরোধের শৃঙ্খলে ফেলা হয় না) ।

  • যাই হোক না কেন, আপনি পরীক্ষিত ব্যতিক্রমটি ধরতে নিজেই প্রবাহটিকে ঘিরেই সক্ষম হবেন না যে পদ্ধতিটিতে স্ট্রিম রয়েছে তার মধ্যে লিখুন (যদি আপনি চেষ্টা করেন, সংকলকটি বলবে: ব্যতিক্রম কখনও সংশ্লিষ্ট চেষ্টা বিবৃতিতে দেবে না)।

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

  • আপনি যদি চেক করা ব্যতিক্রমগুলি ঘৃণা করেন এবং মনে করেন যে এগুলি শুরু করার জন্য জাভা ভাষার সাথে আর যুক্ত করা উচিত নয় (ক্রমবর্ধমান সংখ্যক লোক এইভাবে মনে করে, এবং আমি তাদের মধ্যে কেউ নই), তবে কেবল ছোঁড়াটি থেকে চেক করা ব্যতিক্রম যুক্ত করবেন না স্ট্রিম রয়েছে এমন পদ্ধতির ধারা। চেক করা ব্যতিক্রমগুলি তখন একটি চেক করা ব্যতিক্রমের মতো আচরণ করবে।

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

  • যে কোনও ক্ষেত্রে, আপনি যদি স্ট্রিম রয়েছে এমন পদ্ধতির ছোঁড়া অনুচ্ছেদে চেক করা ব্যতিক্রম যুক্ত (বা যুক্ত করতে ভুলবেন না) তবে চেকড ব্যতিক্রম ছোঁড়ার এই 2 পরিণতি সম্পর্কে সচেতন হন:

    1. কলিং-কোড নামটি ধরতে সক্ষম হবে না (যদি আপনি চেষ্টা করেন, সংকলকটি বলবে: ব্যতিক্রমটি কখনও কখনও চেষ্টা করার অনুরোধের শৃঙ্খলে ফেলা হয় না)। এটি বুদবুদ হবে এবং সম্ভবত কিছু "ক্যাচ এক্সেপশন" বা "ক্যাচ থ্রোয়েবল" দ্বারা মূল প্রোগ্রামের লুপে ধরা হবে, যা আপনি যেভাবে চান তা হতে পারে।

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

তথ্যসূত্র:

দ্রষ্টব্য: আপনি যদি এই কৌশলটি ব্যবহার করার সিদ্ধান্ত নেন, আপনি LambdaExceptionUtilস্ট্যাকওভারফ্লো থেকে সহায়ক শ্রেণিকে অনুলিপি করতে পারেন : https://stackoverflow.com/questions/27644361/how-can-i-throw-checked-exception-from-inside-java-8 -প্রবাহ । এটি আপনাকে উদাহরণ সহ পুরো বাস্তবায়ন (ফাংশন, গ্রাহক, সরবরাহকারী ...) দেয়।


6

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

এটি বিতর্কিত অনুশীলনে তাই ওয়াইএমএমভি। আমি সম্ভবত কিছু ডাউনওয়েটস পাব।


3
+1 কারণ আপনি একটি ত্রুটি নিক্ষেপ করবেন। কেবলমাত্র একটি লাইনের মন্তব্য "ঘটতে পারে না" এমন ক্যাপ ব্লকে কয়েক ঘন্টা ডিবাগিংয়ের পরে আমি কতবার শেষ হয়েছি ...
এক্সেল

3
-1 কারণ আপনি একটি ত্রুটি নিক্ষেপ করবেন। ত্রুটিগুলি JVM তে কিছু ভুল রয়েছে তা বোঝাতে এবং উচ্চ স্তরেরগুলি সে অনুযায়ী পরিচালনা করতে পারে। আপনি যদি সেভাবে চয়ন করেন তবে আপনার রানটাইম এক্সেপশন নিক্ষেপ করা উচিত। আর একটি সম্ভাব্য কাজের ক্ষেত্র হ'ল আসক্তি (প্রয়োজনীয়-پرچم সক্ষম হওয়া) বা লগিং।
দুরোস

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

1
@ সুপের্যাট চমৎকার উদাহরণ। অন্যরা স্ট্রিং এনকোডিংগুলি বা বার্তা ডাইজেসটগুলি থেকে ব্যতিক্রম ছুঁড়ে দিচ্ছে যদি ইউটিএফ -8 বা এসএইচএ অনুপস্থিত থাকে তবে আপনার রানটাইমটি দূষিত হওয়ার সম্ভাবনা রয়েছে।
user949300

1
@ ডুরোস এটি সম্পূর্ণ ভুল ধারণা। An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.(জাভাদোক থেকে উদ্ধৃত Error) এটি ঠিক সেই ধরণের পরিস্থিতি, অতএব অপর্যাপ্ত হওয়া থেকে দূরে, Errorএখানে নিক্ষেপ করা সবচেয়ে উপযুক্ত বিকল্প।
বিজিকলপ

1

এই কোডের অন্য একটি সংস্করণ যেখানে চেক করা ব্যতিক্রম সবেমাত্র বিলম্বিত হয়েছে:

public class Cocoon {
         static <T extends Throwable> T forgetThrowsClause(Throwable t) throws T{
            throw (T) t;
        }

        public static <X, T extends Throwable> Consumer<X> consumer(PeskyConsumer<X,T> touchyConsumer) throws T {
            return new Consumer<X>() {
                @Override
                public void accept(X t) {
                    try {
                        touchyConsumer.accept(t);
                    } catch (Throwable exc) {
                        Cocoon.<RuntimeException>forgetThrowsClause(exc) ;
                    }

                }
            } ;
        }
// and so on for Function, and other codes from java.util.function
}

যাদুটি যদি আপনি কল করেন:

 myArrayList.forEach(Cocoon.consumer(MyClass::methodThatThrowsException)) ;

তারপরে আপনার কোডটি ব্যতিক্রম ধরা বাধ্য থাকবে


এটি যদি সমান্তরাল প্রবাহে চালিত হয় যেখানে উপাদানগুলি বিভিন্ন থ্রেডে গ্রাস করা হয়?
ছাঁটাই

0

হাঁচি থ্রো দুর্দান্ত! আমি আপনার ব্যথা পুরোপুরি অনুভব করছি।

আপনার যদি জাভাতে থাকতে হয় ...

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

চেষ্টা করার জন্য রয়েছে ভিএভিআর এবং দ্য এক্সিলিপস সংগ্রহও

অন্যথায় কোটলিন ব্যবহার করুন

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


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

1
গিথুব আপনার লাইব্রেরির জন্য +1, আপনি eclipse.org/collections বা প্রজেক্ট ভিভর যা কার্যকরী এবং অপরিবর্তনীয় সংগ্রহ সরবরাহ করে তাও পরীক্ষা করতে পারেন । এগুলি সম্পর্কে আপনার কী ধারণা?
ফায়ারফিল

-1

চেক করা ব্যতিক্রমগুলি খুব দরকারী এবং তাদের পরিচালনা আপনার কোডের যে ধরণের পণ্যের কোড তার উপর নির্ভর করে:

  • পাঠাগার
  • একটি ডেস্কটপ অ্যাপ্লিকেশন
  • কিছু বাক্সের মধ্যে একটি সার্ভার চলছে
  • একটি একাডেমিক অনুশীলন

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

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

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

একাডেমিকাল অনুশীলনের জন্য আপনি এগুলি সর্বদা সরাসরি রানটাইমএক্সসেপ্টনে মুড়ে রাখতে পারেন। কেউ একটি ছোট কাঠামো তৈরি করতে পারেন।


-1

আপনি এই প্রকল্পটি একবার দেখতে চান ; আমি এটি বিশেষত চেক করা ব্যতিক্রম এবং কার্যকরী ইন্টারফেসগুলির সমস্যার কারণে তৈরি করেছি।

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

// I don't know the type of f, so it's Foo...
final ThrowingConsumer<Foo> consumer = f -> System.out.println(f.get(p));

যেহেতু এই সমস্ত নিক্ষেপকারী * ইন্টারফেসগুলি তাদের নন থ্রোংয়ের অংশগুলিকে প্রসারিত করে, তারপরে আপনি এগুলি সরাসরি প্রবাহে ব্যবহার করতে পারেন:

Arrays.asList(p.getClass().getFields()).forEach(consumer);

অথবা আপনি কেবল পারেন:

import static com.github.fge.lambdas.consumers.Consumers.wrap;

Arrays.asList(p.getClass().getFields())
    .forEach(wrap(f -> System.out.println(f.get(p)));

এবং অন্যান্য জিনিস.


আরও ভালfields.forEach((ThrowingConsumer<Field>) f -> out.println(f.get(o)))
ব্যবহারকারী 2418306

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