আমার জাভাতে আরম্ভকারী ব্লক ব্যবহার করা উচিত?


16

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

public class Test {
  public Test() { /* first constructor */ }
  public Test(String s) { /* second constructor */ }

  // Non-static initializer block - copied into every constructor:
  {
    doStuff();
  }
}

কোড ব্লকটি প্রতিটি কন্সট্রাক্টরে অনুলিপি করা হবে, যদি আপনার একাধিক কনস্ট্রাক্টর থাকে তবে আপনাকে কোডটি পুনরায় লেখার দরকার নেই।

তবে আমি এই সিনট্যাক্সটি ব্যবহার করে তিনটি প্রধান ত্রুটি দেখতে পাচ্ছি:

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

যদি আমার উপরের বক্তব্যগুলি সত্য হয়, তবে কেন এই ভাষা নির্মাণের (এবং কখন) প্রচলন করা হয়েছিল? কোন বৈধ ব্যবহারের মামলা আছে?


3
আপনি যে উদাহরণ পোস্ট করেছেন তাতে কোনও ইনিশিয়াল ব্লকের মতো দেখতে কিছু অন্তর্ভুক্ত নেই।
সাইমন বি

6
@ সিমোন বার্কার আবার দেখুন - { doStuff(); }ক্লাস স্তরটি একটি ইনিশিয়াল ব্লক।
আমন

কোড ব্লক করা হয় যে, পার্শ্ববর্তী @SimonBarkerdoStuff()
পুনর্বহাল মনিকা - dirkk


2
"[এস] ইঙ্গিত দিয়ে কোড ব্লকের ক্রম পরিবর্তন করা আসলে কোড পরিবর্তন করবে।" এবং ভেরিয়েবল ইনিশিয়েলাইজার বা কোডের স্বতন্ত্র লাইনের ক্রম পরিবর্তন করা থেকে এটি কীভাবে আলাদা? যদি কোনও নির্ভরতা না থাকে, তবে কোনও ক্ষতি হয় না এবং যদি নির্ভরতা থাকে তবে নির্ভরতাগুলি আদেশের বাইরে রেখে দেওয়া কোডের পৃথক লাইনের জন্য দুর্বলতা নির্ভরতা হিসাবে সমান। জাভা আপনাকে পদ্ধতিগুলি এবং ক্লাসগুলি সংজ্ঞায়িত করার আগে উল্লেখ করতে দেয় তার অর্থ এই নয় যে অর্ডার-নির্ভর কোডটি জাভাতে বিরল।
জ্যাব 12'14

উত্তর:


20

দুটি ক্ষেত্রে আছে যেখানে আমি ইনিশিয়ালার ব্লক ব্যবহার করি।

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

এটি বৈধ:

final int val = 2;

এটিও বৈধ:

final int val;

MyClass() {
    val = 2;
}

এটি অবৈধ:

final int val;

MyClass() {
    init();
}

void init() {
    val = 2;  // cannot assign to 'final' field in a method
}

আপনার যদি একাধিক কনস্ট্রাক্টর থাকে এবং আপনি যদি চূড়ান্ত সদস্য ইনলাইনটি সূচনা করতে না পারেন (কারণ প্রারম্ভিক যুক্তিটি খুব জটিল), বা যদি নির্মাণকারীরা তাদের কল করতে না পারেন তবে আপনি হয় আরম্ভের কোডটি অনুলিপি / পেস্ট করতে পারেন, বা আপনি ব্যবহার করতে পারেন একটি প্রাথমিক ব্লক

final int val;
final int squareVal;

MyClass(int v, String s) {
    this.val = v;
    this.s = s;
}

MyClass(Point p, long id) {
    this.val = p.x;
    this.id = id;
}

{
    squareVal = val * val;
}

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

private Map<String, String> days = new HashMap<String, String>();
{
    days.put("mon", "monday");
    days.put("tue", "tuesday");
    days.put("wed", "wednesday");
    days.put("thu", "thursday");
    days.put("fri", "friday");
    days.put("sat", "saturday");
    days.put("sun", "sunday");
}

এটি অবৈধ পদ্ধতি পদ্ধতি কল নয়। এটি init পদ্ধতির অভ্যন্তরের কোড যা অবৈধ। কেবলমাত্র কন্সট্রাক্টর এবং ইনিটালাইজার ব্লকগুলি একটি চূড়ান্ত সদস্য ভেরিয়েবলের জন্য বরাদ্দ করতে পারে, সুতরাং থ্রিতে অ্যাসাইনমেন্টটি সংকলন করবে না।
বরজাক

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

11

সাধারণভাবে, অ-স্ট্যাটিক ইনিশিয়ালাইজার ব্লক ব্যবহার করবেন না (এবং সম্ভবত স্ট্যাটিকগুলি এড়ানোও হবে)।

বিভ্রান্তিকর সিনট্যাক্স

এই প্রশ্নটি দেখে 3 টি উত্তর রয়েছে, তবুও আপনি এই সিনট্যাক্স সহ 4 জনকে বোকা বানিয়েছেন। আমি তাদের মধ্যে একজন ছিলাম এবং আমি 16 বছর ধরে জাভা লিখছি! স্পষ্টতই, সিনট্যাক্সটি সম্ভাব্য ত্রুটির প্রবণতা! আমি এ থেকে দূরে থাকব

দূরবীন নির্মাণকারী

সত্যিকারের সরল স্টাফের জন্য, আপনি এই বিভ্রান্তি এড়াতে "টেলিস্কোপিং" কনস্ট্রাক্টর ব্যবহার করতে পারেন:

public class Test {
    private String something;

    // Default constructor does some things
    public Test() { doStuff(); }

    // Other constructors call the default constructor
    public Test(String s) {
        this(); // Call default constructor
        something = s;
    }
}

নির্মাতা প্যাটার্ন

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

public class Test {
    // Value can be final (immutable)
    private final String something;

    // Private constructor.
    private Test(String s) { something = s; }

    // Static method to get a builder
    public static Builder builder() { return new Builder(); }

    // builder class accumulates values until a valid Test object can be created. 
    private static class Builder {
        private String tempSomething;
        public Builder something(String s) {
            tempSomething = s;
            return this;
        }
        // This is our factory method for a Test class.
        public Test build() {
            Test t = new Test(tempSomething);
            // Here we do your extra initialization after the
            // Test class has been created.
            doStuff();
            // Return a valid, potentially immutable Test object.
            return t;
        }
    }
}

// Now you can call:
Test t = Test.builder()
             .setString("Utini!")
             .build();

স্ট্যাটিক ইনিশিয়ালাইজার লুপস

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

অলস সূচনা

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

ডেটা সংজ্ঞা

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

private ImMap<String,String> days =
        map(tup("mon", "monday"),
            tup("tue", "tuesday"),
            tup("wed", "wednesday"),
            tup("thu", "thursday"),
            tup("fri", "friday"),
            tup("sat", "saturday"),
            tup("sun", "sunday"));

Conculsion

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


3

final( বারজাকের উত্তর দেখুন ) হিসাবে ঘোষিত একটি উদাহরণ ভেরিয়েবলের সূচনাকরণের পাশাপাশি আমি staticআরম্ভের ব্লকটিও উল্লেখ করব ।

আপনি এগুলিকে "স্ট্যাটিক কনট্রাক্টর" হিসাবে ব্যবহার করতে পারেন।

এইভাবে ক্লাসটি প্রথমবার রেফারেন্স করার পরে আপনি স্ট্যাটিক ভেরিয়েবলের উপর জটিল সূচনা করতে পারেন।

বারজাকের দ্বারা অনুপ্রাণিত একটি উদাহরণ এখানে:

public class dayHelper(){
    private static Map<String, String> days = new HashMap<String, String>();
    static {
        days.put("mon", "monday");
        days.put("tue", "tuesday");
        days.put("wed", "wednesday");
        days.put("thu", "thursday");
        days.put("fri", "friday");
        days.put("sat", "saturday");
        days.put("sun", "sunday");
    }
    public static String getLongName(String shortName){
         return days.get(shortName);
    }
}

1

অ স্ট্যাটিক ইনিশিয়ালাইজার ব্লকগুলি যত তাড়াতাড়ি সম্পর্কিত, ততক্ষণ তাদের অনাবৃত ফাংশন বেনাম শ্রেণিতে একটি ডিফল্ট নির্মাতা হিসাবে কাজ করা। এটিই মূলত তাদের অস্তিত্বের অধিকার।


0

আমি 1, 2, 3 বিবৃতিগুলির সাথে সম্পূর্ণ একমত I আমি এই কারণে ব্লক ইনিশিয়ালাইজারগুলি কখনও ব্যবহার করি না এবং জাভাতে কেন এটি বিদ্যমান তা আমি জানি না।

যাইহোক, আমি এক ক্ষেত্রে স্ট্যাটিক ব্লক ইনিশিয়ালাইজারটি ব্যবহার করতে বাধ্য হই : যখন আমাকে এমন স্ট্যাটিক ক্ষেত্র ইনস্ট্যান্ট করতে হয় যার নির্মাতা একটি চেক করা ব্যতিক্রম ছুঁড়ে ফেলতে পারে।

private static final JAXBContext context = JAXBContext.newInstance(Foo.class); //doesn't compile

তবে পরিবর্তে আপনাকে এটি করতে হবে:

private static JAXBContext context;
static {
    try
    {
        context = JAXBContext.newInstance(Foo.class);
    }
    catch (JAXBException e)
    {
        //seriously...
    }
}

আমি এই বাগ্ধারা খুব কুৎসিত (এটা এছাড়াও চিহ্ন আপনার আটকায় এটি contextযেমন final) কিন্তু এই একমাত্র উপায় জাভা দ্বারা সমর্থিত এমন ক্ষেত্র আরম্ভ হয়।


আমি মনে করি আপনি context = null;যদি আপনার ক্যাচ ব্লকে সেট করেন তবে আপনি প্রসঙ্গটি চূড়ান্ত হিসাবে ঘোষণা করতে সক্ষম হতে পারেন।
গ্লেনপিটারসন

@ গ্লেনপিটারসন আমি চেষ্টা করেছিলাম কিন্তু এটি সংকলন করে না:The final field context may already have been assigned
স্পটড

ওহো! আমি বাজি static { JAXBContext tempCtx = null; try { tempCtx = JAXBContext.newInstance(Foo.class); } catch (JAXBException ignored) { ; } context = tempCtx; }
ধরছি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.