.toArray (নতুন MyClass [0]) বা .toArray (নতুন মাইক্লাস [myList.size ()])?


176

ধরে নিচ্ছি আমার একটি অ্যারেলিস্ট আছে

ArrayList<MyClass> myList;

এবং আমি অ্যারেতে কল করতে চাই, সেখানে ব্যবহার করার কোনও পারফরম্যান্স কারণ রয়েছে?

MyClass[] arr = myList.toArray(new MyClass[myList.size()]);

উপর

MyClass[] arr = myList.toArray(new MyClass[0]);

?

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

অবশ্যই, 99% ক্ষেত্রে এটি কোনওভাবেই বা অন্যভাবে কোনও পার্থক্য করে না, তবে আমি আমার স্বাভাবিক কোড এবং আমার অনুকূলিত অভ্যন্তরীণ লুপগুলির মধ্যে একটি ধারাবাহিক স্টাইল রাখতে চাই ...


6
দেখে মনে হচ্ছে প্রশ্নটি এখন পূর্বের উইজডম এর অ্যারেজ আলেকসে শিপিলিভের একটি নতুন ব্লগ পোস্টে নিষ্পত্তি হয়েছে !
glts

6
ব্লগ পোস্ট থেকে: "নীচের লাইন: টু অ্যারে (নতুন টি [0]) দ্রুত, নিরাপদ এবং চুক্তি হিসাবে পরিষ্কার পরিচ্ছন্ন বলে মনে হচ্ছে এবং তাই এখনই ডিফল্ট পছন্দ হওয়া উচিত" "
ডেভিডএস

উত্তর:


109

পাল্টা, হটস্পট 8-তে দ্রুততম সংস্করণটি হ'ল:

MyClass[] arr = myList.toArray(new MyClass[0]);

আমি jmh ব্যবহার করে একটি মাইক্রো বেঞ্চমার্ক চালিয়েছি ফলাফল এবং কোড নীচে রয়েছে, খালি অ্যারে সহ সংস্করণ ধারাবাহিকভাবে একটি প্রেসযুক্ত অ্যারে সহ সংস্করণকে ছাপিয়ে দেখায়। মনে রাখবেন যে আপনি যদি সঠিক আকারের বিদ্যমান অ্যারেটি পুনরায় ব্যবহার করতে পারেন তবে ফলাফলটি ভিন্ন হতে পারে।

বেঞ্চমার্ক ফলাফল (মাইক্রোসেকেন্ডে স্কোর, আরও ছোট = আরও ভাল):

Benchmark                      (n)  Mode  Samples    Score   Error  Units
c.a.p.SO29378922.preSize         1  avgt       30    0.025  0.001  us/op
c.a.p.SO29378922.preSize       100  avgt       30    0.155  0.004  us/op
c.a.p.SO29378922.preSize      1000  avgt       30    1.512  0.031  us/op
c.a.p.SO29378922.preSize      5000  avgt       30    6.884  0.130  us/op
c.a.p.SO29378922.preSize     10000  avgt       30   13.147  0.199  us/op
c.a.p.SO29378922.preSize    100000  avgt       30  159.977  5.292  us/op
c.a.p.SO29378922.resize          1  avgt       30    0.019  0.000  us/op
c.a.p.SO29378922.resize        100  avgt       30    0.133  0.003  us/op
c.a.p.SO29378922.resize       1000  avgt       30    1.075  0.022  us/op
c.a.p.SO29378922.resize       5000  avgt       30    5.318  0.121  us/op
c.a.p.SO29378922.resize      10000  avgt       30   10.652  0.227  us/op
c.a.p.SO29378922.resize     100000  avgt       30  139.692  8.957  us/op

রেফারেন্সের জন্য, কোড:

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
public class SO29378922 {
  @Param({"1", "100", "1000", "5000", "10000", "100000"}) int n;
  private final List<Integer> list = new ArrayList<>();
  @Setup public void populateList() {
    for (int i = 0; i < n; i++) list.add(0);
  }
  @Benchmark public Integer[] preSize() {
    return list.toArray(new Integer[n]);
  }
  @Benchmark public Integer[] resize() {
    return list.toArray(new Integer[0]);
  }
}

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


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

আমি দিমত করছি. আমি এর জন্য মাপদণ্ড দেখতে চাই MyClass[] arr = myList.stream().toArray(MyClass[]::new);... যা আমার ধারণা ধীরে ধীরে হবে। এছাড়াও, আমি অ্যারে ঘোষণার সাথে পার্থক্যের জন্য মানদণ্ডগুলি দেখতে চাই। যেমন: MyClass[] arr = new MyClass[myList.size()]; arr = myList.toArray(arr);এবং MyClass[] arr = myList.toArray(new MyClass[myList.size()]);... এর মধ্যে পার্থক্যের মতো? আমি অনুমান করি যে এই দু'টি একটি সমস্যা যা toArrayকার্যকারণের ঘটনার বাইরে । কিন্তু আরে! আমি ভাবিনি যে আমি অন্যান্য জটিল জটিলতাগুলি সম্পর্কে শিখব।
পিম্প ট্রাইজকিট

1
@ পিম্পট্রিজেকিট ঠিক পরীক্ষা করেছেন: অতিরিক্ত ভেরিয়েবল ব্যবহার করা প্রত্যাশার মতো কোনও পার্থক্য করে না, একটি স্ট্রিম ব্যবহার করতে toArrayসরাসরি কল করার জন্য %০% থেকে ১০০% বেশি সময় লাগে (আকারটি যত ছোট, আপেক্ষিকতর ওভারহেড বৃহত্তর)
অ্যাসিরিয়াস

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

2
এই একই উপসংহারটি এখানে পাওয়া গেছে: শিপিলিভ.নেট
2016

122

জাভা 5 এ অ্যারেলিস্ট হিসাবে , অ্যারেটি সঠিক আকারে (বা আরও বড়) থাকলে ইতিমধ্যে পূরণ করা হবে। অতএব

MyClass[] arr = myList.toArray(new MyClass[myList.size()]);

একটি অ্যারে অবজেক্ট তৈরি করবে, এটি পূরণ করবে এবং এটি "আরারে" ফিরিয়ে দেবে। অন্য দিকে

MyClass[] arr = myList.toArray(new MyClass[0]);

দুটি অ্যারে তৈরি করা হবে। দ্বিতীয়টি হ'ল দৈর্ঘ্য সহ মাইক্লাসের একটি অ্যারে So উত্স কোডটি যতদূর মনে করে সংকলক / জেআইটি এটিকে অনুকূলিত করতে পারে না যাতে এটি তৈরি হয় না। অতিরিক্তভাবে, শূন্য-দৈর্ঘ্যের অবজেক্টটি ব্যবহারের ফলে টু অরাই () - পদ্ধতির মধ্যে castালাই (গুলি) হয়।

অ্যারেলিস্ট.টোর অ্যারে () এর উত্স দেখুন:

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

প্রথম পদ্ধতিটি ব্যবহার করুন যাতে কেবলমাত্র একটি অবজেক্ট তৈরি হয় এবং (অন্তর্ভুক্ত তবে ব্যয়বহুল) ingsালাই এড়ানো যায়।


1
দুটি মন্তব্য, কারও আগ্রহী হতে পারে: 1) লিংকডলিস্ট.টোর অ্যারে (টি [] এ) এমনকি আরও ধীর (প্রতিবিম্ব ব্যবহার করে: অ্যারে.নেউইনস্ট্যান্স) এবং আরও জটিল; 2) অন্যদিকে, জেডিকে 7 রিলিজে, আমি এটি জানতে পেরে খুব অবাক হয়েছিলাম, যে সাধারণত বেদনাদায়ক-ধীর অ্যারে.নিউইনস্ট্যান্স স্বাভাবিক অ্যারে তৈরির চেয়ে প্রায় তত দ্রুত সম্পাদন করে !
java.is.for.desktop

1
@ কেটারিয়া আকারটি অ্যারেলিস্টের একটি ব্যক্তিগত সদস্য, **** চমক **** আকার নির্দিষ্ট করে। দেখুন ArrayList sourcecode
MyPasswordIsLasercats

3
মানদণ্ড ছাড়াই পারফরম্যান্স অনুমান করা কেবলমাত্র তুচ্ছ ক্ষেত্রে কাজ করে। প্রকৃতপক্ষে, new Myclass[0]দ্রুততর: শিপিলিভ.নেট
করোল এস

এই আর JDK6 + এর যেমন বৈধ উত্তর
Антон Антонов

28

জেটব্রেইনস ইন্টেলিজ আইডিয়া পরিদর্শন থেকে:

একটি সংগ্রহকে অ্যারেতে রূপান্তর করতে দুটি স্টাইল রয়েছে: হয় প্রাক-আকারের অ্যারে ব্যবহার করা (যেমন সি.টোআরাই (নতুন স্ট্রিং [সি। সাইজ ()]) ) অথবা খালি অ্যারে ব্যবহার করুন ( সি.আরএআরএর মতো (নতুন স্ট্রিং [ 0])

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

এই পরিদর্শনটি অভিন্ন শৈলী অনুসরণ করতে অনুমতি দেয়: হয় খালি অ্যারে (যা আধুনিক জাভাতে প্রস্তাবিত) বা প্রাক-আকারের অ্যারে (যা পুরানো জাভা সংস্করণে বা নন-হটস্পট ভিত্তিক জেভিএম দ্রুততর হতে পারে) ব্যবহার করে।


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

3
: এখানে আপনি পরীক্ষা করতে পারবেন পরিদর্শন গ্রন্থে github.com/JetBrains/intellij-community/tree/master/plugins/...
Антон Антонов


17

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


2
'খালি অ্যারে পুনরায় ব্যবহার করুন' উপস্থাপন করা, কারণ এটি পাঠযোগ্যতা এবং সম্ভাব্য পারফরম্যান্সের মধ্যে একটি সমঝোতা যা বিবেচ্য। ঘোষিত একটি যুক্তি পাস করা private static final MyClass[] EMPTY_MY_CLASS_ARRAY = new MyClass[0]প্রত্যাবর্তনের দ্বারা ফিরে আসা অ্যারেগুলি প্রতিরোধের দ্বারা প্রতিরোধ করে না, তবে প্রতিবার এটি অতিরিক্ত অ্যারে তৈরি করা বাধা দেয় না।
মাইকেল শ্যাপার

ম্যাচেল ঠিক আছে, আপনি যদি শূন্য দৈর্ঘ্যের অ্যারে ব্যবহার করেন তবে এর চারপাশের কোনও উপায় নেই: আকারটি যদি> = আসল সাইজ (জেডিকে 7) হয় তবে যা অতিমাত্রায় হবে
অ্যালেক্স

আপনি যদি "আধুনিক জেভিএমগুলি এই ক্ষেত্রে প্রতিফলিত অ্যারে নির্মাণকে অনুকূলিত করে" এর জন্য একটি প্রশংসা দিতে পারেন, আমি আনন্দের সাথে এই উত্তরটিকে উপস্থাপন করব।
টম প্যানিং

আমি এখানে শিখছি। পরিবর্তে যদি আমি ব্যবহার করি: MyClass[] arr = myList.stream().toArray(MyClass[]::new);এটি সিঙ্ক্রোনাইজড এবং সমবর্তী সংগ্রহগুলির সাহায্য বা ক্ষতি করতে পারে। এবং কেন? অনুগ্রহ.
পিম্প ট্রিজকিট

3

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

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

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


2

প্রথম কেসটি আরও দক্ষ।

কারণ এটি দ্বিতীয় ক্ষেত্রে:

MyClass[] arr = myList.toArray(new MyClass[0]);

রানটাইম আসলে একটি শূন্য অ্যারে তৈরি করে (শূন্য আকারের সাথে) এবং তারপরে টু অ্যারে পদ্ধতির ভিতরে প্রকৃত ডেটা ফিট করার জন্য আরও একটি অ্যারে তৈরি করে। এই কোডটি নিম্নলিখিত কোডটি ব্যবহার করে প্রতিবিম্বের সাহায্যে সম্পন্ন হয়েছে (jdk1.5.0_10 থেকে নেওয়া):

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        a = (T[])java.lang.reflect.Array.
    newInstance(a.getClass().getComponentType(), size);
System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

প্রথম ফর্মটি ব্যবহার করে, আপনি দ্বিতীয় অ্যারে তৈরি করা এড়াতে পারবেন এবং প্রতিবিম্ব কোডটিও এড়িয়ে চলবেন।


toArray () প্রতিবিম্ব ব্যবহার করে না। কমপক্ষে যতক্ষণ আপনি "কাস্টিং" কে প্রতিবিম্ব হিসাবে গণনা করেন না ;-)।
জর্জি 13

টু অ্যারে (টি []) করে। এটি উপযুক্ত ধরণের অ্যারে তৈরি করা দরকার। আধুনিক জেভিএমগুলি সেই ধরণের প্রতিবিম্বটি অপ-প্রতিবিম্বিত সংস্করণ হিসাবে একই গতির জন্য হতে পারে।
টম হাটিন -

আমি মনে করি এটি প্রতিবিম্ব ব্যবহার করে। JDK 1.5.0_10 নিশ্চিতভাবে কাজ করে এবং প্রতিচ্ছবি হ'ল একমাত্র উপায় যেটি টাইপ করার সময় আপনি জানেন না এমন ধরণের অ্যারে তৈরি করতে আমি জানি।
Panagiotis Korros

তারপরে সোর্স কোডের উদাহরণগুলির মধ্যে একটি তার (উপরে বা আমার একটি) পুরানো। দুঃখের বিষয়, যদিও আমি আমার জন্য একটি সঠিক উপ-সংস্করণ নম্বর পাইনি।
জর্জি 13

1
জর্জি, আপনার কোডটি জেডিকে ১.6 থেকে রয়েছে এবং আপনি যদি অ্যারেসকপিও পদ্ধতিটির বাস্তবায়ন দেখতে পান তবে আপনি দেখতে পাবেন যে প্রয়োগটি প্রতিচ্ছবি ব্যবহার করে।
Panagiotis Korros

-1

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


-2

সঠিক আকারের অ্যারের সাথে 'টু অ্যারে' ব্যবহার করা আরও ভাল সম্পাদন করবে কারণ বিকল্পটি প্রথমে শূন্য আকারের অ্যারে তৈরি করবে তারপরে সঠিক আকারের অ্যারে তৈরি করবে। তবে, আপনি যেমনটি বলেছেন ততই তুচ্ছ হওয়ার সম্ভাবনা রয়েছে।

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

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


OTOH, যদি মানটি শূন্য-দৈর্ঘ্যের অ্যারে ব্যবহার করতে হয়, তবে এমন কেসগুলি যা বোঝায় যে এই কর্মক্ষমতাটি একটি উদ্বেগ।
মাইকেল শ্যাপার

-5

পূর্ণসংখ্যার জন্য নমুনা কোড:

Integer[] arr = myList.toArray(new integer[0]);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.