מבוא לפרויקט ענבר

1. מה זה פרויקט ענבר

Project Amber היא יוזמה נוכחית של מפתחי Java ו- OpenJDK, שמטרתה לספק כמה שינויים קטנים אך מהותיים ל- JDK כדי להפוך את תהליך הפיתוח ליותר נחמד.. זה נמשך מאז 2017 וכבר סיפק כמה שינויים ב- Java 10 ו- 11, כשאחרים אמורים להיכלל ב- Java 12 ועוד יגיעו במהדורות עתידיות.

עדכונים אלה ארוזים כולם בצורת JEPs - תכנית ההצעה של JDK.

2. עדכונים שהועברו

עד כה, Project Amber העביר בהצלחה כמה שינויים בגרסאות ה- JDK שפורסמו כעת - JEP-286 ו- JEP-323.

2.1. הסקה מסוג משתנה מקומי

ג'אווה 7 הציגה את מפעיל היהלומים כדרך להקל על העבודה עם הגנריות. משמעות התכונה הזו היא שאנחנו כבר לא צריכים לכתוב מידע גנרי מספר פעמים באותה הצהרה כאשר אנו מגדירים משתנים:

מחרוזות רשימה = ArrayList חדש (); // Java 6 List strings = new ArrayList (); // ג'אווה 7

Java 10 כללה את העבודה שהושלמה על JEP-286, מה שמאפשר לקוד ה- Java שלנו להגדיר משתנים מקומיים מבלי להזדקק לשכפל את פרטי הסוג בכל מקום שהמהדר כבר זמין. זה מכונה בקהילה הרחבה בשם var מילת מפתח ומביא פונקציונליות דומה ל- Java כפי שהיא זמינה בשפות רבות אחרות.

עם העבודה הזו, בכל פעם שאנחנו מגדירים משתנה מקומי, אנחנו יכולים להשתמש ב- var מילת מפתח במקום ההגדרה המלאה, והמהדר יעבוד באופן אוטומטי את מידע הסוג הנכון לשימוש:

מחרוזות var = ArrayList חדש ();

באמור לעיל, המשתנה מיתרים נחוש להיות מסוג רשימת מערך(), אך ללא צורך בשכפול המידע באותה שורה.

אנו יכולים להשתמש בכך בכל מקום בו אנו משתמשים במשתנים מקומיים, ללא קשר לאופן קביעת הערך. זה כולל סוגי החזרה וביטויים, כמו גם מטלות פשוטות כמו האמור לעיל.

המילה var הוא מקרה מיוחד בכך שהוא אינו מילה שמורה. במקום זאת, זה שם סוג מיוחד. המשמעות היא שאפשר להשתמש במילה לחלקים אחרים של הקוד - כולל שמות משתנים. מומלץ בחום לא לעשות זאת כדי למנוע בלבול.

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

var unknownType; // לא ניתן ערך להסיק מהסוג מ- var nullType = null; // הערך המפורש הניתן אך הוא null var lambdaType = () -> System.out.println ("Lambda"); // למבדה מבלי להגדיר את הממשק

למרות זאת, הערך יכול להיות ריק אם זה ערך החזר משיחה אחרת מכיוון שהשיחה עצמה מספקת מידע על סוג:

שם אופציונלי = Optional.empty (); var nullName = name.orElse (null);

במקרה הזה, nullName יסיק את הסוג חוּט כי זה מה סוג ההחזרה של name.orElse () הוא.

למשתנים המוגדרים בדרך זו יכולים להיות כל שינוי אחר באותו אופן כמו כל משתנה אחר - לדוגמה, מעבר, מסונכרן, ו סופי.

2.2. הסקה מסוג משתנה מקומי עבור למבדות

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

ב- Java 10, אנו יכולים להגדיר פונקציות Lambda באחת משתי דרכים - על ידי הצהרה מפורשת על הסוגים או על ידי השמטה מוחלטת:

names.stream () .filter (שם מחרוזת -> name.length ()> 5) .מפה (שם -> name.toUpperCase ());

כאן, בשורה השנייה יש הצהרת סוג מפורשת - חוּט ואילו השורה השלישית משמיטה אותה לחלוטין, והמהדר עובד על הסוג הנכון. מה שאנחנו לא יכולים לעשות זה להשתמש ב- var הקלד פה.

ג'אווה 11 מאפשרת לזה לקרותכדי שנוכל לכתוב במקום זאת:

names.stream () .filter (var שם -> name.length ()> 5) .מפה (שם var -> name.toUpperCase ());

זה עולה בקנה אחד עם השימוש ב- var הקלד במקום אחר בקוד שלנו.

Lambdas תמיד הגבילו אותנו להשתמש בשמות סוגים מלאים עבור כל פרמטר, או עבור אף אחד מהם. זה לא השתנה, ו השימוש של var חייב להיות לכל פרמטר או לאף אחד מהם:

numbers.stream () .reduce (0, (var a, var b) -> a + b); // מספרים תקפים.זרם () .פחת (0, (var a, b) -> a + b); // מספרים לא חוקיים.זרם () .פחת (0, (var a, int b) -> a + b); // לא חוקי

הנה, הדוגמה הראשונה תקפה לחלוטין - מכיוון ששני הפרמטרים של lambda משתמשים בשניהם var. השני והשלישי אינם חוקיים, מכיוון שרק פרמטר אחד משתמש var, למרות שבמקרה השלישי יש לנו גם שם סוג מפורש.

3. עדכונים קרובים

בנוסף לעדכונים שכבר קיימים ב- JDK שפורסמו, מהדורת ה- JDK 12 הקרובה כוללת עדכון אחד - JEP-325.

3.1. החלף ביטוי

JEP-325 מביא תמיכה לפשט את האופן שבו החלף הצהרות עובדות, ועל כך שאפשר להשתמש בהן כביטויים כדי לפשט עוד יותר את הקוד שעושה בהם שימוש.

נכון לעכשיו, החלף הצהרה פועלת באופן דומה מאוד לאלה בשפות כגון C או C ++. שינויים אלה הופכים אותו להרבה יותר דומה ל מתי הצהרה בקוטלין או ב התאמה הצהרה בסקאלה.

עם השינויים האלה, התחביר להגדרת משפט מתג נראה דומה לזה של למבדה, עם השימוש ב- -> סֵמֶל. זה יושב בין התאמת המקרה לקוד שיש לבצע:

מתג (חודש) {מקרה FEBRUARY -> System.out.println (28); מקרה אפריל -> System.out.println (30); מקרה JUNE -> System.out.println (30); מקרה SEPTEMBER -> System.out.println (30); מקרה NOVEMBER -> System.out.println (30); ברירת מחדל -> System.out.println (31); }

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

הצד הימני של החץ חייב להיות ביטוי, חסימה או הצהרת זריקה. כל דבר אחר הוא טעות. זה גם פותר את הבעיה של הגדרת משתנים בתוך הצהרות מתג - שיכולות להתרחש רק בתוך בלוק, מה שאומר שהם מוגדרים אוטומטית לאותו בלוק:

החלף (חודש) {case FEBRUARY -> {int days = 28; } מקרה אפריל -> {int ימים = 30; } ....}

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

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

מתג (חודש) {מקרה FEBRUARY -> System.out.println (28); מקרה אפריל, יוני, ספטמבר, נובמבר -> System.out.println (30); ברירת מחדל -> System.out.println (31); }

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

זה מאפשר את החלף ביטוי כדי לפתור לערך, ואז להשתמש בערך זה בהצהרות אחרות - למשל, מטלה:

final var days = switch (חודש) {case FEBRUARY -> 28; מקרה אפריל, יוני, ספטמבר, נובמבר -> 30; ברירת מחדל -> 31; }

הנה, אנו משתמשים ב- החלף ביטוי כדי ליצור מספר ואז אנו מקצים מספר זה ישירות למשתנה.

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

4. שינויים קרובים

עד כה, כל השינויים הללו כבר זמינים או יהיו במהדורה הקרובה. ישנם כמה שינויים המוצעים במסגרת Project Amber שעדיין לא מתוכננים לצאת.

4.1. ספרות מחרוזת גולמיות

נכון לעכשיו, לג'אווה יש בדיוק דרך אחת להגדיר מילולית מחרוזת - על ידי הקפת התוכן במרכאות כפולות. זה קל לשימוש, אך הוא סובל מבעיות במקרים מסובכים יותר.

במיוחד, קשה לכתוב מחרוזות המכילות תווים מסוימים - כולל אך לא מוגבל ל: שורות חדשות, ציטוטים כפולים ותווים נטויים לאחור. זה יכול להיות בעייתי במיוחד בנתיבי קבצים ובביטויים רגולריים שבהם תווים אלה יכולים להיות נפוצים יותר מהמקובל.

JEP-326 מציג סוג מילולי חדש של מחרוזת בשם Raw String Literals. אלה כלואים בסימני backstick במקום במרכאות כפולות ויכולים לכלול בתווים כלשהם בתוכם.

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

לדוגמה:

// נתיב מערכת הקבצים "C: \ Dev \ file.txt" `C: \ Dev \ file.txt` // Regex" \ d + \. \ d \ d "\ d + \. \ d \ d // // רב-קו "שלום \ העולם" שלום עולם`

בשלושת המקרים, קל יותר לראות מה קורה בגרסה עם התיקים, וזה גם הרבה פחות נוטה להקלדה.

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

"מחרוזת זו מאפשרת" "" יחיד מכיוון שהיא עטופה בשני תיקים "

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

4.2. שאריות למבדה

JEP-302 מציג כמה שיפורים קטנים באופן העבודה של lambdas.

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

Java 8 הציג שינוי כך ששימוש בקו תחתון כשם הוא אזהרה. ג'אווה 9 התקדמה כך להיות שגיאה במקום זאת, ומונעת מאיתנו להשתמש בהם בכלל. שינוי זה הקרוב מאפשר להם פרמטרים של lambda מבלי לגרום להתנגשויות כלשהן. זה יאפשר, למשל, את הקוד הבא:

jdbcTemplate.queryForObject ("SELECT * FROM users WHERE user_id = 1", (rs, _) -> parseUser (rs))

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

השינוי העיקרי הנוסף בשיפור זה הוא לאפשר לפרמטרים של lambda להצליל על שמות מההקשר הנוכחי. כרגע זה לא מותר, מה שעלול לגרום לנו לכתוב קוד פחות מהאידיאלי. לדוגמה:

מפתח מחרוזת = computeSomeKey (); map.computeIfAbsent (key, key2 -> key2.length ());

אין צורך אמיתי, מלבד המהדר, מדוע מַפְתֵחַ ו מקש 2 לא יכול לחלוק שם. למבדה לעולם לא צריך להתייחס למשתנה מַפְתֵחַ, ואילוץ עלינו לעשות זאת הופך את הקוד למכוער יותר.

במקום זאת, שיפור זה מאפשר לנו לכתוב אותו בצורה ברורה ופשוטה יותר:

מפתח מחרוזת = computeSomeKey (); map.computeIfAbsent (מפתח, מפתח -> key.length ());

בנוסף, יש שינוי המוצע בשיפור זה שיכול להשפיע על רזולוציית עומס יתר כאשר לשיטה עמוסת יתר יש טיעון למבדה. נכון לעכשיו, ישנם מקרים בהם הדבר עלול להוביל לאי-בהירות בשל הכללים לפיהם פועלת רזולוציית עומס יתר, ו- JEP זה עשוי להתאים מעט את הכללים הללו כדי למנוע חלק מהעמימות.

לדוגמה, נכון לעכשיו, המהדר רואה את השיטות הבאות כמשמעותיות:

m (Predicate ps) {...} m (פונקציה fss) {...}

שתי השיטות הללו לוקחות למבדה שיש לה יחיד חוּט פרמטר ויש לו סוג החזרה שאינו ריק. ברור למפתח שהם שונים - אחד מחזיר א חוּטוהשני, א בוליאני, אך המהדר יתייחס לאלה כאל מעורפל.

JEP זה עשוי לטפל בחסר זה ולאפשר טיפול במפורש בעומס יתר זה.

4.3. התאמת תבנית

JEP-305 מציג שיפורים בדרך שנוכל לעבוד עם ה- מופע של מפעיל וכפיית סוג אוטומטית.

נכון לעכשיו, כאשר משווים סוגים בג'אווה, עלינו להשתמש ב- מופע של אופרטור כדי לראות אם הערך הוא מהסוג הנכון, ואז אחר כך, עלינו לזרוק את הערך לסוג הנכון:

if (obj instanceof String) {String s = (String) obj; // השתמש ב- s}

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

שיפור זה מבצע התאמה דומה ל- מופע של כפי שהיה בעבר תחת נסה עם משאבים בג'אווה 7. עם שינוי זה, ההשוואה, ההרכב וההצהרה המשתנה הופכים להצהרה אחת במקום:

if (obj instanceof String s) {// use s}

זה נותן לנו הצהרה אחת, ללא כפילות וללא סיכון להתגנבות שגיאות, ובכל זאת מבצע את אותו הדבר כמו האמור לעיל.

פעולה זו תפעל גם כראוי בין הענפים, ותאפשר לפעולות הבאות:

אם (obj instanceof String s) {// יכול להשתמש ב- s כאן} אחרת {// לא יכול להשתמש ב- s}}

השיפור יעבוד גם כראוי על גבולות היקף שונים לפי הצורך. המשתנה שהוכרז על ידי מופע של סעיף יציל כהלכה משתנים שהוגדרו מחוצה לו, כצפוי. זה יקרה רק בבלוק המתאים, אם כי:

מחרוזת s = "שלום"; if (obj instanceof String s) {// s מתייחס ל- obj} אחר {// s מתייחס למשתנה שהוגדר לפני הצהרת if}

זה עובד גם בתוך אותו דבר אם סָעִיף, באותו אופן שאנחנו מסתמכים עליו ריק צ'קים:

אם (obj instanceof String s && s.length ()> 5) {// s הוא מחרוזת של יותר מ -5 תווים}

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

4.4. גופי שיטה תמציתית

טיוטת JEP 8209434 היא הצעה לתמיכה בהגדרות שיטות פשוטות, באופן הדומה לאופן שבו הגדרות למבדה עובדות.

כרגע אנו יכולים להגדיר למבדה בשלוש דרכים שונות: עם גוף, כביטוי יחיד, או כהפניה לשיטה:

ToIntFunction lenFn = (String s) -> {return s.length (); }; ToIntFunction lenFn = (מחרוזת s) -> s.length (); ToIntFunction lenFn = מחרוזת :: אורך;

למרות זאת, כשמדובר בכתיבה של גופי שיטות כיתה בפועל, עלינו כרגע לכתוב אותם במלואם.

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

לדוגמא, שיטת גטר אינה זקוקה לגוף שיטה מלא, אך ניתן להחליפה בביטוי יחיד:

מחרוזת getName () -> שם;

באותה מידה, אנו יכולים להחליף שיטות שהן פשוט עוטפות שיטות אחרות בשיחת הפניה לשיטה, כולל העברת פרמטרים על פני:

אורך int (מחרוזת s) = מחרוזת :: אורך

אלה יאפשרו שיטות פשוטות יותר במקרים בהם הם הגיוניים, כלומר, הסיכוי שלהם פחות לטשטש את ההיגיון העסקי האמיתי בשאר הכיתות.

שים לב כי זה עדיין במצב טיוטה וככזה, הוא נתון לשינויים משמעותיים לפני המסירה.

5. Enums משופרת

JEP-301 תוכנן בעבר להיות חלק מ- Project Amber. זה היה מביא לשיפורים מסוימים באנומות, מה שמאפשר במפורש לאלמנטים בודדים של אנום לקבל מידע כללי מובהק.

לדוגמה, זה יאפשר:

enum פרימיטיבי {INT (Integer.class, 0) {int mod (int x, int y) {return x% y; } int להוסיף (int x, int y) {להחזיר x + y; }}, FLOAT (Float.class, 0f) {long add (long x, long y) {return x + y; }}, ...; תיבת הכיתה הסופית Class; סופי X defaultValue; פרימיטיבי (Class boxClass, X defaultValue) {this.boxClass = boxClass; this.defaultValue = defaultValue; }}

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

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

6. סיכום

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


$config[zx-auto] not found$config[zx-overlay] not found