Lambda - porównanie Stringa za pomocą == zwraca poprawny wynik

Lambda - porównanie Stringa za pomocą == zwraca poprawny wynik
Burdzi0
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Futurama
  • Postów: 887
0

Witajcie!

Kończę ogarniać lambdę i mam do was wszystkich pytanie względem przykładu z książki (który już przybliżam).

Mam taki oto interfejs.

Kopiuj
public interface MyFunc<T> {
	int func(T[] vals, T t);
}

Taką klasę

Kopiuj
public class MyArrayOps {
	
	static <T> int countMatching(T[] vals, T v) {
		int count = 0;
		
		for (int i = 0; i < vals.length; i++) {
			if (vals[i] == v) {
				++count;
			}
		}
		return count;
	}
}

Oraz klasę wykonawczą

Kopiuj
public class GenericMethodRefDemo {
	
	static <T> int myOp(MyFunc<T> f, T[] vals, T v) {
		return f.func(vals, v);
	}
	
	public static void main(String[] args) {
		Integer[] vals = {1,2,3,4,2,3,4,4,5};
		String[] strs = {"Jeden", "Dwa", "Trzy", "Dwa"};
		
		int count;
		
		count = myOp(MyArrayOps::countMatching, vals, 4);
		System.out.println(count);
		count = myOp(MyArrayOps::countMatching, strs, "Dwa");
		System.out.println(count);
	}
}

Moje pytanie brzmi: dlaczego podając tablicę obiektów String i osobny obiekt typu String, czyli ta linijka

Kopiuj
count = myOp(MyArrayOps::<String>countMatching, strs, "Dwa");

zwraca poprawny wynik? W końcu metoda countMatching porównuje obiekty za pomocą operatora ==, co normalnie porównałoby referencje...
Czy lambda wnioskując typ podanych obiektów korzysta niejawnie z metody equals przy użyciu operatora ==?

bogdans
  • Rejestracja: dni
  • Ostatnio: dni
1

Niesłusznie zakładasz, że referencje są różne.

Burdzi0
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Futurama
  • Postów: 887
0

@bogdans: Ale jak to? O.o
Czy taka sama referencja nie byłaby, gdybym wykorzystał coś takiego?:

Kopiuj
count = myOp(MyArrayOps::countMatching, strs, strs[1]);

Rozwiń, jeśli możesz, bo już kompletnie zgłupiałem... (zwłaszcza, że to przykład z kompendium Herberta Schildta przepisany jota w jotę)

bogdans
  • Rejestracja: dni
  • Ostatnio: dni
1

Tak działa kompilator - jeśli dostrzeże dwa identyczne Stringi (a przy tworzeniu drugiego nie ma operatora new), to nie tworzy dwóch różnych obiektów.

Kopiuj
String a = "dwa";
String b = "dwa";
//porównanie a == b zwraca true
String c = new String("dwa");
//porównanie a == c zwraca false
String d = new String("dwa").intern();
//porównanie a == d zwraca true
Burdzi0
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Futurama
  • Postów: 887
0

Rzeczywiście, masz rację...
Czy to oznacza błąd w książce?

bogdans
  • Rejestracja: dni
  • Ostatnio: dni
0

O jaki błąd pytasz?

Burdzi0
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Futurama
  • Postów: 887
0

Już nie ważne, już (chyba) ogarnąłem, że jego celem było porównanie referencji, a nie wartości obiektu (bo tak jest, prawda?)

Shalom
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Space: the final frontier
  • Postów: 26433
1

@Burdzi0 w 99% przypadków chcesz porównywać wartości a nie referencje. No i pamiętaj że String w javie, tak samo jak np. Integer maja pewien wewnętrzny cache, wiec obiekty tworzone przez valueOf() mogą być tymi samymi obiektami. To nie jest problem bo te obiekty i tak są immutable -> zmiana stringa powoduje utworzenie nowego.

Burdzi0
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Futurama
  • Postów: 887
0
Shalom napisał(a):

No i pamiętaj że String w javie, tak samo jak np. Integer maja pewien wewnętrzny cache, wiec obiekty tworzone przez valueOf() mogą być tymi samymi obiektami. To nie jest problem bo te obiekty i tak są immutable -> zmiana stringa powoduje utworzenie nowego.

Tego nie wiedziałem, dzięki :)

jarekr000000
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: U krasnoludów - pod górą
  • Postów: 4712
1

I tu jako uzupełnienie ciekawa metoda z klasy String
intern

Przydaje się raz na piętnaście lat.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.