কোটলিন - "অলস দ্বারা" বনাম "ল্যাটিনাইট" ব্যবহার করে সম্পত্তি শুরুকরণ


279

কোটলিনে আপনি যদি কনস্ট্রাক্টরের অভ্যন্তরে বা শ্রেণিবদ্ধের শীর্ষে কোনও শ্রেণীর সম্পত্তি শুরু করতে না চান তবে আপনার কাছে মূলত এই দুটি বিকল্প রয়েছে (ভাষার রেফারেন্স থেকে):

  1. অলস সূচনা

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

উদাহরণ

public class Hello {

   val myLazyString: String by lazy { "Hello" }

}

প্রথম কল এবং subquential কল, যেখানেই থাকুন না কেন এটা করা হয়, তাই myLazyString ফিরে আসবে "হ্যালো"

  1. দেরী সূচনা

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

এই কেসটি পরিচালনা করতে আপনি ল্যাটিনাইট সংশোধক দিয়ে সম্পত্তি চিহ্নিত করতে পারেন:

public class MyTest {
   
   lateinit var subject: TestSubject

   @SetUp fun setup() { subject = TestSubject() }

   @Test fun test() { subject.method() }
}

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

সুতরাং, এই দুটি বিকল্পের মধ্যে কীভাবে সঠিকভাবে চয়ন করবেন, যেহেতু উভয়ই একই সমস্যা সমাধান করতে পারে?

উত্তর:


334

এখানে অর্পিত সম্পত্তি lateinit varএবং এর মধ্যে উল্লেখযোগ্য পার্থক্য রয়েছে by lazy { ... }:

  • lazy { ... }প্রতিনিধি কেবলমাত্র valবৈশিষ্ট্যগুলির জন্য ব্যবহার করা যেতে পারে, যেখানে lateinitকেবলমাত্র প্রয়োগ করা যায় var, কারণ এটি কোনও finalক্ষেত্রে সংকলন করা যায় না , ফলে কোনও অপরিবর্তনীয়তা গ্যারান্টিযুক্ত হতে পারে না;

  • lateinit varএকটি ব্যাকিং ফিল্ড রয়েছে যা মানটি সঞ্চয় করে, এবং by lazy { ... }একটি প্রতিনিধি অবজেক্ট তৈরি করে যেখানে মানটি একবার গণনা করা হয়, প্রতিনিধি উদাহরণের রেফারেন্সটি ক্লাস অবজেক্টে সংরক্ষণ করে এবং প্রতিনিধি উদাহরণের সাথে কাজ করে এমন সম্পত্তিটির জন্য গেটর তৈরি করে। সুতরাং আপনার যদি ক্লাসে উপস্থিত ব্যাকিং ফিল্ডের প্রয়োজন হয়, ব্যবহার করুন lateinit;

  • valগুলি ছাড়াও , lateinitনন-অযোগ্য বৈশিষ্ট্য এবং জাভা আদিম ধরণের জন্য ব্যবহার করা যাবে না (এটি কারণ nullঅবিচ্ছিন্ন মানের জন্য ব্যবহৃত হয়);

  • lateinit varঅবজেক্টটি যে কোনও জায়গা থেকে দেখা যায় সেখান থেকে সূচনা করা যেতে পারে, উদাহরণস্বরূপ ফ্রেমওয়ার্ক কোডের অভ্যন্তর থেকে এবং একক শ্রেণীর বিভিন্ন অবজেক্টের জন্য একাধিক সূত্রপাত সম্ভব। by lazy { ... }পরিবর্তে, সম্পত্তিটির একমাত্র সূচনা সংজ্ঞা দেয়, যা কেবল একটি সাবক্লাসে সম্পত্তি ওভাররাইড করে পরিবর্তন করা যেতে পারে। আপনি যদি চান যে আপনার সম্পত্তি বাইরে থেকে এমনভাবে শুরু করা যেতে পারে যা আগেই অজানা ছিল, তবে ব্যবহার করুন lateinit

  • সূচনাটি by lazy { ... }ডিফল্টরূপে থ্রেড-নিরাপদ এবং গ্যারান্টি দেয় যে ইনিশিয়ালাইজারটি একবারে ডাকা হবে (তবে এটি অন্য lazyওভারলোড ব্যবহার করে পরিবর্তন করা যেতে পারে )। এর ক্ষেত্রে lateinit var, মাল্টি-থ্রেড পরিবেশে সম্পত্তি সঠিকভাবে শুরু করা ব্যবহারকারীর কোডের উপর নির্ভর করে।

  • একটি Lazyউদাহরণ সংরক্ষণ করা যেতে পারে, প্রায় পাস এবং এমনকি একাধিক বৈশিষ্ট্যের জন্য ব্যবহার করা যেতে পারে। বিপরীতে, lateinit varগুলি কোনও অতিরিক্ত রানটাইম স্থিতি সঞ্চয় করবে না (কেবল nullঅবিশ্রুত মানের জন্য ক্ষেত্রে)।

  • তোমাদের মধ্যে একটি দৃষ্টান্ত একটি রেফারেন্স কাছে, তাহলে Lazy, isInitialized()আপনি তা ইতিমধ্যে সক্রিয়া করা হয়েছে চেক করতে (এবং আপনি করতে পারেন প্রতিফলন দিয়ে এত উদাহরণস্বরূপ প্রাপ্ত একটি অর্পণ সম্পত্তি থেকে)। কোনও ল্যাটিনিট সম্পত্তি শুরু করা হয়েছে কিনা তা পরীক্ষা করতে আপনি কোটলিন ১.২ থেকে ব্যবহারproperty::isInitialized করতে পারেন

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

এছাড়াও, প্রশ্নে উল্লিখিত না হওয়ার মতো আরও একটি উপায় রয়েছে: Delegates.notNull()যা জাভা আদিম ধরণেরগুলি সহ নন-নাল বৈশিষ্ট্যগুলি স্থগিতকরণের জন্য উপযুক্ত।


9
দুর্দান্ত উত্তর! আমি যুক্ত করব যা lateinitসেটারের দৃশ্যমানতার সাথে এর ব্যাকিং ফিল্ডটি প্রকাশ করে যাতে কোটলিন থেকে এবং জাভা থেকে সম্পত্তিটি অ্যাক্সেস করার উপায়গুলি আলাদা are এবং জাভা কোড থেকে এই সম্পত্তিটি nullকোটলিনে কোনও চেক ছাড়াই সেট করা যেতে পারে । সুতরাং lateinitঅলস সূচনা করার জন্য নয় তবে প্রাথমিকভাবে কোটলিন কোড থেকে প্রয়োজনীয় নয়।
মাইকেল

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

@ মার্চি, আপনি এটি করতে পরিষ্কারভাবে সঞ্চিত Lazy+ ব্যবহার করতে পারেন .isInitialized()। আমি অনুমান করি nullযে গ্যারান্টি আপনি nullএটি থেকে পেতে পারবেন না কারণ এর জন্য এই জাতীয় কোনও সম্পত্তি যাচাই করার জন্য সোজা উপায় নেই । :) এই ডেমো দেখুন ।
হটকি

@ হটকি by lazyবিল্ড টাইম বা রানটাইমকে ধীর করতে পারে এমন অনেক বেশি ব্যবহার করার কোনও ধারণা আছে কি ?
ডাঃ জ্যাকি

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

26

Additionnally করতে hotkeyএর ভাল উত্তর, এখানে কিভাবে আমি বাস্তবে দুই চয়ন হল:

lateinit বাহ্যিক আরম্ভের জন্য: যখন কোনও পদ্ধতিতে কল করে আপনার মানটি আরম্ভ করার জন্য আপনার বাহ্যিক স্টাফের প্রয়োজন হয়।

যেমন কল করে:

private lateinit var value: MyClass

fun init(externalProperties: Any) {
   value = somethingThatDependsOn(externalProperties)
}

যদিও lazyযখন এটি শুধুমাত্র আপনার বস্তু অভ্যন্তরীণ নির্ভরতা ব্যবহার করে।


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

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

24

খুব সংক্ষিপ্ত এবং সংক্ষিপ্ত উত্তর

ল্যাটিনিট: এটি নন-নাল বৈশিষ্ট্যগুলি ইদানীং সূচনা করে

অলস প্রারম্ভিককরণের বিপরীতে, ল্যাটিনিট সংকলকটিকে স্বীকৃতি দেয় যে নন-নাল সম্পত্তির মান নির্ধারক পর্যায়ে সাধারণভাবে সংকলনের জন্য সংরক্ষণ করা হয় না।

অলস সূচনা

কোটলিনে অলস-সূচনা করার জন্য কেবলমাত্র পঠনযোগ্য (ভাল) বৈশিষ্ট্যগুলি প্রয়োগ করার সময় অলস দ্বারা খুব কার্যকর হতে পারে ।

অলস দ্বারা {... its তার ইনিশিয়ালাইজারটি সম্পাদন করে যেখানে সংজ্ঞায়িত সম্পত্তিটি প্রথমে ব্যবহৃত হয়, এর ঘোষণাপত্র নয়।


দুর্দান্ত উত্তর, বিশেষত "তার প্রাথমিককরণটি সম্পাদন করে যেখানে সংজ্ঞায়িত সম্পত্তিটি প্রথমে ব্যবহৃত হয়, এটির ঘোষণা নয়"
ব্যবহারকারী 1489829

17

ল্যাটিনাইট বনাম অলস

  1. lateinit

    i) এটিকে পরিবর্তনশীল ভেরিয়েবল [var] সহ ব্যবহার করুন

    lateinit var name: String       //Allowed
    lateinit val name: String       //Not Allowed

    ii) কেবল নন-অযোগ্য ডেটা সহ অনুমোদিত

    lateinit var name: String       //Allowed
    lateinit var name: String?      //Not Allowed

    iii) এটি সংকলনের প্রতিশ্রুতি যে ভবিষ্যতে মানটি আরম্ভ করা হবে।

দ্রষ্টব্য : আপনি যদি আরম্ভ না করেই ল্যাটিনাইট পরিবর্তনশীল অ্যাক্সেস করার চেষ্টা করেন তবে এটি UnInitializedPropertyAccessException নিক্ষেপ করে।

  1. অলস

    i) অলস সূচনাটি অবজেক্টগুলির অপ্রয়োজনীয় প্রারম্ভিক প্রতিরোধের জন্য ডিজাইন করা হয়েছিল।

    ii) আপনার পরিবর্তনশীলটি ব্যবহার না করা শুরু করা হবে না ized

    iii) এটি একবারেই শুরু করা হয়েছে। পরের বার আপনি যখন এটি ব্যবহার করবেন, আপনি ক্যাশে মেমরি থেকে মান পাবেন।

    iv) এটি থ্রেড নিরাপদ (এটি থ্রেডে আরম্ভ হয় যেখানে এটি প্রথমবার ব্যবহৃত হয় Other অন্যান্য থ্রেডগুলি ক্যাশে সঞ্চিত একই মান ব্যবহার করে)।

    উ) পরিবর্তনশীল শুধুমাত্র হতে পারে Val

    vi) ভেরিয়েবলটি কেবল অযোগ্য হয়


7
আমি অলস ভেরিয়েবল ভেরিয়েবল হতে পারে না বলে মনে করি।
দেইশ শর্মি

4

দুর্দান্ত উত্তরের সমস্তগুলি ছাড়াও, একটি ধারণা রয়েছে অলস লোডিং:

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

এটি সঠিকভাবে ব্যবহার করে, আপনি আপনার অ্যাপ্লিকেশনটির লোডিং সময় কমাতে পারেন। এবং এটি বাস্তবায়নের কোটলিন উপায় হ'ল lazy()এটির সাহায্যে যখনই আপনার ভেরিয়েবলের প্রয়োজনীয় মান লোড হয়।

তবে ল্যাটিনাইট ব্যবহার করা হয় যখন আপনি নিশ্চিত হন যে কোনও পরিবর্তনশীল নাল বা খালি হবে না এবং অ্যান্ড্রয়েডের পদ্ধতিতে -Eg ব্যবহার করার আগে এটি আরম্ভ করা onResume()হবে- এবং সুতরাং আপনি এটিকে একটি নলাবদ্ধ টাইপ হিসাবে ঘোষণা করতে চান না।


হ্যাঁ, আমি এছাড়াও সক্রিয়া onCreateView, onResumeএবং সঙ্গে অন্যান্য lateinit, কিন্তু কখনও কখনও ত্রুটি ঘটেছে (কারণ কিছু ঘটনা আগে শুরু)। সুতরাং সম্ভবত by lazyএকটি উপযুক্ত ফলাফল দিতে পারেন। আমি lateinitনন-নাল ভেরিয়েবলগুলির জন্য ব্যবহার করি যা লাইফসাইকের সময় পরিবর্তন করতে পারে।
শীতলমান্ড

2

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


0

যদি আপনি স্প্রিং পাত্রে ব্যবহার করছেন এবং আপনি অ-ননযোগ্য শিমের ক্ষেত্রটি আরম্ভ করতে চান তবে lateinitএটি আরও উপযুক্ত।

    @Autowired
    lateinit var myBean: MyBean

1
মত হওয়া উচিত@Autowired lateinit var myBean: MyBean
Cnfn

0

আপনি একটি পরিবর্তনযোগ্য নয় ভেরিয়েবল ব্যবহার ফেলেন, তাহলে এটি সঙ্গে আরম্ভ করাই ভালো by lazy { ... }বা val। এই ক্ষেত্রে আপনি নিশ্চিত হতে পারেন যে এটি সর্বদা প্রয়োজনের সময় এবং সর্বাধিক 1 সময় শুরু করা হবে।

আপনি যদি একটি নন-নাল ভেরিয়েবল চান তবে এটি এর মান, ব্যবহার পরিবর্তন করতে পারে lateinit var। Android বিকাশ আপনি পরে মতো ঘটনা এটি আরম্ভ করতে পারেন onCreate, onResume। সচেতন হোন, আপনি যদি আরআরএসটি অনুরোধটি কল করেন এবং এই ভেরিয়েবলটি অ্যাক্সেস করেন তবে এটি একটি ব্যতিক্রম হতে পারে UninitializedPropertyAccessException: lateinit property yourVariable has not been initialized, কারণ অনুরোধটি সেই পরিবর্তনশীলটি আরম্ভ করার চেয়ে দ্রুত সম্পাদন করতে পারে।

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