(Getter-) Name für "soll..."

Hey Leute.
Wie benennt man auf englisch am besten booleans,
die soetwas ausdrücken wie “soll…” ? zB “sollEntferntWerden” ?

Einfach “remove” ist doof, weil wie man dann den getter nennen, isRemove() ?
“removeable” ist doof, weil das teil ja genaugenommen immer entfernbar ist, aber
nicht immer entfernt werden soll. (und überhaupt, sollte man booleans mit “…able” benennen?)

Vielleicht sowas wie removeRequested… aber das ist mir irgendwie zu lang …
wie macht ihr das?

Die Frage sollte eigentlich lauten: “Wie bekommt man sowas ohne Getter hin?”.

Die Antwort wäre dann: “Mit Listener.”

Darüber hinaus gilt für die Nomenklatur: Der Name muss exakt ausdrücken was die Methode macht oder die Variable enthält, egal wie Lang der Name wird.

bye
TT

ja gut, zu lang ist da wohl nicht der punkt.
aber removeRequested… gefällt mir irgendwie nicht… ka.

In meinem fall funktioniert ein listener eigentlich nicht.
Es geht um die Klasse Animation, viele Animations im AnimationPool,
welcher jeden Frame durch erstere iteriert. Im Moment gilt: if(a.isReady()) list.remove(a);
Aber da die Bedingung ein bisschen komplexer werden soll, will ich einfach ne variable machen… wie oben erwähnt,
und statt ner langen if einfach nur diese eine abfragen.

Ein Listener wäre doch sinnfrei, weil eine Animation sich nicht selber entfernen kann…?.

Immer wie es logisch und sprechend klingt. isFoo, hasBar, canBlubb, je nachdem, was es für steht.

In deinem Fall sind aber eher Listener angebracht, außer du willst unbedingt an diesem Statuspolling festhalten.

ohne spezielle Befürwortung und ohne englische Rückversicherung,
aber allein schon weil es noch nicht erwähnt wurde:

boolean toRemove, toDisplay, toSend usw., edit: toDo :wink:
boolean isToRemove() usw.

ah, danke slater :smiley:
das macht sinn ^^
@TheDarkRose : Wie würdest du hier denn konkret mit nem interface arbeiten?

Observer Pattern, oder? Der, wer die Animations verwaltet, registriert sich bei der Animation als Listener und die Animation informiert dann die Listener, anstatt ein boolean zu setzen,

halb OffTopic, aber wenn du schon ein wenig fragst:
ein list.remove()-Aufruf mutmaßlich in einem Durchlauf per Schleife derselben Liste ist aber auch nicht zu empfehlen,
wenn dann mit Iterator

oder bei Animation, vielen Durchläufen, vielleicht temporären leichten Modifikationen, am Ende Animation immer noch da,
klingt es eher nach gar nicht entfernen, nur bei bestimmten Durchläufen mal NICHT anzeigen, isVisible() false :wink:

hä? Also AnimationPool implements AnimationListener

dann interface AnimationListener { void onRemove(Animation source); //... }

und in Animation: protected void setAnimationListener(AnimationListener e){}

so? Dann in Animation einfach listener.onRemove(this) ?

*** Edit ***

[QUOTE=SlaterB]halb OffTopic, aber wenn du schon ein wenig fragst:
ein list.remove()-Aufruf mutmaßlich in einem Durchlauf per Schleife derselben Liste ist aber auch nicht zu empfehlen,
wenn dann mit Iterator

oder bei Animation, vielen Durchläufen, vielleicht temporären leichten Modifikationen, am Ende Animation immer noch da,
klingt es eher nach gar nicht entfernen, nur bei bestimmten Durchläufen mal NICHT anzeigen, isVisible() false ;)[/QUOTE]

Hm, mit letzterem meinst du so könnte man es machen? Stimmt eigentlich, aber mal schauen.
Viele werden eigentlich nur einmal gebraucht.

Zur Liste: Nein so sieht das nicht wirklich aus… eher umständlicher… xD

	public void update(){
		for(Animation a : animations){
			if(a.isReady()){
				toRemove.add(a);
			}
			else{
				a.update();
			}
		}
		for(Animation a : toRemove){
			animations.remove(a);
		}
		toRemove.clear();
	}

ja ihr dürft mich schlagen xD

*** Edit ***

Hm ich merk grad das wenn man den Iterator manuell erzeugt, zugriff auf die methode remove() hat…
Ich schlaukopf… danke :smiley: aber geht das dann, auch ohne Concurrency Probleme oder so?

Ja, das pattern mit der toRemove-Liste, das du da bisher verwendet hast, ist gar nicht so unüblich und kann auch Vorteile haben.

Ich würde die Liste lokal in der Methode deklarieren, und damit das “clear()” sparen, und zum entfernen auch “removeAll” verwenden.

Das hat auch zu tun mit der (berechtigten und relevanten) Frage nach der concurrency:

Wenn man das ganze “thread safe” mit dem Iterator machen will, dann müßte man folgendes machen:
(vorischtig mit dem Begriff “thread safe”, es gibt noch 1000 Dinge, die man da berücksichtigen muss!)

  1. Man müßte die “animations”-Liste zu einer Collections.synchronizedList(animations) machen
  2. Man müßte zusätzlich (!) über die komplette iteration synchronisieren. Also sowas wie
synchronized (animations) {
    Iterator it = animations.iterator();
    while (it.hasNext()) {
        Animation a = it.next();
        if (a.isReady()) it.remove(); 
    }
}

Mit der toRemove-Liste reicht die Collections.synchronizedList, weil der Aufruf von removeAll dann schon komplett synchronisiert ist (sofern man den Aufruf verwendet ;))

Zur eigentlichen, ursprünglichen Frage: (Mir ist nicht ganz klar, wie das ganze mit Listenern zusammenhängt, aber ohne DAS nun weiter zu hinterfragen…) : Wenn man eine Methode erstellen will, bei der der (boolean) Rückgabewert “true” besagen soll: “the object should be removed”, dann würde ich dafür vorschlagen:
theObject.shouldBeRemoved()

(Dass das konzeptuell vermutlich (!) nicht “schön” ist, ändert nichts daran, dass Quellcode sich im besten Fall wie Prosa-Text lesen sollte…)

Dazu mal ein fettes OT: http://de.wikipedia.org/wiki/Shakespeare_Programming_Language :smiley:

hm. should gefällt mir eigentlich, danke.

Hm. Irgendwie klingt das mit dem „zusätzlich“ abschreckend.
Es ist ja sowieso alles in einem thread (lwjgl und so), aber ich meinte
eben die Exception die auftritt wenn man remove() während der iteration aufruft…

Ich glaub dann lass ich das erstmal so.

Bzw ich mach nachher mal einen speed test. Will jetzt nicht mit microoptimizing ankommen,
aber solche fragen wie „was ist schneller? clear() oder jedes mal new ArrayList<>()“ interessieren
mich dann doch ^^

Hm. Ich hab jetzt mal einen Test geschrieben…


import java.util.ArrayList;
import java.util.Iterator;

public class SpeedTest {
	
	public SpeedTest(int i){
		System.out.println("Starting test " + i);
                initTime();
		test1();
		test2();
		test3();
		test4();
                System.out.println("

");
	}
	
	private void test1(){
		ArrayList<String> list = new ArrayList<>();
		for(int i = 0; i < 100000000; i++){
			if(i % 2 == 0) list.add("abc!");
			else list.add("def?");
		}
		timeStamp("init 1:");
		ArrayList<String> toRemove = new ArrayList<>();
		for(String s : list){
			if(s.equals("abc?")) toRemove.add(s);
		}
		list.removeAll(toRemove);
		timeStamp("  process 1:");
	}
	
	private void test2(){
		ArrayList<String> list = new ArrayList<>();
		for(int i = 0; i < 100000000; i++){
			if(i % 2 == 0) list.add("abc!");
			else list.add("def?");
		}
		timeStamp("init 2:");
		for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){
			if(iterator.next().equals("abc?")) iterator.remove();
		}
		timeStamp("  process 2:");
	}
	
	private void test3(){
		timeStamp("init 3:");
		ArrayList<String> list = new ArrayList<>();
		for(int i = 0; i < 10; i++){
			for(int j = 0; j < 10000000; j++){
				if(j % 2 == 0) list.add("abc!");
				else list.add("def?");
			}
			list.clear();
		}
		timeStamp("  process 3:");
	}
	
	private void test4(){
		timeStamp("init 4:");
		for(int i = 0; i < 10; i++){
			ArrayList<String> list = new ArrayList<>();
			for(int j = 0; j < 10000000; j++){
				if(j % 2 == 0) list.add("abc!");
				else list.add("def?");
			}
		}
		timeStamp("  process 4:");
	}
	
	private long lastTimeStamp;
	private void initTime(){
		lastTimeStamp = System.currentTimeMillis();
	}
	
	private void timeStamp(String msg){
		long newTimeStamp = System.currentTimeMillis();
		System.out.println(msg + " " + (newTimeStamp - lastTimeStamp) + "ms");
		lastTimeStamp = newTimeStamp;
	}
	
	public static void main(String[] args){
		for(int i = 0; i < 5; i++) new SpeedTest(i);
	}
}

joar, quick and dirty halt.
Aber ich verstehe das ergebniss rein gar nicht.
Wie kann folgendes sein:


Starting test 0
init 1: 765ms
  process 1: 1142ms
init 2: 1254ms
  process 2: 528ms
init 3: 1ms
  process 3: 624ms
init 4: 0ms
  process 4: 888ms



Starting test 1
init 1: 745ms
  process 1: 880ms
init 2: 914ms
  process 2: 348ms
init 3: 0ms
  process 3: 589ms
init 4: 0ms
  process 4: 757ms



Starting test 2
init 1: 741ms
  process 1: 657ms
init 2: 836ms
  process 2: 344ms
init 3: 0ms
  process 3: 529ms
init 4: 0ms
  process 4: 1304ms



Starting test 3
init 1: 1075ms
  process 1: 658ms
init 2: 799ms
  process 2: 341ms
init 3: 0ms
  process 3: 523ms
init 4: 0ms
  process 4: 1145ms



Starting test 4
init 1: 1197ms
  process 1: 655ms
init 2: 1241ms
  process 2: 342ms
init 3: 0ms
  process 3: 502ms
init 4: 0ms
  process 4: 772ms

die werte ergeben keinen sinn.

OB du die Threadsicherheit brauchst, muss du wissen. Wenn es keinen dedizierten Animations- oder Game-Thread gibt, brauchst du sie vielleicht nicht.

Was genau mit diesem “Test” nun getestet werden sollte, hat sich mir aber nicht ganz erschlossen. (BTW: “abc?” kommt doch nie vor, oder?)

test1 und test2: unterschied zwischen toRemove liste, und iterator.remove().
test3 und test4: unterschied zwischen newArrayList und clear.

*** Edit ***

Zum Listener Konzept:

Hier fliegt natürlich direkt eine Concurrency. Wie würdet ihr das konkret lösen, auch
ohne die Effizienz aus dem Blickfeld zu verlieren?


import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

public class ConcurrencyTest implements Runnable, AnListener {
	
	private ArrayList<AnObject> objects;
	
	public ConcurrencyTest(){
		objects = new ArrayList<>();
		for(int i = 0; i < 1000; i++) objects.add(new AnObject(this));
		run();
	}
	
	public void run(){
		while(true){
			for(Iterator<AnObject> iterator = objects.iterator(); iterator.hasNext();){
				iterator.next().update();
			}
		}
	}
	
	static class AnObject {
		
		private AnListener listener;
		
		public AnObject(AnListener listener){
			this.listener = listener;
		}
		
		public void update(){
			if(new Random().nextInt(4) == 1){
				listener.onRemove(this);
			}
		}
	}
	
	public static void main(String[] args){
		new ConcurrencyTest();
	}

	public void onRemove(AnObject o){
		objects.remove(o);
	}
}```

Wenn nicht allzu viele Updates gemacht werden, kannst du eine [japi]CopyOnWriteArrayList[/japi] nehmen:


import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

public class ConcurrencyTest implements Runnable, AnListener {

    private List<AnObject> objects;

    public ConcurrencyTest() {
        objects = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 1000; i++) objects.add(new AnObject(this));
    }

    public void run() {
        while (objects.size() > 0) {
            for (Iterator<AnObject> iterator = objects.iterator(); iterator.hasNext(); ) {
                iterator.next().update();
            }
        }
    }

    static class AnObject {

        private AnListener listener;

        public AnObject(AnListener listener) {
            this.listener = listener;
        }

        public void update() {
            if (new Random().nextInt(4) == 1) {
                listener.onRemove(this);
            }
        }
    }

    public static void main(String[] args) {
        new ConcurrencyTest().run();
    }

    @Override
    public void onRemove(AnObject o) {
        objects.remove(o);
    }
}```

*** Edit ***

Wobei mir dein Ziel noch nicht ganz klar ist... Der [japi]Runnable[/japi] wird ja nicht als eigener Thread ausgeführt. Die Exception fliegt nur, weil während der Iteration über eine Liste **ausschließlich** über den Iterator gelöscht werden darf. Das wird im Listener nicht berücksichtigt und eine [japi]ConcurrentModificationException[/japi] fliegt.

hm. soll ich dann einfach mit for(int i = 0; i < objects.size(); i++) objects.get(i).update();
arbeiten?
Hab eben gehört, das sollte man bei collections vermeiden weil das langsamer sei…
aber stimmt, dann müsste es funktionieren, oder?

OK, den Unterschied zwischen „toRemove“ und „Iterator“ zu messen ist in mehrerer Hinsicht schwierig.

Erstens wegen der üblichen Schwierigkeiten bei Java Microbenchmarks (die hast du Ansatzweise zu vermeiden versucht, z.B. das Problem des JIT durch die mehrfache Ausführung, aber … wenn die Ergebnisse so eines Tests nicht verwendet werden, kann der ja optimieren, was er will).

Zweitens hängt die Performance massivst von den konkreten Daten ab. Wie groß der Unterschied zwischen „toRemove“ und „Iterator“ ist, hängt z.B. davon ab, ob man eine Liste mit 1000000 Elementen hat, und davon 999999 entfernt, oder nur 1. Aber da ich nicht davon ausgehe, dass du 1000000 Animationen ablaufen läßt, von denen 999999 gleichzeitig fertig sind, wäre so ein Test in bezug auf den konkreten Anwendungsfall ohnehin nur sehr begrenzt aussagekräftig :wink:

Wie gesagt, mir ist nicht klar, wo der Listener in diese Diskussion reinkam. Auf Basis des bisher beschriebenen würde ich denken, dass es „toRemove“ oder Iterator schon tun, und es um Listen geht, bei denen sich beide in bezug auf die Performance nicht viel nehmen…

*** Edit ***

Als Nachtrag: Bei der „ConcurrentModificationException“ muss man grob in zwei Kategorien einteilen: Die, die vom selben Thread verursacht werden, und die, die durch concurrent Zugriffe entstehen. Sowas wie

for (Object object : list)
{
    if (someCondition) list.remove(object);
}

wird eine Exception werfen, auch bei EINEM Thread. Dabei spielt es auch keine Rolle, ob dieses „remove“ quasi „von hinten durch die Brust ins Auge“ über einen Listener erfolgt: Das Problem ist, dass die Liste verändert wird, während man drüberiteriert.

Sowas wie

for(int i = 0; i < objects.size(); i++) 
{
    if (someCondition) {
        objects.remove(objects.get(i));
        i--;
   }
}

ist etwas anders. Dort fliegt keine Exception, weil es ja keinen Iterator gibt, der einen Zustand hätte, der durch die Änderungen gestört wird. Aber wie man sieht, muss man händisch die Schleifenvariable (i–) anpassen, was IMHO grundsätzlich häßlich ist, und spätestens dann nicht mehr so leicht funktioniert, wenn das „remove“ an ganz anderer Stelle, versteckt, in einem Listener gemacht wird.

In BEIDEN Fällen bekommt man zusätzliche Probleme, wenn auf die Liste mit mehreren Threads zugegriffen wird, und man das nicht berücksichtigt. Wenn man sowas hat wie

List<String> list = new ArrayList<String>();
list.add("x");

void removeElement()
{
    list.remove("x");
}

und die „removeElement“ gleichzeitig von zwei Threads ausgeführt wird, kann der Zustand der Liste danach schlicht inkonsistent sein (also, richtig kaputt… GROB in dem Sinne, dass sie z.B. eine size() von -1 haben könnte (nicht genau das, aber grob in dem Sinne))