שאלות ראשונות 50 בראיונות תכנות ב-Java

הקדמה

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

1. איך אפשר להפוך מחרוזת ב-Java?

אין שיטת יישום reverse() במחלקת String. אך ניתן ליצור מערך תווים מהמחרוזת ולעבור עליו מהסוף אל ההתחלה. ניתן להוסיף את התווים לבניית מחרוזת ולהחזיר את המחרוזת ההפוכה לבסופו.

הקוד בדוגמה הבאה מציג דרך אחת להפיכת מחרוזת:

public class StringPrograms {

	public static void main(String[] args) {
		String str = "123";

		System.out.println(reverse(str));
	}

	public static String reverse(String in) {
		if (in == null)
			throw new IllegalArgumentException("Null is not valid input");

		StringBuilder out = new StringBuilder();

		char[] chars = in.toCharArray();

		for (int i = chars.length - 1; i >= 0; i--)
			out.append(chars[i]);

		return out.toString();
	}

}

ניתן לקבל נקודות נוספות על ידי הוספת בדיקת null בשיטה ושימוש ב־StringBuilder להוספת התווים. שים לב שהמספור ב-Java מתחיל מ־0, לכן עליך להתחיל ב־chars.length - 1 בלולאת for.

2. איך להחליף שני מספרים בלי שימוש במשתנה שלישי ב-Java?

החלפת מספרים בלי שימוש במשתנה שלישי היא תהליך של שלושה צעדים שניתן להמחיש בקוד:

b = b + a; // now b is sum of both the numbers
a = b - a; // b - a = (b + a) - a = b (a is swapped)
b = b - a; // (b + a) - b = a (b is swapped)

הקוד הדוגמא הבא מציג אחת מהדרכים ליישם את שיטת ההחלפה של מספרים:

public class SwapNumbers {

public static void main(String[] args) {
	int a = 10;
	int b = 20;

    System.out.println("a is " + a + " and b is " + b);

	a = a + b;
	b = a - b;
	a = a - b;

    System.out.println("After swapping, a is " + a + " and b is " + b);
    }

}

הפלט מראה שערכי המספרים מוחלפים:

Output
a is 10 and b is 20 After swapping, a is 20 and b is 10

3. כתוב תוכנית Java כדי לבדוק האם תו ניקוד נמצא במחרוזת.

הקוד הדוגמא הבא מראה כיצד להשתמש בביטוי רגולרי כדי לבדוק האם המחרוזת מכילה תווים ניקוד:

public class StringContainsVowels {

	public static void main(String[] args) {
		System.out.println(stringContainsVowels("Hello")); // true
		System.out.println(stringContainsVowels("TV")); // false
	}

	public static boolean stringContainsVowels(String input) {
		return input.toLowerCase().matches(".*[aeiou].*");
	}

}

4. כתוב תוכנית Java כדי לבדוק האם המספר הנתון הוא מספר ראשי.

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

public class PrimeNumberCheck {

	public static void main(String[] args) {
		System.out.println(isPrime(19)); // אמת
		System.out.println(isPrime(49)); // שקר
	}

	public static boolean isPrime(int n) {
		if (n == 0 || n == 1) {
			return false;
		}
		if (n == 2) {
			return true;
		}
		for (int i = 2; i <= n / 2; i++) {
			if (n % i == 0) {
				return false;
			}
		}

		return true;
	}

}

עם זאת, התוכנית הזו אינה יעילה בזמן ובזיכרון. שים לב שלמספר נתון N, אם יש מספר ראשוני M בין 2 ל- √N (שורש ריבועי של N) שמחלק אותו באופן שווה, אז N אינו מספר ראשוני.

5. כתוב תוכנית ב-Java להדפסת סדרת פיבונצ'י באמצעות רקורסיה.

A Fibonacci sequence is one in which each number is the sum of the two previous numbers. In this example, the sequence begins with 0 and 1. The following example code shows how to use a for loop to print a Fibonacci sequence:

public class PrintFibonacci {

	public static void printFibonacciSequence(int count) {
		int a = 0;
		int b = 1;
		int c = 1;

		for (int i = 1; i <= count; i++) {
			System.out.print(a + ", ");

            a = b;
			b = c;
			c = a + b;
		}
	}

	public static void main(String[] args) {
    	printFibonacciSequence(10);
	}

}
Output
0, 1, 1, 2, 3, 5, 8, 13, 21, 34,

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

F(N) = F(N-1) + F(N-2)

הקוד הדוגמא הבא מראה כיצד להשתמש ברקורסיה לחישוב סדרת פיבונצ'י של 10 מספרים:

public class PrintFibonacciRecursive {

    public static int fibonacci(int count) {
		if (count <= 1)
			return count;

		return fibonacci(count - 1) + fibonacci(count - 2);
	}

	public static void main(String args[]) {
    	int seqLength = 10;

    	System.out.print("A Fibonacci sequence of " + seqLength + " numbers: ");

    	for (int i = 0; i < seqLength; i++) {
      	    System.out.print(fibonacci(i) + " ");
    	}
  	}

}
Output
A Fibonacci sequence of 10 numbers: 0 1 1 2 3 5 8 13 21 34

6. כיצד לבדוק אם רשימת מספרים מכילה רק מספרים אי-זוגיים ב-Java?

ניתן להשתמש בלולאת for ולבדוק האם כל איבר הוא אי-זוגי:

public static boolean onlyOddNumbers(List<Integer> list) {
	for (int i : list) {
		if (i % 2 == 0)
			return false;
	}

	return true;
}

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

public static boolean onlyOddNumbers(List<Integer> list) {
	return list
			.parallelStream() // זרם מקבילי לעיבוד מהיר יותר
			.anyMatch(x -> x % 2 != 0); // מחזיר מיד כאשר ישנם איברים שמקיימים את התנאי
}

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

7. כיצד לבדוק האם מחרוזת היא פלינדרום ב-Java?

A palindrome string is the same string backwards or forwards. To check for a palindrome, you can reverse the input string and check if the result is equal to the input. The following example code shows how to use the String charAt(int index) method to check for palindrome strings:

boolean checkPalindromeString(String input) {
	boolean result = true;
	int length = input.length();

	for (int i = 0; i < length/2; i++) {
		if (input.charAt(i) != input.charAt(length - i - 1)) {
			result = false;
			break;
		}
	}

	return result;
}

8. כיצד להסיר רווחים ממחרוזת ב-Java?

הקוד הבא מציג אופן אחד להסרת רווחים ממחרוזת באמצעות השימוש בשיטת Character.isWhitespace():

String removeWhiteSpaces(String input) {
	StringBuilder output = new StringBuilder();
	
	char[] charArray = input.toCharArray();
	
	for (char c : charArray) {
		if (!Character.isWhitespace(c))
			output.append(c);
	}
	
	return output.toString();
}

למד עוד על הסרת רווחים ותווים אחרים ממחרוזת ב-Java.

9. כיצד להסיר רווחים מראש ומסוף מחרוזת ב-Java?

המחלקה String מכילה שתי שיטות להסרת רווחים מראש ומסוף: trim() ו־strip(). שיטת strip() נוספה למחלקת String ב-Java 11. השיטה strip() משתמשת בשיטת Character.isWhitespace() כדי לבדוק אם התו הוא רווח. שיטה זו משתמשת בנקודות קוד יוניקוד, בעוד שהשיטה trim() מזהה כל תו עם ערך קוד פחות או שווה ל־U+0020 כתו רווח.

שימוש בשיטת strip() הוא הדרך המומלצת להסרת רווחים מאחר והיא משתמשת בתקן יוניקוד. הקוד הבא מציג איך להשתמש בשיטת strip() כדי להסיר רווחים:

String s = "  abc  def\t";
		
s = s.strip();
		
System.out.println(s);

מכיוון שמחרוזת היא לא ניתנת לשינוי, עליך להקצות את פלט strip() למחרוזת.

10. איך ממיין תחום בשפת ג'אווה?

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

int[] array = {1, 2, 3, -1, -2, 4};

Arrays.sort(array);

System.out.println(Arrays.toString(array));

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

11. איך יוצרים סצנריו למצב קריטי באמצעות ג'אווה?

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

public class ThreadDeadlock {

    public static void main(String[] args) throws InterruptedException {
        Object obj1 = new Object();
        Object obj2 = new Object();
        Object obj3 = new Object();
    
        Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1");
        Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2");
        Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3");
        
        t1.start();
        Thread.sleep(5000);
        t2.start();
        Thread.sleep(5000);
        t3.start();        
    }

}

class SyncThread implements Runnable {

    private Object obj1;
    private Object obj2;

    public SyncThread(Object o1, Object o2) {
        this.obj1 = o1;
        this.obj2 = o2;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();

        System.out.println(name + " acquiring lock on " + obj1);
        synchronized (obj1) {
            System.out.println(name + " acquired lock on " + obj1);
            work();
            System.out.println(name + " acquiring lock on " + obj2);
            synchronized (obj2) {
                System.out.println(name + " acquired lock on " + obj2);
                work();
            }
            System.out.println(name + " released lock on " + obj2);
        }
        System.out.println(name + " released lock on " + obj1);
        System.out.println(name + " finished execution.");
    }

    private void work() {
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

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

12. כיצד ניתן למצוא את גורם ההכפלה של מספר שלם ב-Java?

גורם ההכפלה של מספר שלם מחושב על ידי הכפלת כל המספרים מ-1 ועד המספר שניתן:

F(n) = F(1)*F(2)...F(n-1)*F(n)

הקוד בדוגמה הבאה מציג כיצד להשתמש ברקורסיה כדי למצוא את גורם ההכפלה של מספר שלם:

public static long factorial(long n) {
	if (n == 1)
		return 1;
	else
		return (n * factorial(n - 1));
}

13. כיצד ניתן להפוך רשימת קישורים לרשימה בסדר הפוך ב-Java?

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

LinkedList<Integer> ll = new LinkedList<>();

ll.add(1);
ll.add(2);
ll.add(3);

System.out.println(ll);

LinkedList<Integer> ll1 = new LinkedList<>();

ll.descendingIterator().forEachRemaining(ll1::add);

System.out.println(ll1);

למד עוד על היפוך רשימה מקושרת מנקודת מבט מבניות הנתונים והאלגוריתמים.

14. איך לממש חיפוש דו מחרוזתי בשפת ג'אווה?

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

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

הקוד המוצג להלן מממש חיפוש דו מחרוזתי:

public static int binarySearch(int arr[], int low, int high, int key) {
	int mid = (low + high) / 2;

	while (low <= high) {
		if (arr[mid] < key) {
			low = mid + 1;
		} else if (arr[mid] == key) {
			return mid;
		} else {
			high = mid - 1;
		}
		mid = (low + high) / 2;
	}

	if (low > high) {
		return -1;
	}

	return -1;
}

15. כתוב תוכנית בשפת ג'אווה שממחישה מיון מיזוג.

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

public class MergeSort {

	public static void main(String[] args) {
		int[] arr = { 70, 50, 30, 10, 20, 40, 60 };

		int[] merged = mergeSort(arr, 0, arr.length - 1);

		for (int val : merged) {
			System.out.print(val + " ");
		}
	}

	public static int[] mergeTwoSortedArrays(int[] one, int[] two) {
		int[] sorted = new int[one.length + two.length];

		int i = 0;
		int j = 0;
		int k = 0;

		while (i < one.length && j < two.length) {
			if (one[i] < two[j]) {
				sorted[k] = one[i];
				k++;
				i++;
			} else {
				sorted[k] = two[j];
				k++;
				j++;
			}
		}

		if (i == one.length) {
			while (j < two.length) {
				sorted[k] = two[j];
				k++;
				j++;
			}
		}

		if (j == two.length) {
			while (i < one.length) {
				sorted[k] = one[i];
				k++;
				i++;
			}
		}

		return sorted;
	}

	public static int[] mergeSort(int[] arr, int lo, int hi) {
		if (lo == hi) {
			int[] br = new int[1];
			br[0] = arr[lo];

			return br;
		}

		int mid = (lo + hi) / 2;

		int[] fh = mergeSort(arr, lo, mid);
		int[] sh = mergeSort(arr, mid + 1, hi);

		int[] merged = mergeTwoSortedArrays(fh, sh);

		return merged;
	}

}

16. האם תוכל ליצור פירמידה של תווים ב-Java?

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

17. כתוב תוכנית Java שבודקת האם שני מערכים מכילים את אותם איברים.

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

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class ArraySameElements {

	public static void main(String[] args) {
		Integer[] a1 = {1,2,3,2,1};
		Integer[] a2 = {1,2,3};
		Integer[] a3 = {1,2,3,4};
		
		System.out.println(sameElements(a1, a2));
		System.out.println(sameElements(a1, a3));
	}

	static boolean sameElements(Object[] array1, Object[] array2) {
		Set<Object> uniqueElements1 = new HashSet<>(Arrays.asList(array1));
		Set<Object> uniqueElements2 = new HashSet<>(Arrays.asList(array2));
		
		// אם הגודל שונה, יש אי התאמה
		if (uniqueElements1.size() != uniqueElements2.size()) return false;
		
		for (Object obj : uniqueElements1) {
			// האיבר אינו נמצא בשני הסטים?
			if (!uniqueElements2.contains(obj)) return false;
		}
		
		return true;
	}

}
Output
true false

18. איך ניתן לקבל את סכום כל האיברים במערך של מספרים שלמים בשפת ג'אווה?

ניתן להשתמש בלולאת for לעבור על איברי המערך ולחבר אותם כדי לקבל את הסכום הסופי:

int[] array = { 1, 2, 3, 4, 5 };

int sum = 0;

for (int i : array)
	sum += i;

System.out.println(sum);

19. איך ניתן למצוא את המספר השני הגדול ביותר במערך בשפת ג'אווה?

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

private static int findSecondHighest(int[] array) {
	int highest = Integer.MIN_VALUE;
	int secondHighest = Integer.MIN_VALUE;

	for (int i : array) {
		if (i > highest) {
			secondHighest = highest;
			highest = i;
		} else if (i > secondHighest) {
			secondHighest = i;
		}

	}
	return secondHighest;
}

20. איך מערבבים מערך בג'אווה?

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

int[] array = { 1, 2, 3, 4, 5, 6, 7 };

Random rand = new Random();

for (int i = 0; i < array.length; i++) {
	int randomIndexToSwap = rand.nextInt(array.length);
	int temp = array[randomIndexToSwap];
	array[randomIndexToSwap] = array[i];
	array[i] = temp;
}

System.out.println(Arrays.toString(array));

ניתן להריץ את קוד הערבוב בתוך לולאת for נוספת כדי לערבב מספר סיבובים.

21. איך אפשר למצוא מחרוזת בקובץ טקסט בג'אווה?

הדוגמה הבאה מראה איך להשתמש במחלקת Scanner כדי לקרוא את תוכן הקובץ שורה אחר שורה ואז להשתמש בשיטת String contains() כדי לבדוק אם המחרוזת נמצאת בקובץ:

boolean findStringInFile(String filePath, String str) throws FileNotFoundException {
	File file = new File(filePath);

	Scanner scanner = new Scanner(file);

	// קריאת הקובץ שורה אחר שורה
	while (scanner.hasNextLine()) {
		String line = scanner.nextLine();
		if (line.contains(str)) {
			scanner.close();
			return true;
		}
	}
	scanner.close();

	return false;
}

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

22. איך מדפיסים תאריך בפורמט מסוים בג'אווה?

הקוד לדוגמה הבא מראה כיצד להשתמש במחלקת SimpleDateFormat כדי לעצב מחדש את מחרוזת התאריך:

String pattern = "MM-dd-yyyy";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);

String date = simpleDateFormat.format(new Date());
System.out.println(date); // 06-23-2020

למידע נוסף על Java SimpleDateFormat.

23. איך למזג שני רשימות ב-Java?

הקוד לדוגמה הבא מראה כיצד להשתמש בשיטת addAll() כדי למזג מספר רב של רשימות ב-Java:

List<String> list1 = new ArrayList<>();
list1.add("1");
List<String> list2 = new ArrayList<>();
list2.add("2");

List<String> mergedList = new ArrayList<>(list1);
mergedList.addAll(list2);
System.out.println(mergedList); // [1, 2]

24. כתוב תוכנית Java שממיינת HashMap לפי ערך.

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class SortHashMapByValue {

	public static void main(String[] args) {
		Map<String, Integer> scores = new HashMap<>();

		scores.put("David", 95);
		scores.put("Jane", 80);
		scores.put("Mary", 97);
		scores.put("Lisa", 78);
		scores.put("Dino", 65);

		System.out.println(scores);

		scores = sortByValue(scores);

		System.out.println(scores);
	}

	private static Map<String, Integer> sortByValue(Map<String, Integer> scores) {
		Map<String, Integer> sortedByValue = new LinkedHashMap<>();

		// קבל את ערכי הכניסה
		Set<Entry<String, Integer>> entrySet = scores.entrySet();
		System.out.println(entrySet);

		// צור רשימה מאחר והסט אינו מסודר
		List<Entry<String, Integer>> entryList = new ArrayList<>(entrySet);
		System.out.println(entryList);

		// מיין את הרשימה לפי הערך
		entryList.sort((x, y) -> x.getValue().compareTo(y.getValue()));
		System.out.println(entryList);

		// מלא את המפת הגיבוב החדשה
		for (Entry<String, Integer> e : entryList)
			sortedByValue.put(e.getKey(), e.getValue());

		return sortedByValue;
	}

}

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

מחלקת String אין בה שיטה להסיר תווים. הדוגמה הבאה מראה כיצד להשתמש בשיטת replace() כדי ליצור מחרוזת חדשה בלי התו הנתון:

String str1 = "abcdABCDabcdABCD";
		
str1 = str1.replace("a", ""); 

System.out.println(str1); // bcdABCDbcdABCD

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

26. כיצד ניתן לקבל תווים שונים ומספרם במחרוזת ב־Java?

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

String str1 = "abcdABCDabcd";

char[] chars = str1.toCharArray();

Map<Character, Integer> charsCount = new HashMap<>();

for (char c : chars) {
	if (charsCount.containsKey(c)) {
		charsCount.put(c, charsCount.get(c) + 1);
	} else
		charsCount.put(c, 1);
}

System.out.println(charsCount); // {a=2, A=1, b=2, B=1, c=2, C=1, d=2, D=1}

27. האם ניתן להוכיח כי אובייקט מסוג String ב־Java הוא לא משתנה באמצעות תכנות?

הקטע הבא מציג כיצד להוכיח שאובייקט מסוג String הוא לא משתנה וההערות בקוד מסבירות כל שלב:

String s1 = "Java"; // מחרוזת "Java" נוצרה בבריכה והתייחסות שווה ניתנה ל-s1

String s2 = s1; // s2 גם כן מתייחסת למחרוזת "Java" בבריכה

System.out.println(s1 == s2); // הוכחה כי s1 ו-s2 מצביעות על אותו התייחסות

s1 = "Python"; 
// ערך ה-s1 השתנה למעלה, אז איך String היא לא נעלמה?

// במקרה לעיל נוצרה מחרוזת חדשה "Python" בבריכה
// s1 מפנה כעת למחרוזת החדשה בבריכה
// אך, המחרוזת המקורית "Java" עדיין לא שונתה ונשארת בבריכה
// s2 עדיין מציינת את המחרוזת המקורית "Java" בבריכה

// הוכחה כי s1 ו-s2 מצביעות על התייחסויות שונות
System.out.println(s1 == s2); 

System.out.println(s2); 
// מדפיס "Java" תומך בעובדה שערך המחרוזת המקורי לא השתנה, לכן String היא לא ניתנת לשינוי

28. האם תוכל לכתוב קוד להדגמת ירושה ב-Java?

הקוד לדוגמה הבא מראה כיצד להשתמש במילת המפתח extends כדי ליצור תת-מחלקה של המחלקה Animal. המחלקה החדשה Cat מורישה את המשתנה מהמחלקה Animal ומוסיפה קוד נוסף ששייך רק למחלקה Cat.

class Animal {
	String color;
}

class Cat extends Animal {
	void meow() {
		System.out.println("Meow");
	}
}

29. איך מראים בעיה של יהלומית עם יירוש מרובה ב-Java?

הבעיה של היהלומית מתרחשת כאשר מחלקה מירשת ממחלקות מרובות ואי ודאות מתרחשת כאשר לא ברור איזה שיטה להריץ מאיזו מחלקה. Java לא מאפשרת להרחיב מחלקות מרובות כדי למנוע את בעית היהלומית שמודגמת בדוגמה הבאה:

interface I {
	void foo();
}
class A implements I {
	public void foo() {}
}

class B implements I {
	public void foo() {}
}

class C extends A, B { // לא יידרוס
	public void bar() {
		super.foo();
	}
}

30. איך מייצגים דוגמה של try catch ב-Java?

הקוד לדוגמה הבא מציג דוגמה של try-catch:

try {
	FileInputStream fis = new FileInputStream("test.txt");
} catch(FileNotFoundException e) {
	e.printStackTrace();
}

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

public static void foo(int x) throws IllegalArgumentException, NullPointerException {
	// קוד מסוים
}

public static void main(String[] args) {
	try {
		foo(10);
	} catch (IllegalArgumentException | NullPointerException e) {
		System.out.println(e.getMessage());
	}
}

31. כתוב תוכנית Java להצגת NullPointerException.

אם אתה קורא לפונקציה על null, היא תזרוק NullPointerException, כפי שמוצג בדוגמה הבאה:

public static void main(String[] args) {
	printString(null, 3);
	
}

static void printString(String s, int count) {
	for (int i = 0; i < count; i++) {
		System.out.println(s.toUpperCase()); // חריגה בנושא "main" java.lang.NullPointerException
	}
}

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

static void printString(String s, int count) {
	if (s == null) return;
	for (int i = 0; i < count; i++) {
		System.out.println(s.toUpperCase());
	}
}

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

32. איך ליצור רשומה ב-Java?

רשומות נוספו כתכונה סטנדרטית ב-Java 16. רשומות מאפשרות לך ליצור מחלקת POJO עם קוד מינימלי. רשומות יוצרות באופן אוטומטי את הקוד של hashCode(), equals(), שיטות ה- getter, ושיטת ה- toString() עבור המחלקה. רשומות הן סופיות ומרחיבות באופן משולב את המחלקה java.lang.Record. הקוד בדוגמה הבאה מציג דרך אחת ליצירת רשומה:

import java.util.Map;
 
public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
}

מידע נוסף על רשומות ב-Java. לפרטים נוספים אודות POJO, יש להסתכל ב-Plain old Java object בוויקיפדיה.

33. איך ניתן ליצור בלוקי טקסט ב-Java?

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

String textBlock = """
		Hi
		Hello
		Yes""";

זה זהה ליצירת מחרוזת, כמו למשל Hi\\nHello\\nYes.

34. תציג דוגמה לביטויי switch ולהצהרות case ב-Java.

הביטויים switch הוספו כתכונה סטנדרטית ב-Java 14. הדוגמאות הבאות מציגות ביטויי switch והצהרות case רב-תוויות:

int choice = 2;

int x = switch (choice) {
    case 1, 2, 3:
	    yield choice;
    default:
	    yield -1;
};

System.out.println("x = " + x); // x = 2

ניתן גם להשתמש בביטויי למבדה בתוך ביטויי switch.

String day = "TH";
String result = switch (day) {
    case "M", "W", "F" -> "MWF";
    case "T", "TH", "S" -> "TTS";

    default -> {
	    if (day.isEmpty())
		    yield "Please insert a valid day.";
	    else
		    yield "Looks like a Sunday.";
    }
};

System.out.println(result); // TTH

35. איך ניתן להדר ולהריץ קובץ Java מהשורת פקודה?

דוגמה זו מתייחסת לקובץ Java הבא:

public class Test {

public static void main(String args[]) {
		System.out.println("Hi");
	}

}

ניתן להדר אותו באמצעות הפקודה הבאה בטרמינל שלך:

  1. javac Test.java

כדי להריץ את המחלקה, השתמש בפקודה הבאה בטרמינל שלך:

  1. java Test

בהוצאות האחרונות, הפקודה java תדרוג את התוכנית אם קובץ המחלקה לא קיים. אם המחלקה נמצאת בחבילה, כמו com.example, אז עליה להיות בתוך התיקייה com/example. הפקודה להדר ולהריץ היא:

  1. java com/example/Test.java

אם המחלקה שלך דורשת JARs נוספים כדי להדר ולהריץ, ניתן להשתמש באפשרות java -cp. לדוגמה:

  1. java -cp .:~/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar com/example/Test.java

36. איך מייצרים enum ב-Java?

הקוד בדוגמה הבאה מראה איך ליצור enum בסיסי:

public enum ThreadStates {
	START,
	RUNNING,
	WAITING,
	DEAD;
}

ThreadStates הוא האינום עם שדות קבועים קבועים START, RUNNING, WAITING, ו- DEAD. כל האינומים מרחיבים משמעותית את המחלקה java.lang.Enum מאולתרים בפנים ומיישמים את הממשקים Serializable ו־ Comparable. אינום יכול להכיל גם שיטות. למידע נוסף על אינומים ב-Java.

37. איך משתמשים בשיטת forEach() ב-Java?

השיטה forEach() מספקת דרך קצרה לבצע פעולה על כל האיברים של אוסף. הקוד הדוגמא הבא מראה כיצד לעבור על איברי הרשימה ולהדפיס אותם:

List<String> list = new ArrayList<>();

Iterator<String> it = list.iterator();

while (it.hasNext()) {
	System.out.println(it.next());
}

ניתן להשתמש בשיטת forEach() עם ביטוי למבדר כדי להפחית את גודל הקוד, כפי שמוצג בקוד הדוגמא הבא:

List<String> list = new ArrayList<>();

list.forEach(System.out::print);

38. איך לכתוב ממשק עם שיטות default ו־ static?

Java 8 הציגה שיטות ברירת מחדל וסטטיות בממשקים. זה סייע לגשר על הפער בין ממשקים ובין כיתות אבסטרקטיות. הקוד בדוגמה הבאה מציג דרך לכתוב ממשק עם השיטות default ו־static:

public interface Interface1 {
	
	// שיטה אבסטרקטית רגילה
	void method1(String str);
	
	default void log(String str) {
		System.out.println("I1 logging::" + str);
	}
	
	static boolean isNull(String str) {
		System.out.println("Interface Null Check");

		return str == null ? true : "".equals(str) ? true : false;
	}

}

מידע נוסף על שיטות default ו־static בממשקים ניתן למצוא בשינויים בממשק ב-Java 8.

39. איך ניתן ליצור ממשק פונקציונלי?

ממשק עם בדיוק שיטה אבסטרקטית אחת נקרא ממשק פונקציונלי. היתרון המרכזי של ממשקים פונקציונליים הוא שניתן להשתמש בביטויי למבדר להם באמצעות השתמשות בביטויי למבדר (Lambda Expressions) ולהימנע משימוש במימוש של כיתה אנונימית וכביכול יכולת למלא ממשק. האנוטציה @FunctionalInterface מציינת ממשק פונקציונלי, כפי שמוצג בדוגמה הבאה:

@FunctionalInterface
interface Foo {
	void test();
}

40. הצג דוגמה לשימוש בביטויי למבדר ב-Java.

Runnable הוא דוגמה מצוינת לממשק פונקציונלי. באפשרותך להשתמש בביטויי למבדר (lambda expressions) כדי ליצור ממשק מבצע (runnable), כפי שמוצג בדוגמה הבאה:

Runnable r1 = () -> System.out.println("My Runnable");

41. הראה דוגמאות לטעינת מתודות (overloading) וכיבוי (overriding) ב-Java.

כאשר יש לכיתה שני או יותר מתודות בעלות אותו שם, הן נקראות מתודות מעומרות (overloaded methods). בדוגמה הבאה מוצגת מתודה מעומרת בשם print:

class Foo {
	void print(String s) {
		System.out.println(s);
	}

	void print(String s, int count) {
		while (count > 0) {
			System.out.println(s);
			count--;
		}
	}

}

כאשר מתודת המחלקה העל (superclass) מיושמת גם במחלקת הילד, זו נקראת כיבוי (overriding). בדוגמה הבאה מוצג כיצד להוסיף הערות למתודת printname() שמיושמת בשתי המחלקות:

class Base {
	void printName() {
		System.out.println("Base Class");
	}
}

class Child extends Base {
	@Override
	void printName() {
		System.out.println("Child Class");
	}
}

למד עוד על כיבוי וטעינת מתודות ב-Java.

42.-49. נחש את הפלט

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


String s1 = "abc";
String s2 = "abc";

System.out.println("s1 == s2 is:" + s1 == s2);
Output
false

הפלט של ההצהרה הנתונה הוא false מאחר ואופרטור החיבור + נמצא בעדיפות גבוהה יותר מאשר אופרטור ההשוואה ==. לכן, הביטוי הנתון מיוערך ל-“s1 == s2 is:abc” == “abc”, שהוא false.


String s3 = "JournalDev";
int start = 1;
char end = 5;

System.out.println(s3.substring(start, end));
Output
ourn

הפלט של ההצהרה הנתונה הוא `ourn`. התו הראשון משתנה באופן אוטומטי לסוג `int`. לאחר מכן, מאחר שאינדקס התו הראשון הוא 0, הוא יתחיל מהתו `o` וידפיס עד לתו `n`. שים לב ששיטת `substring` של מחרוזת יוצרת מחרוזת מתחילת האינדקס `start` ונגמרת בתו האינדקס `end – 1`.


HashSet shortSet = new HashSet();

	for (short i = 0; i < 100; i++) {
    shortSet.add(i);
    shortSet.remove(i - 1);
}

System.out.println(shortSet.size());
Output
100

גודל ה- `shortSet` הוא `100`. התכונה של אוטומטי האריזה ב-Java אומרת שהביטוי `i`, שיש לו סוג פרימיטיבי של `short`, משתנה לאובייקט של `Short`. באופן דומה, הביטוי `i - 1` יש לו סוג פרימיטיבי של `int` ומאוטומטי האריז לאובייקט של `Integer`. מאחר שאין אובייקט של `Integer` ב- `HashSet`, אין דבר שנמחק והגודל הוא `100`.


try {
	if (flag) {
  		while (true) {
   		}
   	} else {
   		System.exit(1);
   	}
} finally {
   	System.out.println("In Finally");
}
Output

אין פלט. קוד זה מייצר לולאה אינסופית אם הדגל הוא `true` והתוכנית יוצאת אם הדגל הוא `false`. בלוק ה- `finally` לעולם לא ייגע.


String str = null;
String str1="abc";

System.out.println(str1.equals("abc") | str.equals(null));
Output
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "<local1>" is null

ההצהרה הנתונה תזרוק חריגת `java.lang.NullPointerException` מכיוון שאופרטור הלוגיקה `OR` מעריך את שני הליטרלים לפני שהוא מחזיר את התוצאה. מאחר ש- `str` הוא `null`, שיטת `.equals()` תזרוק חריגה. תמיד כדאי להשתמש באופרטורי הלוגיקה הקצר-מעגליים, כמו `||` ו- `&&`, שמעריכים את ערכי הליטרל משמאל לימין. במקרה זה, מאחר שהליטרל הראשון יחזיר `true`, הוא ידלג על הערכות הליטרל השני.


String x = "abc";
String y = "abc";

x.concat(y);

System.out.print(x);
Output
abc

ה- x.concat(y) יוצרת מחרוזת חדשה אך לא מוקצה ל- x, לכן ערך ה- x לא משתנה.


public class MathTest {

 	public void main(String[] args) {  		
   		int x = 10 * 10 - 10;
   		
   		System.out.println(x);
   	}
   
}
Output
Error: Main method is not static in class MathTest, please define the main method as:
   public static void main(String[] args)

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


public class Test {
   
  	public static void main(String[] args) {
   		try {
   			throw new IOException("Hello");
   		} catch(IOException | Exception e) {
   			System.out.println(e.getMessage());
   		}
   	}
}
Output
Test.java:5: error: cannot find symbol
   			throw new IOException("Hello");
   			          ^
  symbol:   class IOException
  location: class Test
Test.java:6: error: cannot find symbol
   		}catch(IOException | Exception e) {
   		       ^
  symbol:   class IOException
  location: class Test
2 errors

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

50. מצאו 5 טעויות בקטע הקוד הבא.

package com.digitalocean.programming-interviews;

public class String Programs {

	static void main(String[10] args) {
		String s = "abc"
		System.out.println(s);
	}
}
Answers
  1. שם החבילה לא יכול להכיל מקפים.
  2. שם המחלקה לא יכול לכלול רווחים.
  3. השיטה הראשית אינה public, לכן היא לא תרוץ.
  4. הארגומנט של שיטת הראשית לא צריך לציין את הגודל.
  5. הנקודה פסיק חסרה בהגדרת המחרוזת.

מסקנה

אוסף זה של 50 שאלות ראיון תכנות ב-Java כלל שאלות מרמה מתחילה עד רמת מומחה, לעזור לך להתכונן לראיון שלך.

קריאה מומלצת:

Source:
https://www.digitalocean.com/community/tutorials/java-programming-interview-questions