Java Quiz

Ne, aber wozu sollte man? Um den Anwendungsfall abzudecken, iteriert über das entrySet und verändert die Entrys. Dieses Verhalten ist nämlich spezifiziert.

Weiter geht’s:

Was macht dieser (Quell-)Code:

int toGuess = ((lo + fence) >>> 1) & ~1;

Welchen Integer berechnet er? :slight_smile:

Das hängt von lo und fence ab.

:o)

Das >>> ist ein “geteilt durch zwei” (mit Vorzeichenbehandlung), und das & ~1 löscht das letzte Bit. Also müßte das sowas sein wie “Die hälfte von lo + fence, abgerundet auf die nächste gerade Zahl”…!?

Das ist richtig, Marco, die Mitte von lo und fence, aber -1, wenn sie nicht gerade ist.
Oder: x | x gerade und x<=Hälfte/Mitte und x>Hälfte-1
Oder so ähnlich.
Weiter geht’s. …

Also (int) (Math.floor((lo + fence) / 2.0)) oder (int) (Math.floor((lo + fence) / 2.0)) - 1, wenn (int) (Math.floor((lo + fence) / 2.0)) ungerade.
{ x | x gerade und x<=Hälfte und x+2>Hälfte }.
Hälfte==Mitte von lo und fence.
>>> behandelt das Vorzeichen in der Art und Weise, dass es getilgt wird, wenn zuvor 1 MSB.

Bitte jetzt aber schnell weiter mit jemand anderes. :wink: :slight_smile:

Gegeben sei folgende Klasse mit zu testender Methode:

  String arg;
  void setArg(String arg) {
    assert(arg!=null && !arg.isEmpty());
    this.arg = arg;
  }
}

Dafür wurde folgender UnitTest implementiert:

  
  @Test(expected=AssertionError.class)
  public void testSetArg() {
    PackagePrivateBean underTest = new PackagePrivateBean();
    String argToSet = "";
    underTest.setArg(argToSet);
    Assert.assertSame(argToSet, underTest.arg);
  }
}

In der Testumgebung wird die VM mit “-ea” gestartet und der Test durchlaufen. Was läuft bei diesem Test schief, bzw. warum ist dieser Test schlecht.

Im Fall von -ea ist Zeile 8 DeadCode, das assert aus der zu testenden Klasse wirft die Assertion. Die Assertion wird erwartet und der Test funktioniert.

arg wird allerdings nicht gesetzt. Daher ist arg != argToSet

Schält man die Assertions aus, dann bekommt man ein anderes Verhalten.
arg wird gesetzt und arg == argToSet

Eine IllegalArgumentException wäre wohl sinnvoller.

[li]Der Name des Tests sagt nichts über die getestete Anforderung aus.
[/li][li]Der Name der an den produktiven Code übergenenen Variablen gib nicht die für den Test wichtigen Eigenschaften des Arguments wieder.
[/li][li]Der Test kennt den internen Aufbau der getesteten Produktiv-Klasse.
[/li][li]Die vom Test erwartete Exception wird wo möglich während der Laufzeit gar nicht geworfen.
[/li][li]Und wie mein Vorposter schon schrieb: die Zeile 8 im Test verschleiert die ware Absicht des Tests.
[/li][/ol]

Das eigentliche Problem liegt aber nicht im Test selbst sondern in dem Ansatz, assert() für die Prüfung der Eingabe zu misbrauchen. Wenn leere Strings aus fachlichen Gründen nicht erlaubt sind (so dass es einen Unittest dafür gibt) müssen sie auch ohne -ea abgelehnt werden.

bye
TT

Oha, da kam ja einiges zusammen :wink: Ich wollte aber auf das von Unregistered Genannte hinaus. Wenn man Code hat, der Java-Assertions nutzt (die ich übrigens für die Validierung von Package-Privatem Code sehr sinnvoll finde, aber das wäre wohl eine eigene Diskussion) und das Funktionieren dieser mittels expected=AssertionError.class verifiziert, verbaut man sich evtl. Tests, weil die JUnit-Assert-Methoden auch AssertionErrors werfen.

Das Kernproblem in dem dargestellten Testcode ist aber letztlich, dass hier zwei Testfälle in einer Methode getestet werden:

  1. Funktioniert das assert bei Übergabe eines invaliden Parameters?
  2. Setzt die Methode das interne Feld, ohne den Parameter zu verändern?
    Also merken: Auch wenn’s unbequem ist, für jeden Testfall eine eigene Testmethode! (dabei würde man dann auch die von Timothy genannten Punkte 1,2 und 5 berücksichtigen)
    {
        private int a;

        public void setA(int a)
        {
            this.a = a;
        }

        // auto generierte equals() und hashCode()
        @Override
        public boolean equals(Object o)
        {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            A a1 = (A) o;

            if (a != a1.a)
                return false;

            return true;
        }

        @Override
        public int hashCode()
        {
            return a;
        }
    }

    public static void main(String[] args)
    {
        A a = new A();
        HashMap<A, Object> map = new HashMap<A, Object>();
        map.put(a, null);
        a.setA(5);

        for(Entry<A, Object> entry : map.entrySet()){
            if(entry.getKey().equals(a))
                System.out.println("(1) map contains a");
        }

        if(map.containsKey(a))
            System.out.println("(2) map contains a");
    }

Zusammengefasst: Objekt A wird erzeugt, in eine HashMap gesteckt, Attribut a wird gesetzt. Nun wird nach dem Objekt gesucht: (1) über Iterator + equals und (2) über containsKey.
Was wird ausgegeben?

[SPOILER]nur System.out.println("(1) map contains a");
[SPOILER]weil der Key im falschen Bucket gesucht wird, der Hashcode hat sich geändert.[/SPOILER][/SPOILER]

bye
TT

[spoiler]Hier wird dagegen versoßen, dass Map-Keys nicht geändert werden sollen. Dies führt laut Doku zu unvorhersagbarem Verhalten. In diesem Fall ändert sich der hashCode. In einer HashMap führt das dazu, dass der Key nicht mehr wiedergefunden wird. Also sage ich “(1) map contains a” wird ausgegeben, das andere nicht.

Edit: Nun hab ich mal Timothy’s Spoiler aufgemacht. Der hatte es (leider) schon vor mir…
[/spoiler]

[spoiler]Ich würde auch sagen, dass nur „(1) map contains a“ ausgegeben wird. Allerdings könne es zufälligerweise so sein, dass auch die 5 auf das nullt Bucket abgebildet wird, weil das HashSet noch zu klein ist. Dann würde der Key trotzdem zufälligerweise gefunden. Dazu müsste man sich ansehen, wie das HashSet implementiert ist (oder es einfach ausprobieren :wink: ).[/spoiler]

Alles richtig :slight_smile:
Mit dem Problem haben wir heute zu dritt bestimmt ne halbe Stunde gekämpft. Ein Oracle Zertifikat wäre vielleicht doch nicht so nutzlos wie gedacht :smiley:

Gibt es einen praktischen Unterschied zwischen den folgenden Methoden?

public <E> void fill1(List<? extends Comparable<? super E>> a);

public <E extends Comparable<? super E>> void fill2(List<E> a);

Die Frage hab’ ich auch gesehen :smiley:
[spoiler]

Ja.

In einem Fall ist festgelegt, das „E“ das sein muss, zu dessen Supertypen die Listenelemente vergleichbar sind (auch wenn das ein anderer Typ ist, als die Listenelemente selbst)
Im anderen Fall ist festgelegt, das „E“ das sein muss, zu dessen Supertypen die Listenelemente vergleichbar sind, und dass dieser Typ auch in der Liste enthalten ist.

Für den Fall, dass beim Comparable das „E“ etwas ist, was komplett unverwandt zur implementierenden Klasse ist, fällt mir zwar spontan nichts sinnvolles ein, aber da müßte man nochmal drüber nachdenken…


import java.util.List;

abstract class Foo implements Comparable<Foo> {}
abstract class Bar implements Comparable<Foo> {}

public class ComparableTest {
	
	public static void main(String[] args) {
		List<Foo> foos = null;
		List<Bar> bars = null;
		
		ComparableTest c = null;

		c.fill1(foos); // geht
		c.fill1(bars); // geht

		c.fill2(foos); // geht
		c.fill2(bars); // geht NICHT
	}
	
	public <E> void fill1(List<? extends Comparable<? super E>> a) {}
	 
	public <E extends Comparable<? super E>> void fill2(List<E> a) {}
}

[/spoiler]

mehr Logik-Quiz, aber wenn es gerade allgemein im Netz ein Thema sein sollte so dass es bis in die Zeit kommt, dann lohnt sie sich ja zu erwähnen,
anderer Thread muss gewiss nicht sein:

bzw. Mathe-Aufgabe: Ist doch total logisch!
(auch mit Lösungslink, bringt also nicht viel es hier zu lösen, nur für jeden für sich)

Ich hatte die richtige Lösung herausbekommen, nach ca. 20 min.

if (i.equals(1))
    i = null;
Double d = new Double(2.0);
Object o = true ? i : d;
System.out.println(o);```

Die Frage wie immer: kompiliert der Code, und wenn ja, was wird ausgegeben?

Was ich vermutet hatte, war falsch.