جاوا میں موازنہ اور موازنہ کے بارے میں لکھنے والے صرف سست لوگ نہیں ہیں۔ میں سست نہیں ہوں، لہذا براہ کرم ایک اور وضاحت کے بارے میں پیار اور گرفت کریں۔ مجھے امید ہے کہ یہ ضرورت سے زیادہ نہیں ہوگا۔ اور ہاں، یہ مضمون اس سوال کا جواب ہے: " کیا آپ میموری سے کمپیریٹر لکھ سکتے ہیں؟ " مجھے امید ہے کہ ہر کوئی اس مضمون کو پڑھنے کے بعد میموری سے موازنہ لکھنے کے قابل ہو جائے گا۔

تعارف
جیسا کہ آپ جانتے ہیں، جاوا ایک آبجیکٹ پر مبنی زبان ہے۔ نتیجے کے طور پر، جاوا میں اشیاء کو ہیرا پھیری کرنے کا رواج ہے۔ لیکن جلد یا بدیر، آپ کو کسی خاصیت کی بنیاد پر اشیاء کا موازنہ کرنے کے کام کا سامنا کرنا پڑتا ہے۔ مثال کے طور پر : فرض کریں کہ ہمارے پاس کلاس کے ذریعہ بیان کردہ کچھ پیغام ہےMessage
:
public static class Message {
private String message;
private int id;
public Message(String message) {
this.message = message;
this.id = new Random().nextInt(1000);
}
public String getMessage() {
return message;
}
public Integer getId() {
return id;
}
public String toString() {
return "[" + id + "] " + message;
}
}
اس کلاس کو ٹیوٹوریل پوائنٹ جاوا کمپائلر
میں رکھیں ۔ درآمدی بیانات بھی شامل کرنا نہ بھولیں:
import java.util.Random;
import java.util.ArrayList;
import java.util.List;
طریقہ کار میں main
، کئی پیغامات بنائیں:
public static void main(String[] args){
List<Message> messages = new ArrayList();
messages.add(new Message("Hello, World!"));
messages.add(new Message("Hello, Sun!"));
System.out.println(messages);
}
آئیے سوچتے ہیں کہ اگر ہم ان کا موازنہ کرنا چاہیں تو کیا کریں گے؟ مثال کے طور پر، ہم شناخت کے لحاظ سے ترتیب دینا چاہتے ہیں۔ اور ترتیب بنانے کے لیے، ہمیں کسی نہ کسی طرح اشیاء کا موازنہ کرنے کی ضرورت ہے تاکہ یہ سمجھ سکیں کہ کون سی چیز پہلے آنی چاہیے (یعنی چھوٹی) اور کس کی پیروی کرنی چاہیے (یعنی بڑی)۔ آئیے java.lang.Object
جیسی کلاس سے شروعات کریں ۔ ہم جانتے ہیں کہ تمام طبقے واضح طور پر Object
کلاس کے وارث ہیں۔ اور یہ سمجھ میں آتا ہے کیونکہ یہ اس تصور کی عکاسی کرتا ہے کہ "ہر چیز ایک چیز ہے" اور تمام طبقات کے لیے مشترکہ رویہ فراہم کرتی ہے۔ یہ کلاس حکم دیتی ہے کہ ہر کلاس کے دو طریقے ہیں: → hashCode
طریقہ آبجیکٹ کی hashCode
کچھ عددی ( ) نمائندگی دیتا ہے ۔ int
اس کا کیا مطلب ہے؟ اس کا مطلب یہ ہے کہ اگر آپ کلاس کی دو مختلف مثالیں بناتے ہیں، تو ان میں مختلف hashCode
s ہونا چاہیے۔ طریقہ کار کی وضاحت اتنا ہی کہتی ہے: "جتنا معقول حد تک عملی ہے، کلاس آبجیکٹ کے ذریعہ بیان کردہ ہیش کوڈ کا طریقہ الگ الگ اشیاء کے لیے الگ الگ عدد واپس کرتا ہے"۔ دوسرے الفاظ میں، دو مختلف s کے لیے ، مختلف s instance
ہونا چاہیے ۔ hashCode
یعنی یہ طریقہ ہمارے مقابلے کے لیے موزوں نہیں ہے۔ → equals
_ طریقہ equals
سوال کا جواب دیتا ہے "کیا یہ اشیاء برابر ہیں؟" اور واپس کرتا ہے a boolean
." پہلے سے طے شدہ طور پر، اس طریقہ میں درج ذیل کوڈ ہوتا ہے:
public boolean equals(Object obj) {
return (this == obj);
}
یعنی، اگر یہ طریقہ اوور رائڈ نہیں ہے، تو یہ بنیادی طور پر کہتا ہے کہ آیا آبجیکٹ کے حوالہ جات مماثل ہیں یا نہیں۔ یہ وہ نہیں ہے جو ہم اپنے پیغامات کے لیے چاہتے ہیں، کیونکہ ہمیں میسج آئی ڈیز میں دلچسپی ہے، آبجیکٹ ریفرینسز میں نہیں۔ اور یہاں تک کہ اگر ہم equals
طریقہ کو اوور رائیڈ کرتے ہیں، تو ہم سب سے زیادہ امید کر سکتے ہیں یہ سیکھنا ہے کہ آیا وہ برابر ہیں۔ اور یہ ہمارے لیے آرڈر کا تعین کرنے کے لیے کافی نہیں ہے۔ تو پھر ہمیں کیا چاہیے؟ ہمیں کسی ایسی چیز کی ضرورت ہے جو موازنہ کرے۔ جو موازنہ کرتا ہے وہ ہے Comparator
۔ Java API
کھولیں اور Comparator
تلاش کریں ۔ java.util.Comparator
درحقیقت، ایک انٹرفیس ہے java.util.Comparator and java.util.Comparable
جیسا کہ آپ دیکھ سکتے ہیں، ایسا انٹرفیس موجود ہے۔ ایک طبقہ جو اسے نافذ کرتا ہے کہتا ہے، "میں ایک ایسا طریقہ نافذ کرتا ہوں جو اشیاء کا موازنہ کرتا ہوں۔" صرف ایک چیز جو آپ کو واقعی یاد رکھنے کی ضرورت ہے وہ ہے موازنہ کنٹریکٹ، جس کا اظہار مندرجہ ذیل ہے:
Comparator returns an int according to the following rules:
- It returns a negative int if the first object is smaller
- It returns a positive int if the first object is larger
- It returns zero if the objects are equal
اب ایک کمپیریٹر لکھتے ہیں۔ ہمیں درآمد کرنے کی ضرورت ہوگی java.util.Comparator
۔ درآمدی بیان کے بعد، main
طریقہ میں درج ذیل کو شامل کریں: Comparator<Message> comparator = new Comparator<Message>();
یقیناً، یہ کام نہیں کرے گا، کیونکہ Comparator
ایک انٹرفیس ہے۔ لہٰذا ہم {}
قوسین کے بعد گھوبگھرالی منحنی خطوط وحدانی جوڑتے ہیں۔ منحنی خطوط وحدانی کے اندر درج ذیل طریقہ لکھیں:
public int compare(Message o1, Message o2) {
return o1.getId().compareTo(o2.getId());
}
آپ کو ہجے یاد کرنے کی بھی ضرورت نہیں ہے۔ موازنہ کرنے والا وہ ہوتا ہے جو موازنہ کرتا ہے، یعنی موازنہ کرتا ہے۔ اشیاء کے رشتہ دار ترتیب کی نشاندہی کرنے کے لیے، ہم ایک واپس کرتے ہیں int
۔ یہ بنیادی طور پر ہے. اچھا اور آسان۔ جیسا کہ آپ مثال سے دیکھ سکتے ہیں، Comparator کے علاوہ، ایک اور انٹرفیس ہے — java.lang.Comparable
جو کہ ہم سے compareTo
طریقہ کو نافذ کرنے کی ضرورت ہے۔ یہ انٹرفیس کہتا ہے، "ایک کلاس جو مجھے لاگو کرتی ہے کلاس کی مثالوں کا موازنہ کرنا ممکن بناتی ہے۔" مثال کے طور پر، To Integer
کا نفاذ compare
مندرجہ ذیل ہے:
(x < y) ? -1 : ((x == y) ? 0 : 1)
جاوا 8 نے کچھ اچھی تبدیلیاں متعارف کرائی ہیں۔ اگر آپ انٹرفیس کو قریب سے دیکھیں تو Comparator
آپ کو @FunctionalInterface
اس کے اوپر تشریح نظر آئے گی۔ یہ تشریح معلومات کے مقاصد کے لیے ہے اور ہمیں بتاتی ہے کہ یہ انٹرفیس فعال ہے۔ اس کا مطلب یہ ہے کہ اس انٹرفیس میں صرف 1 تجریدی طریقہ ہے، جو بغیر کسی عمل کے ایک طریقہ ہے۔ یہ ہمیں کیا دیتا ہے؟ اب ہم کمپیریٹر کا کوڈ اس طرح لکھ سکتے ہیں:
Comparator<Message> comparator = (o1, o2) -> o1.getId().compareTo(o2.getId());
ہم متغیرات کو قوسین میں نام دیتے ہیں۔ جاوا دیکھے گا کہ چونکہ صرف ایک طریقہ ہے، اس لیے مطلوبہ تعداد اور ان پٹ پیرامیٹرز کی اقسام واضح ہیں۔ پھر ہم تیر آپریٹر کو کوڈ کے اس حصے میں منتقل کرنے کے لیے استعمال کرتے ہیں۔ مزید کیا ہے، جاوا 8 کی بدولت، اب ہمارے پاس انٹرفیس میں پہلے سے طے شدہ طریقے ہیں۔ یہ طریقے ڈیفالٹ کے طور پر ظاہر ہوتے ہیں جب ہم ایک انٹرفیس کو نافذ کرتے ہیں۔ انٹرفیس Comparator
میں کئی ہیں۔ مثال کے طور پر:
Comparator moreImportant = Comparator.reverseOrder();
Comparator lessImportant = Comparator.naturalOrder();
ایک اور طریقہ ہے جو آپ کے کوڈ کو صاف ستھرا بنا دے گا۔ اوپر کی مثال پر ایک نظر ڈالیں، جہاں ہم نے اپنے موازنہ کی تعریف کی ہے۔ یہ کیا کرتا ہے؟ یہ کافی قدیم ہے۔ یہ صرف ایک چیز لیتا ہے اور کچھ قدر نکالتا ہے جو "موازنہ" ہے۔ مثال کے طور پر، Integer
impuls comparable
، لہذا ہم میسج آئی ڈی فیلڈز کی قدروں پر compareTo آپریشن کرنے کے قابل ہیں۔ اس سادہ کمپیریٹر فنکشن کو اس طرح لکھا جا سکتا ہے:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
دوسرے لفظوں میں، ہمارے پاس ایک ہے Comparator
جو اس طرح موازنہ کرتا ہے: یہ اشیاء لیتا ہے، ان سے getId()
حاصل کرنے کے لیے طریقہ استعمال کرتا ہے Comparable
، اور پھر compareTo
موازنہ کرنے کے لیے استعمال کرتا ہے۔ اور اس سے زیادہ خوفناک تعمیرات نہیں ہیں۔ اور آخر میں، میں ایک اور خصوصیت نوٹ کرنا چاہتا ہوں۔ موازنہ کرنے والوں کو جکڑا جا سکتا ہے۔ مثال کے طور پر:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
comparator = comparator.thenComparing(obj -> obj.getMessage().length());
درخواست
موازنہ کرنے والے کا اعلان کرنا کافی منطقی نکلا، کیا آپ نہیں سوچتے؟ اب دیکھنا یہ ہے کہ اسے کیسے اور کہاں استعمال کیا جائے۔ →Collections.sort(java.util.Collections)
ہم، یقینا، اس طرح مجموعوں کو ترتیب دے سکتے ہیں۔ لیکن ہر مجموعہ نہیں، صرف فہرستیں۔ یہاں کوئی غیر معمولی بات نہیں ہے، کیونکہ فہرستیں اس قسم کے مجموعے ہیں جہاں آپ عناصر کو ان کے انڈیکس کے ذریعے رسائی حاصل کرتے ہیں۔ یہ دوسرے عنصر کو تیسرے عنصر کے ساتھ تبدیل کرنے کی اجازت دیتا ہے۔ اس لیے ترتیب دینے کا درج ذیل طریقہ صرف فہرستوں کے لیے ہے۔
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
Collections.sort(messages, comparator);
→ Arrays.sort(java.util.Arrays)
صفوں کو ترتیب دینا بھی آسان ہے۔ ایک بار پھر، اسی وجہ سے - ان کے عناصر کو انڈیکس کے ذریعے حاصل کیا جاتا ہے۔ → Descendants of java.util.SortedSet and java.util.SortedMap
آپ اسے یاد کریں گے Set
اور Map
اس ترتیب کی ضمانت نہیں دیں گے جس میں عناصر کو ذخیرہ کیا گیا ہے۔ لیکن، ہمارے پاس خصوصی نفاذ ہیں جو آرڈر کی ضمانت دیتے ہیں۔ اور اگر کسی مجموعہ کے عناصر نافذ نہیں کرتے ہیں ، تو ہم اس کے کنسٹرکٹر کو java.util.Comparable
بھیج سکتے ہیں :Comparator
Set<Message> msgSet = new TreeSet(comparator);
→ Stream API
اسٹریم API میں، جو جاوا 8 میں ظاہر ہوا، موازنہ کرنے والے آپ کو اسٹریم عناصر کے ساتھ کام کو آسان بنانے دیتے ہیں۔ مثال کے طور پر، فرض کریں کہ ہمیں 0 سے 999 تک بے ترتیب نمبروں کی ایک ترتیب درکار ہے، بشمول:
Supplier<Integer> randomizer = () -> new Random().nextInt(1000);
Stream.generate(randomizer)
.limit(10)
.sorted(Comparator.naturalOrder())
.forEach(e -> System.out.println(e));
ہم یہاں رک سکتے ہیں، لیکن اس سے بھی زیادہ دلچسپ مسائل ہیں۔ مثال کے طور پر، فرض کریں کہ آپ کو ایک تیار کرنے کی ضرورت ہے Map
، جہاں کلید ایک پیغام کی شناخت ہے۔ مزید برآں، ہم ان کلیدوں کو ترتیب دینا چاہتے ہیں، لہذا ہم درج ذیل کوڈ سے شروع کریں گے:
Map<Integer, Message> collected = Arrays.stream(messages)
.sorted(Comparator.comparing(msg -> msg.getId()))
.collect(Collectors.toMap(msg -> msg.getId(), msg -> msg));
ہم اصل میں HashMap
یہاں ایک حاصل کرتے ہیں. اور جیسا کہ ہم جانتے ہیں، یہ کسی بھی حکم کی ضمانت نہیں دیتا۔ نتیجے کے طور پر، ہمارے عناصر، جو id کے لحاظ سے ترتیب دیئے گئے تھے، اپنی ترتیب سے محروم ہو جاتے ہیں۔ اچھا نہیں. ہمیں اپنے کلکٹر کو تھوڑا سا تبدیل کرنا پڑے گا:
Map<Integer, Message> collected = Arrays.stream(messages)
.sorted(Comparator.comparing(msg -> msg.getId()))
.collect(Collectors.toMap(msg -> msg.getId(), msg -> msg, (oldValue, newValue) -> oldValue, TreeMap::new));
کوڈ تھوڑا خوفناک نظر آنے لگا ہے، لیکن اب مسئلہ صحیح طریقے سے حل ہو گیا ہے۔ یہاں مختلف گروہوں کے بارے میں مزید پڑھیں:
آپ اپنا کلیکٹر بنا سکتے ہیں۔ یہاں مزید پڑھیں: "جاوا 8 میں ایک کسٹم کلیکٹر بنانا"
۔ اور آپ یہاں بحث کو پڑھنے سے فائدہ اٹھائیں گے: "جاوا 8 لسٹ ٹو میپ ٹو اسٹریم کے ساتھ"
۔
گرنے کا جال
Comparator
اور Comparable
اچھے ہیں. لیکن ایک باریکی ہے جو آپ کو یاد رکھنی چاہیے۔ جب کوئی کلاس چھانٹتی ہے تو یہ توقع کرتی ہے کہ آپ کی کلاس کو ایک میں تبدیل کیا جا سکتا ہے Comparable
۔ اگر یہ معاملہ نہیں ہے، تو آپ کو رن ٹائم پر ایک خرابی موصول ہوگی۔ آئیے ایک مثال دیکھتے ہیں:
SortedSet<Message> msg = new TreeSet<>();
msg.add(new Message(2, "Developer".getBytes()));
ایسا لگتا ہے کہ یہاں کچھ بھی غلط نہیں ہے۔ لیکن درحقیقت، ہماری مثال میں، یہ ایک غلطی کے ساتھ ناکام ہو جائے گا: java.lang.ClassCastException: Message cannot be cast to java.lang.Comparable
اور سب اس لیے کہ اس نے عناصر کو ترتیب دینے کی کوشش کی (یہ ایک ہے SortedSet
، آخر کار)...لیکن ایسا نہیں ہو سکا۔ SortedMap
اور کے ساتھ کام کرتے وقت اسے مت بھولنا SortedSet
۔
مزید پڑھنا: |
---|
GO TO FULL VERSION