Views و URLها در جنگو؛ تفاوت Function-Based و Class-Based View
مرورگر یک نشانی درخواست میکند؛ جنگو باید بداند کدام کد را اجرا کند و چه پاسخی برگرداند. ویو در جنگو …
اگر در جاوا یک پیام کوتاه میسازید، عملگر جمع معمولاً خواناترین انتخاب است. اما وقتی هزاران قطعه را در حلقه کنار هم میگذارید، مسئله عوض میشود: آیا هر بار رشتهای تازه میخواهید یا یک فضای قابل تغییر برای ساخت متن؟ تفاوت String، StringBuilder و StringBuffer از همین تصمیم شروع میشود. این راهنما روی ساخت تدریجی رشته، ظرفیت، همزمانی و روش درست سنجش تمرکز دارد؛ بدون اینکه برای هر برنامه عدد سرعت یکسانی وعده بدهد.
آخرین بهروزرسانی: ۱۶ آبان ۱۴۰۵ — منابع بررسیشده در این روز: مستندات رسمی جاوا ۲۵ برای StringBuilder و StringBuffer، آموزش رسمی بافرهای رشته و توضیح بهینهسازی الحاق رشته در اوپنجیدیکی.
⚡ پاسخ کوتاه
برای متن نهایی از String استفاده کنید؛ برای ساخت تدریجی متن در یک نخ، StringBuilder معمولاً انتخاب مناسب است. StringBuffer همگامسازی داخلی دارد، اما چند فراخوانی پشت سر هم را خودبهخود به یک عملیات اتمی تبدیل نمیکند. برای عبارت کوتاه و ثابت، استفاده از + اشکالی ندارد. عملکرد را در محیط واقعی خودتان بسنجید، نه با عددهای بدون روش.
📑 فهرست مطالب
وقتی روی یک رشته عمل تغییر ظاهری انجام میدهید، محتوای همان شیء رشته عوض نمیشود؛ نتیجه میتواند رشته دیگری باشد. متغیر شما اجازه دارد به نتیجه تازه اشاره کند، اما این موضوع با تغییر خود شیء متفاوت است. برای توضیح کاملتر چرا رشتهها در جاوا غیرقابل تغییرند و مخزن ثابت رشته در جاوا را بخوانید؛ اینجا وارد جزئیات دوباره مخزن رشتهها نمیشویم.
تغییرناپذیری برای اشتراک امن محتوا و پیشبینیپذیری مفید است، اما ساخت مرحلهای متن نیاز دیگری دارد. در مثال زیر، مقدار اشارهشده توسط متغیر عوض میشود، نه محتوای رشته قبلی. اگر در هر دور حلقه، متن قبلی را به متن تازه اضافه کنید، ممکن است بارها مجبور به ساخت و کپی نتیجههای میانی شوید. اندازه ورودی و شکل کد تعیین میکند این هزینه چقدر مهم باشد.
String title = "Java";
title = title + " Strings";
// The original String object is not modified.
اگر با کلاسها و نوعها تازه آشنا شدهاید، از مقدمهای بر جاوا و نوع دادهها در جاوا شروع کنید. فهم تفاوت متغیر، مرجع و شیء کمک میکند وقتی دو متغیر به یک سازنده رشته اشاره میکنند، اثر تغییر را درست پیشبینی کنید؛ ابهام در همین نقطه منشأ بسیاری از خطاهای ساده است.
سازنده رشته یک دنباله قابل تغییر نگه میدارد. فراخوانی افزودن، محتوا را به انتهای همان سازنده اضافه میکند و معمولاً مرجع همان شیء را برمیگرداند؛ برای همین میتوان چند فراخوانی را زنجیره کرد. در پایان، با تبدیل به رشته، خروجی مناسب برای نمایش یا تحویل به بخش دیگر برنامه میگیرید. بهتر است سازنده را محلی نگه دارید و تنها نتیجه نهایی را بیرون بدهید.
StringBuilder message = new StringBuilder();
message.append("Order #").append(42).append(": ready");
String result = message.toString();
System.out.println(result);
در این مثال، عدد به نمایش متنی تبدیل میشود و نیازی به ساخت رشته واسطه با عملگر جمع درون فراخوانی نیست. نوشتن زنجیره به معنی الزام استفاده از آن برای هر جمله نیست؛ خوانایی را حفظ کنید. اگر تنها یک عبارت کوتاه دارید، تبدیل آن به چند خط سازنده ممکن است کد را پیچیده کند بدون اینکه مزیت قابلسنجشی بدهد.
افزودن به انتها، درج در موقعیت، حذف بازه و جایگزینی بازه کارهای متفاوتاند. اندیس شروع معمولاً شامل و اندیس پایان بازه حذف یا جایگزینی خارج از بازه است. قبل از تغییر، طول و قرارداد متد را بررسی کنید تا خطای خارج از محدوده نگیرید. برای کار با جستوجو یا بریدن متن، همچنان باید به قرارداد هر متد در مستندات همان نسخه رجوع کنید.
StringBuilder value = new StringBuilder("Java web");
value.insert(4, " and");
value.replace(0, 4, "Django");
value.delete(6, 10);
String snapshot = value.toString();
value.append("!");
// snapshot is an independent String value.
تبدیل به رشته یک تصویر از محتوا میدهد؛ تغییر بعدی سازنده نباید متن رشته تحویلشده را تغییر دهد. این ویژگی برای مرزبندی بخشها مفید است: داخل متد متن را بسازید و بیرون متد رشته نهایی تحویل دهید. اگر سازنده را در چند نقطه برنامه به اشتراک بگذارید، مالکیت تغییر مبهم میشود و اشکالزدایی سختتر خواهد شد.

طول، تعداد واحدهای متنی فعلاً موجود است؛ ظرفیت، فضایی است که پیش از نیاز به گسترش میتوان در آن نوشت. طبق مستندات جاوا ۲۵، سازنده بدون آرگومان با ظرفیت اولیه ۱۶ شروع میشود. ظرفیت را میتوان در سازنده تعیین کرد یا با درخواست ظرفیت بیشتر آماده کرد. ظرفیت بزرگتر به معنی طول بیشتر یا وجود نویسههای قابل مشاهده تازه نیست.
StringBuilder report = new StringBuilder(128);
report.append("ready");
System.out.println(report.length()); // 5
System.out.println(report.capacity()); // 128
اگر تخمین معقولی از خروجی دارید، ظرفیت اولیه میتواند از گسترشهای تکراری کم کند، اما عدد خیلی بزرگ هم حافظه بیدلیل نگه میدارد. ظرفیت را بر حسب نیاز واقعی انتخاب کنید، نه اینکه همیشه یک مقدار نجومی ثابت بگذارید. برای متن بسیار بزرگ، نوشتن تدریجی در خروجی ممکن است از نگه داشتن همه محتوا در یک سازنده مناسبتر باشد.
تغییر طول را با رزرو ظرفیت اشتباه نگیرید. بزرگ کردن طول با setLength میتواند واحدهای صفر به محتوا اضافه کند؛ این کار معادل رزرو فضای خالی برای بعد نیست. پاک کردن محتوا با طول صفر هم لزوماً حافظه بافر بزرگشده را آزاد نمیکند. اگر سازنده در یک شیء طولانیعمر نگهداری میشود، این تفاوت برای مصرف حافظه اهمیت پیدا میکند.
بافر رشته از نظر بسیاری از متدها شبیه سازنده رشته است، اما برای استفاده همزمان از همگامسازی داخلی بهره میبرد. این تفاوت هزینه و رفتار دارد. در کار تکنخی معمول، مستندات رسمی استفاده از سازنده رشته را ترجیح میدهند. بااینحال، نباید از این توصیه نتیجه بگیریم در هر اجرای کوچک، ترتیب زمانها حتماً یکسان یا اختلاف همیشه بزرگ است.
نکته مهمتر این است که ایمن بودن متدهای جدا، منطق چندمرحلهای شما را اتمی نمیکند. اگر ابتدا طول را بخوانید، بعد بر اساس آن تصمیم بگیرید و سپس چیزی اضافه کنید، نخ دیگر ممکن است بین این مراحل وارد شود. برای یک قاعده مشترک باید کل بخش لازم را با قفل مناسب یا معماری بدون اشتراک کنترل کنید؛ انتخاب کلاس بهتنهایی مسئله طراحی را حل نمیکند.
StringBuffer shared = new StringBuffer();
synchronized (shared) {
if (shared.length() == 0) {
shared.append("initialized");
}
}
این مثال صرفاً مرز یک بررسی و تغییر مشترک را نشان میدهد. در برنامه واقعی، همه دسترسیهای مرتبط باید از قرارداد قفل یکسان پیروی کنند. اگر تنها بخشی از کد قفل بگیرد، تضمین مدنظر شما حاصل نمیشود. اغلب ساخت متن در هر نخ بهصورت محلی و ترکیب نتیجهها پس از پایان کار، سادهتر از یک بافر مشترک پیچیده است.

| ویژگی | String | StringBuilder | StringBuffer |
|---|---|---|---|
| تغییر محتوا | تغییرناپذیر | تغییرپذیر | تغییرپذیر |
| همگامسازی داخلی | محتوا تغییر نمیکند | تضمین همگامسازی ندارد | متدهای لازم همگامسازی میشوند |
| کاربرد رایج | متن نهایی و مقادیر ثابت | ساخت تدریجی متن در محدوده یک نخ | نیاز مشخص به بافر مشترک با کنترل همزمانی |
| مقایسه محتوا | equals بر اساس محتوا | equals ارثرسیده از Object | equals ارثرسیده از Object |
| خروجی نهایی | خود رشته | toString | toString |
برای شناخت بقیه قابلیتهای رشته، کلاس String در جاوا مرجع تکمیلی است. این جدول درباره نقش کلاسهاست، نه حکم قطعی مصرف حافظه در تمام ماشینهای مجازی. جزئیات پیادهسازی، اندازه داده و بهینهسازی زمان اجرا میتوانند نتیجه عملکرد را عوض کنند؛ مستندات رابط را از مشاهده یک اجرای خاص جدا نگه دارید.
در این نسخه مقاله، نتیجه بنچمارک اجرایی ارائه نشده است؛ بنابراین عدد یا نسبت سرعت تجربی اعلام نمیکنیم. بهجای ساختن نتیجه، روش بازتولید را میآوریم تا آزمون با نسخه جیدیکی و محیط مشخص انجام شود. مثال زیر ابزار آموزشی ساده است، نه جایگزین چارچوب تخصصی بنچمارک برای تصمیم تولیدی.
برای آزمون محلی، نسخه جاوا، سیستم، اندازه ورودی، تعداد تکرار و روش گرمکردن را ثبت کنید. نتیجه هر روش باید استفاده شود تا حذف کار بیمصرف کمتر بر سنجش اثر بگذارد. چند اجرای مستقل لازم است؛ یک بار اجرا، بهخصوص پس از روشن شدن برنامه، ممکن است بیشتر هزینه شروع و کامپایل زمان اجرا را نشان دهد تا کار موردنظر شما را.
public class StringsBench {
static volatile int sink;
static String plus(int n) {
String s = "";
for (int i = 0; i < n; i++) s = s + i;
return s;
}
static String builder(int n) {
StringBuilder s = new StringBuilder();
for (int i = 0; i < n; i++) s.append(i);
return s.toString();
}
static String buffer(int n) {
StringBuffer s = new StringBuffer();
for (int i = 0; i < n; i++) s.append(i);
return s.toString();
}
public static void main(String[] args) {
int n = 2000;
System.out.println(System.getProperty("java.runtime.version"));
for (int i = 0; i < 20; i++) {
sink = plus(n).hashCode();
sink = builder(n).hashCode();
sink = buffer(n).hashCode();
}
for (int r = 0; r < 5; r++) {
long t = System.nanoTime();
String a = plus(n);
long p = System.nanoTime();
String b = builder(n);
long q = System.nanoTime();
String c = buffer(n);
long end = System.nanoTime();
if (!a.equals(b) || !a.equals(c)) throw new AssertionError();
sink = a.hashCode() ^ b.hashCode() ^ c.hashCode();
System.out.printf("plus=%d builder=%d buffer=%d ns%n",
p-t, q-p, end-q);
}
}
}
برای اجرای نمونه، فایل را با نام کلاس ذخیره و با کامپایلر نسخه نصبشده کامپایل کنید. ترتیب ثابت روشها و وجود همان فرایند، محدودیت این آزمون آموزشی است؛ برای نتیجه معتبرتر از چارچوب جیاماچ، چند فرایند مستقل و گزارش پراکندگی استفاده کنید. این کد هنوز مصرف حافظه، تعداد تخصیص یا رقابت واقعی چند نخ را اندازه نمیگیرد.
الحاق کوتاه در یک عبارت با انباشت خروجی در هر دور حلقه یکی نیست. اوپنجیدیکی در توضیح بهبود الحاق رشته، امکان انتخاب راهبرد مناسبتر توسط زمان اجرا را شرح میدهد. پس نگاه کردن به علامت جمع در کد کافی نیست تا درباره همه تخصیصها حکم بدهیم. مسئله اصلی حلقه این است که نتیجه قبلی در ساخت نتیجه بعدی شرکت میکند.
متد concat در جاوا هم نتیجه رشتهای تولید میکند؛ عوض کردن عملگر جمع با آن در حلقه، بهتنهایی الگوی ساخت مکرر رشته را حل نمیکند. از سوی دیگر، برای اتصال فهرستی از واژهها با جداکننده، روشهای آماده پیوستن رشته میتوانند خواناتر باشند. اول روشن کنید چه عملیاتی دارید، بعد ابزار متناسب را انتخاب کنید.دو سازنده با محتوای یکسان را نباید با equals مانند دو رشته مقایسه کنید؛ سازنده رشته برابری محتوایی String را پیاده نمیکند. برای مقایسه متن نهایی، تبدیل به رشته و مقایسه مناسب انجام دهید. همچنین قرار دادن شیء قابل تغییر در مجموعه مرتب یا استفاده بیدقت از آن بهعنوان کلید، میتواند با انتظار شما از هویت و ترتیب سازگار نباشد.
اندیسهای رشته و سازنده بر پایه واحدهای یوتیاف شانزدهاند؛ هر نماد قابل مشاهده الزاماً یک واحد نیست. حذف یک واحد از نمادی مثل بعضی ایموجیها ممکن است بخشی از جفت جانشین را باقی بگذارد. برای پردازش متن کاربر، بین واحد کد، نقطه کد و خوشه نوشتاری فرق بگذارید؛ برعکس کردن متن نیز معادل مرتب کردن درست متن فارسی برای نمایش نیست.
در بعضی سربارهای افزودن، مقدار تهی به متن «null» تبدیل میشود؛ این رفتار را با همه سازندهها و متدها یکی نگیرید. اگر داده ورودی اختیاری است، پیش از ساخت پیام تکلیف نبود مقدار را روشن کنید. در غیر این صورت ممکن است مشتری متنی با واژه فنی ناخواسته ببیند، در حالی که برنامه هیچ خطایی نداده است.

برای عنوان، شناسه و متن نهایی از رشته استفاده کنید. برای جمع کردن قطعهها در حلقه و محدوده یک نخ، سازنده محلی انتخاب خوبی است. اگر واقعاً بافر مشترک لازم دارید، نیاز همزمانی را کامل طراحی کنید و سپس درباره بافر رشته و قفل تصمیم بگیرید. هرجا امکان حذف اشتراک هست، آن را پیش از افزودن قفل بررسی کنید.
اگر گلوگاه هنوز اندازهگیری نشده، خوانایی و صحت را قربانی حدس سرعت نکنید. در سامانه وب، زمان پایگاه داده یا شبکه ممکن است مهمتر از ساخت یک پیام کوتاه باشد. برای بررسی معماری و اجرای پروژه، خدمات طراحی و توسعه وبسایت رادینو را ببینید؛ انتخاب یک کلاس، جای اندازهگیری عملکرد کل سامانه را نمیگیرد.
مستندات برای کاربرد تکنخی معمول، سازنده رشته را ترجیح میدهند چون همگامسازی تضمینشده ندارد. اما نسبت سرعت قطعی بدون آزمون محیط شما قابل اعلام نیست. در این مقاله عدد تجربی اجراشده نداریم و کد نمونه برای بازتولید ارائه شده است.
خیر، تضمین همگامسازی ندارد. محلی بودن هر سازنده در هر نخ اغلب راه سادهای است. اگر نمونه مشترک دارید، باید همزمانی و انتشار نتیجه را با سازوکار مناسب کنترل کنید.
خیر. طول مقدار محتوای فعلی است و ظرفیت فضای قابل استفاده پیش از گسترش. رزرو ظرفیت نباید محتوای قابل نمایش اضافه کند؛ تغییر طول میتواند روی محتوای منطقی اثر بگذارد.
برای متن نهایی، مقدار ثابت و عبارت کوتاه خوانا معمولاً کافی است. سازنده را وقتی وارد کنید که ساخت تدریجی یا ویرایش محتوا نیاز واقعی باشد، نه صرفاً برای حذف هر علامت جمع از کد.
وقتی نتیجه دور قبل دوباره در ساخت رشته تازه شرکت میکند، محتوای رو به رشد ممکن است بارها کپی شود. این الگو با یک عبارت کوتاه الحاق فرق دارد. درباره زمان واقعی و میزان اختلاف فقط پس از اجرای آزمون در نسخه و محیط خودتان قضاوت کنید.
نظرات 0
برای ارسال نظر وارد حساب کاربری شوید.
هنوز نظری ثبت نشده؛ اولین نفر باشید.