JavaRush /בלוג Java /Random-HE /ניתוח שאלות ותשובות מראיונות למפתח Java. חלק 16

ניתוח שאלות ותשובות מראיונות למפתח Java. חלק 16

פורסם בקבוצה
שלום חבר! כמה זמן לוקח להפוך למפתח? שאלתי הרבה אנשים שונים ושמעתי הרבה תשובות שונות. עבור אנשים מסוימים אפילו חודש עשוי להספיק, אך עבור אחרים אפילו שנה לא תספיק. אבל אני יודע בוודאות שלהיות מפתח ג'אווה זו דרך קוצנית וארוכה, ללא קשר ליכולות הראשוניות שלך. אחרי הכל, לא כל כך חשובה היכולת כמו עקשנות ועבודה קשה. ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 1לכן, היום אנו ממשיכים לנתח בכוונה את שאלות הראיונות הפופולריות ביותר עבור מפתחי Java. לימוד אותם יקרב אותך בהדרגה אל המטרה היקרה שלך. בואו נתחיל!

17. תן דוגמאות לשימוש מוצלח ולא מוצלח באופציונלי

נניח שיש לנו סדרה מסוימת של ערכים שדרכה אנו עוברים בזרם, ובסופו של דבר נקבל כמה אופציונליים כתוצאה מכך:
Optional<String> stringOptional = Stream.of("a", "ab", "abc", "abcd")
   .filter(str -> str.length() >= 3)
   .findAny();
אנחנו, כצפוי, צריכים לקבל את הערך מהאופציונלי הזה . רק שימוש ב-get() הוא דרך גרועה:
String result = stringOptional.get();
אבל השיטה הזו אמורה לקבל את הערך מ- Optional ולהחזיר לנו אותו? זה, כמובן, נכון, אבל אם יש לזה משמעות. ובכן, אם הערכים בזרם היו שונים, ובסופו של דבר קיבלנו ריק אופציונלי , כשאנחנו מנסים לקחת ממנו ערך בשיטת get() ייזרקו הדברים הבאים: ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 2וזה לא טוב. במקרה זה, עדיף להשתמש במבנים הבאים:
  1. String result = null;
    if (stringOptional.isPresent()) {
     stringOptional.get();
    }

    במקרה זה, אנו בודקים אם הרכיב נמצא ב- Optional . אם לא, למחרוזת המתקבלת יש את הערך הישן שלה.

  2. String result = stringOptional.orElse("default value");

    במקרה זה, אנו מציינים ערך ברירת מחדל כלשהו, ​​שיינתן למחרוזת המתקבלת במקרה של אופציונלי ריק .

  3. String result = stringOptional.orElseThrow(() -> new CustomException());

    במקרה זה, אנו בעצמנו זורקים חריג כאשר אופציונלי ריק .

זה יכול להיות נוח באפליקציה כאשר, למשל, נעשה שימוש בשיטת Spring JPA - findById() , המחזירה ערכים אופציונליים . במקרה זה, בשיטה זו אנו מנסים לקחת את הערך, ואם הוא לא קיים, אנו זורקים חריג Runtime כלשהו , ​​אשר מעובד ברמת הבקר באמצעות ExceptionHandler ומומר לתגובת HTTP עם הסטטוס 404 - NOT FOUND . ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 3

18. האם ניתן להכריז על שיטה עיקרית כסופית?

כן, כמובן, שום דבר לא מונע מאיתנו להכריז על השיטה main( ) כסופית . המהדר לא יפיק שגיאות. אבל כדאי לזכור שכל שיטה לאחר הכרזתה כסופית תהפוך לשיטה האחרונה - לא תידחה. אמנם, מי יגדיר מחדש את ראשי ??? ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 4

19. האם ניתן לייבא את אותה חבילה/מחלקה פעמיים? מה יכולות להיות ההשלכות?

כן אתה יכול. השלכות? יהיו לנו כמה יבוא מיותר ש-Intelijj IDEA יציג כאפור, כלומר. לא בשימוש. ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 5ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 6

20. מה זה ליהוק? מתי נוכל לקבל ClassCastException?

ליהוק, או ליהוק סוג , הוא תהליך של המרת סוג נתונים אחד לסוג נתונים אחר: ידנית (הליהקה מרומזת) או אוטומטית (הליהוק מסוג מפורש). ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 7המרה אוטומטית מתבצעת על ידי המהדר, והמרה ידנית מבוצעת על ידי המפתח. ליהוק סוג עבור פרימיטיבים ומעמדות שונה במקצת, אז נשקול אותם בנפרד. טיפוסים פרימיטיביים דוגמה ליציקה אוטומטית של טיפוסים פרימיטיביים:
int value = 17;
double convertedValue = value;
כפי שאתה יכול לראות, אין צורך במניפולציות נוספות מלבד הסימן = כאן. דוגמה ליציקה ידנית של טיפוסים פרימיטיביים:
double value = 17.89;
int convertedValue = (int)value;
במקרה זה, אנו יכולים לראות cast ידני, אשר מיושם באמצעות (int) , לפיו החלק שאחרי הפסיק יימחק וה- convertedValue יהיה בעל ערך של - 17. קרא עוד על ליהוק טיפוסים פרימיטיביים במאמר זה . ובכן, עכשיו בואו נעבור לחפצים. סוגי התייחסות עבור סוגי התייחסות, הליהוק אוטומטי אפשרי עבור כיתות צאצאות לכיתות אב. זה נקרא גם פולימורפיזם . נניח שיש לנו כיתת אריה שיורשת מכיתה חתול . במקרה זה, ההמרה האוטומטית תיראה כך:
Cat cat = new Lion();
אבל עם צוות מפורש , הכל קצת יותר מסובך, כי אין פונקציונליות לחתוך עודפים, כמו עם פרימיטיביים. ורק לעשות המרה מפורשת של הטופס:
Lion lion= (Lion)new Cat();
תקבל שגיאה: ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 8למעשה, אתה יכול להוסיף שיטות למחלקה צאצא אריה שלא היו במקור במחלקה Cat , ולאחר מכן לנסות לקרוא להן, כי סוג האובייקט שלך יהפוך לאריה . ובכן, אין בזה שום היגיון. לכן, צמצום הסוג אפשרי רק כאשר האובייקט המקורי היה מסוג אריה , אך מאוחר יותר יצוק למחלקת אב:
Lion lion = new Lion();
Cat cat = lion;
Lion newLion = (Lion)cat;
כמו כן, לאמינות רבה יותר, מומלץ לצמצם יציקה עבור אובייקטים באמצעות המבנה instanceOf :
if (cat instanceof Lion) {
 newLion = (Lion)new Cat();
}
קרא עוד על יציאות של סוג התייחסות במאמר זה .

21. מדוע מסגרות מודרניות משתמשות בעיקר בחריגים לא מסומנים?

אני חושב שהכל בגלל שטיפול בחריגים שנבדקו הוא עדיין קוד ספגטי שחוזר על עצמו בכל מקום, אבל לא באמת נחוץ בכל המקרים. ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 9במקרים כאלה, קל יותר לבצע את העיבוד בתוך המסגרת, כדי לא להעביר זאת שוב על כתפי המפתחים. כן, כמובן, עלול להיווצר מצב חירום, אבל ניתן לטפל באותם חריגים לא מסומנים בצורה נוחה יותר, מבלי להתעסק בעיבוד ב- Try-catch ובלי להעביר אותם הלאה בשיטות. זה מספיק רק להמיר את החריג לתגובת HTTP כלשהי ב- exceptionHandler .

22. מהו יבוא סטטי?

כשמשתמשים בנתונים סטטיים (שיטות, משתנים), לא ניתן ליצור את האובייקט עצמו, אלא לעשות זאת לפי שם המחלקה, אבל גם במקרה הזה אנחנו צריכים קישור למחלקה. הכל פשוט איתו: הוא מתווסף באמצעות ייבוא ​​רגיל. אבל מה אם נלך להשתמש בשיטה סטטית בלי לכתוב את שם המחלקה, כאילו זו שיטה סטטית של המחלקה הנוכחית? זה אפשרי עם יבוא סטטי! במקרה זה, עלינו לכתוב ייבוא ​​סטטי וקישור לשיטה זו. כמו זו, למשל, שיטה סטטית של המחלקה Math לחישוב ערך הקוסינוס:
import static java.lang.Math.cos;
כתוצאה מכך, אנו יכולים להשתמש בשיטה מבלי לציין את שם המחלקה:
double result = cos(60);
אנחנו יכולים גם פשוט לטעון את כל השיטות הסטטיות של מחלקה בבת אחת באמצעות ייבוא ​​סטטי:
import static java.lang.Math.*;
ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 10

23. מה הקשר בין שיטות hashCode() ל-equals()?

לפי אורקל , הכלל הוא: אם שני אובייקטים שווים (כלומר השיטה equals() מחזירה true ), עליהם להיות בעל אותו קוד hash. יחד עם זאת, אל תשכח שלשני אובייקטים שונים יכול להיות אותו קוד hash. כדי להבין מדוע equals() ו- hashCode() נדחפים תמיד בזוגות, שקול את המקרים הבאים:
  1. שתי השיטות מבוטלות.

    במקרה זה, שני אובייקטים שונים עם אותם מצבים פנימיים יחזירו equals() - true , בעוד hashCode() יחזירו שניהם את אותו מספר.

    מסתבר שהכל בסדר, כי מקיימים את הכלל.

  2. שתי השיטות אינן מבוטלות.

    במקרה זה, שני אובייקטים שונים עם אותם מצבים פנימיים יחזירו false כאשר equals() , מכיוון שההשוואה היא באמצעות הפניה דרך האופרטור == .

    שיטת hashCode() תחזיר גם ערכים שונים (סביר להניח) מכיוון שהיא מייצרת את הערך המומר של כתובת מיקום הזיכרון. אבל עבור אותו אובייקט הערך הזה יהיה זהה, בדיוק כפי ש- equals() במקרה זה יחזיר true רק כאשר ההפניות מצביעות על אותו אובייקט.

    מסתבר שבמקרה הזה הכל בסדר והכלל מתקיים.

  3. עוקף שווה() , לא נדחק hashCode() .

    במקרה זה, עבור שני אובייקטים שונים עם אותם מצבים פנימיים, equals() יחזיר true , ו- hashCode() יחזיר (ככל הנראה) ערכים שונים.

    זוהי עבירה על הכלל, ולכן לא מומלץ לעשות זאת.

  4. equals() אינו מוחלף , hashCode() מוחלף .

    במקרה זה, עבור שני אובייקטים שונים עם אותם מצבים פנימיים, equals() יחזיר false ו- hashCode() יחזיר את אותם ערכים.

    יש הפרה של הכלל, ולכן הגישה לא נכונה.

כפי שאתה יכול לראות, הכלל יכול להתבצע רק כאשר equals() ו- hashCode() נדרוסים או שניהם אינם מדרסים כלל. קרא ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 11עוד על equals() ו- hashCode() במאמר זה .

24. מתי משתמשים במחלקות BufferedInputStream ו- BufferedOutputStream?

InputStream משמש לקריאת נתונים בייט אחר בייט ממשאב כלשהו, ​​ו- OutputStream משמש לכתיבת נתונים בייט אחר בייט. אבל פעולות בייט-byte יכולות להיות מאוד לא נוחות ודורשות עיבוד נוסף (כדי לקרוא/לכתוב טקסטים כרגיל). למעשה, כדי לפשט רשומות בתים כאלה, BufferedOutputStream הוצג , ו- BufferedInputStream הוצג לקריאה . מחלקות אלו אינן אלא מאגרים שצוברים נתונים, ומאפשרים לך לעבוד עם נתונים לא בייט אחר בייט, אלא לפי חבילות נתונים שלמות (מערכים). כאשר נוצר, BufferedInputStream לוקח לבנאי שלו מופע מסוג InputStream , שממנו קוראים נתונים:
BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in);
byte[] arr = new byte[100];
bufferedInputStream.read(arr);
System.in הוא אובייקט InputStream שקורא נתונים מהמסוף. כלומר, באמצעות אובייקט BufferedInputStream זה , אנו יכולים לקרוא נתונים מה- InputStream על ידי כתיבתם למערך המועבר. מסתבר שזה סוג של מעטפת של מחלקה InputStream . מערך המערך מדוגמה זו הוא המערך שמקבל נתונים מ- BufferedInputStream . זה, בתורו, קורא נתונים מה- InputStream עם מערך אחר, אשר כברירת מחדל יש לו גודל של 2048 בתים. הדבר נכון גם לגבי BufferedOutputStream : יש להעביר מופע מהסוג OutputStream לבנאי , אליו נכתוב נתונים במערכים שלמים:
byte[] arr = "Hello world!!!".getBytes();
BufferedOutputStream bufferedInputStream = new BufferedOutputStream(System.out);
bufferedInputStream.write(arr);
bufferedInputStream.flush();
System.out הוא אובייקט OutputStream שכותב נתונים למסוף. השיטה flush() שולחת נתונים מה- BufferedOutputStream ל- OutputStream , תוך שטיפת ה-BufferedOutputStream בתהליך . ללא שיטה זו, שום דבר לא יירשם. ובדומה לדוגמא הקודמת: arr הוא המערך שממנו נכתבים נתונים ל- BufferedOutputStream . משם הם נכתבים ל- OutputStream במערך אחר, אשר כברירת מחדל יש לו גודל של 512 בתים. קרא עוד על שני השיעורים הללו במאמר .

25. מה ההבדל בין שיעורי java.util.Collection ל-java.util.Collections?

אוסף הוא ממשק שהוא ראש היררכיית האוסף. הוא מציג מחלקות המאפשרות לך ליצור, להכיל ולשנות קבוצות שלמות של אובייקטים. קיימות שיטות רבות לכך, כמו add() , remove() , contains() ואחרות. ממשקים עיקריים של מחלקת Collection :
  • קבוצה היא ממשק המתאר קבוצה המכילה אלמנטים ייחודיים לא מסודרים (לא חוזרים).

  • רשימה היא ממשק המתאר מבנה נתונים המאחסן רצף מסודר של אובייקטים. אובייקטים אלו מקבלים אינדקס (מספר) משלהם, באמצעותו ניתן ליצור איתם אינטראקציה: קח, מחק, שנה, החלף.

  • Queue הוא ממשק המתאר מבנה נתונים עם רכיבי אחסון בצורת תור העוקב אחר הכלל - FIFO - First In First Out .

ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 12קרא עוד על אוסף . Collections היא מחלקת שירות המספקת שיטות שירות רבות ושונות. לדוגמה:
  • addAll(Collection<? super T> collection, T...element) - מוסיף את האלמנטים שעברו מסוג T לאוסף .

  • copy(List<? super T> dest, List<? extends T> src) - מעתיק את כל האלמנטים מהרשימה src לרשימה ב- dest .

  • emptyList() - מחזיר רשימה ריקה.

  • max(Collection<? extends T> collection, Comparator<? super T> comp) - מחזירה את הרכיב המקסימלי של אוסף נתון לפי הסדר שצוין על ידי המשווה שצוין.

  • unmodifiableList(List<? extends T> list) - מחזיר ייצוג בלתי ניתן לשינוי של הרשימה שעברה.

ויש הרבה מאוד שיטות נוחות שונות כאלה באוספים . ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 13רשימה מלאה של שיטות אלה ניתן למצוא באתר אורקל . לא סתם אמרתי שהם נוחים. אחרי הכל, כולם סטטיים. כלומר, אתה לא צריך ליצור אובייקט של מחלקה זו בכל פעם כדי לקרוא את המתודה הדרושה עליו. אתה רק צריך להזין את שם המחלקה, לקרוא לשיטה הרצויה עליה ולהעביר את כל הארגומנטים הנדרשים. לסיכום, Collection הוא ממשק השורש של מסגרת האוספים. Collections היא מחלקה עוזרת לעיבוד נוח יותר של אובייקטים השייכים לסוג ממבנה האוספים. ובכן, זה הכל להיום. כל טוב!ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 16 - 14
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION