Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Sammansatta datatyper Generics: Parametrisk polymorfism [email protected] – 2016 2 Enligt TDDD73: "Listan är en mycket användbar sammansatt datatyp. I många andra språk kallar man listor för arrayer." Många språk har både listor och arrayer! Exakta definitioner varierar… Listor (i Java): Implementerade som klasser Finns många varianter (olika lagring) Kan växa och krympa Arrayer (i Java): "Inbyggda" i språket En enda variant Fixerad storlek jonkv@ida Listor och arrayer 4 För varje typ T kan Java dynamiskt skapa motsvarande arraytyp T[] Exempel: Object[], String[], Circle[] Subklass till Object ▪ Arrayer har metoder och fält, inte bara element Object Object[] String[] Circle[] Circle[][] jonkv@ida Arrayer 1: Arraytyper 5 numbers Circle[] circles = new Circle[10]; int[] numbers = new int[rnd()]; Arrayer skapas med new Storlekar är fasta, men sätts vid körning int second = numbers[1]; Element hämtas ut med index (första = 0) for (int i = 0; i < numbers.length; i++) { System.out.println(numbers[i]); } Index: 0…length-1 Arrayer känner till sin egen längd int val = numbers[42000]; Indexkontroll: Ger ArrayIndexOutOfBoundsException Object header: length [0] [1] [41] (data) 42 0 0 0 Element initialiseras: 0, 0.0, null, eller false jonkv@ida Arrayer 2: Användning 6 Objektarrayer innehåller pekare: Circle[ ] circles = new Circle[10]; circles Object header: length [0] [1] (data) 10 [9] Kan peka på vilken Circle som helst, inklusive subklasser (GraphicCircle) Element initialiseras till null Inga nya Circle-objekt skapas! jonkv@ida Arrayer 3: Pekar-arrayer Att initialisera en array 7 Antal element: Implicit ▪ public static void main(String[ ] args) { int[ ] numbers = new int[ ] { 1, 2, 4, 8, 16 }; print(numbers); print(new int[ ] { 44, getRandomInt() }); } Kompileras till kod! Motsvarar: int[ ] temp = new int[2]; temp[0] = 44; temp[1] = getRandomInt(); print(temp); Kompileras till kod! Motsvarar: int[ ] numbers = new int[5]; numbers[0] = 1; numbers[1] = 2; numbers[2] = 4; numbers[3] = 8; numbers[4] = 16; jonkv@ida Arrayer 4: Ange element Arrayer av arrayer: Square[ ][ ] board Square[ ] row Square pos board row = new Square[20][10]; = board[19]; = board[1][0]; Object header: length [0] [1] (data) 20 8 Object header: length [0] … [9] Object header: length [0] … [9] (data) 10 (data) 10 [18] [19] Object header: length [0] … [9] (data) 10 jonkv@ida Arrayer 5: Flerdimensionella arrayer 9 Arrayer ärver metoder från Object Av historiska anledningar: Bara default-implementationerna Default-implementationer… equals() testar identitet int[ ] ar1 = new int[3]; // 0, 0, 0 int[ ] ar2 = new int[3]; // 0, 0, 0 System.out.println(ar1.equals(ar2)); // false Kan inte ändras: Bakåtkompatibilitet! Vad vi oftast vill Hjälpmetoder i java.util.Arrays int[ ] ar1 = new int[3]; // 0, 0, 0 int[ ] ar2 = new int[3]; // 0, 0, 0 System.out.println(Arrays.equals(ar1,ar2)); // true Också i java.util.Arrays: sort(), binarySearch(), copyOfRange(), deepToString(), hashCode(), fill(), … jonkv@ida Arrayer 6: Tillgängliga metoder 10 Arrayer ärver metoder from Object Av historiska anledningar: Bara default-implementationerna Default-implementationer… toString(): typnamn + ID System.out.println(new int[10].toString()); // [I@3effd44e System.out.println(new Circle[4] .toString()); // [LCircle;@2b78146d Vad vi oftast vill Hjälpmetoder i java.util.Arrays System.out.println( Arrays.toString(new int[10])); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] jonkv@ida Arrayer 7: toString() Styrka: Effektiv användning av minne 11 numbers Liten konstant "startkostnad", 12–20 bytes Plus elementens "verkliga" kostnad ▪ Kan använda byte / short Styrka: Snabbt Element 40: Minnesadress = [arraystart+12] + 40 * 4 Svaghet: Kan inte ändra längd när den har skapats! Saknar metoder som add(), append(), remove(), … Object header: length [0] [1] [41] (data) 42 0 0 0 jonkv@ida Arrayer 8: Styrkor och svagheter Listor: Variabel storlek bekvämt att använda! Inget stöd i språket, men i klassbiblioteken För bättre förståelser för listor och generics: Vi visar en möjlig implementation Använder en array internt Måste byta ut arrayen när element läggs till 13 jonkv@ida Listor 1: Intro 14 public class StringList { private String[] elements; private int size; Använder en array för lagring! public StringList() { this.elements = new String[8]; this.size = 0; } Allokerar lite extra plats Hur många av platserna är använda? StringList strings = new StringList(); strings Object header: elements size (data) 0 Object header: length [0] [1] [7] (data) 8 jonkv@ida Listor 2: En listklass 15 public void add(String element) { elements[size] = element; size++; } StringList strings = new StringList(); strings.add("Hello"); strings Object header: elements size (data) 1 Object header: length [0] [1] (data) 8 [7] Vad händer när arrayen blir full? "Hello" jonkv@ida Listor 3: En listklass (forts.) public void add(String element) { if (size == elements.length) { int newsize = 2*size; String[] arr2 = new String[newsize]; System.arraycopy(…); this.elements = arr2; } elements[size] = element; size++; } 16 Är interna lagringen full? Skapa större array, kopiera innehållet, kasta bort gamla arrayen! jonkv@ida Listor 4: En listklass (forts.) public String get(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(); } else { return elements[index]; } } 17 Kolla index: Tillåt inte get(4) när size==2! jonkv@ida Listor 5: En listklass (forts.) 18 Effektiv representation – för de flesta operationer… public void insert(int index, E element) { if (size == elements.length) { … allocate more memory … } } System.arraycopy(elements, index, elements, index + 1, size - index); elements[index] = element; size++; A B C D E F G H list.add(2, "X"); A B C C D E F G H Kopiera – tar tid! A B X C D E F G H Stoppa in jonkv@ida Listor 6: Stoppa in element Vår listklass lagrar bara strängar! public class StringList { private String[] elements; private int size; … } Behöver vi en listklass för varje elementtyp? 20 jonkv@ida Elementtyper 1: Typspecifika listor? 21 public class ObjectList { Array av Object-pekare, private Object[] elements; kan peka på objekt av godtycklig klass private int size; public ObjectList() { this.elements = new Object[8]; this.size = 0; } public Object get(int index) { if (index >= 0 && index <size) { return elements[index]; } else /* Signal error */ } public void add(Object element) { if (size == elements.length) { /* Create a new array; copy old element */ } elements[size] = element; size++; } } jonkv@ida Elementtyper 2: Godtyckliga objekt 22 Nu får vi nya problem! 1: Ingen typsäkerhet när vi adderar element! ▪ Vill ha en lista där vi stoppar in strängar: ObjectList greetings = new ObjectList(); ▪ Kan lägga in strängar: greetings.add("hello"); ▪ Kan råka lägga in cirklar också – inget fel vid kompilering eller körning! greetings.add(new Circle(1, 1, 3)); public class ObjectList { public ObjectList() { … } public Object get(int index) { … } public void add(Object element) { … } } jonkv@ida Elementtyper 3: Problem 23 Problem 2: Ingen typinformation när vi hämtar element! ObjectList greetings = new ObjectList(); greetings.add("hello"); greetings.add(new Circle(1, 1, 3)); … String str = greetings.get(0); // Kompileringsfel String str = (String) greetings.get(0); // OK Vi måste tala om för kompilatorn: "Jag vet att jag la en sträng på position 0 – jag lovar!" Krävs en cast – extra arbete för oss public class ObjectList { public ObjectList() { … } public Object get(int index) { … } public void add(Object element) { … } } jonkv@ida Elementtyper 4: Problem Problem 3: Tänk om vi har fel! ObjectList greetings = new ObjectList(); greetings.add("hello"); greetings.add(new Circle(1, 1, 3)); for (int i = 0; i < greetings.size(); i++) { String str = (String) greetings.get(i); // Runtime error for i=1 – it’s a Circle! } Upptäcks inte när programmet kompileras 24 jonkv@ida Elementtyper 5: Problem void printMult3() { for (int i = 1; i <= 13; i++) { System.out.println(3 * i); } } void printMult5() { for (int i = 1; i <= 13; i++) { System.out.println(5 * i); } } void printMult(int num) { for (int i = 1; i <= 13; i++) { System.out.println(num * i); } } void printMult4() { for (int i = 1; i <= 13; i++) { System.out.println(4 * i); } } 26 num är en heltalsvariabel Kan ha värdet 3, 4, 5, 8, … void printMult8() { for (int i = 1; i <= 13; i++) { System.out.println(8 * i); } } jonkv@ida Vanliga parametrar till metoder class ListOfString { String[] elements; int length; {…} String get(int index) void add(String element) { … } } class MyList<E> { E[] elements; int length; E get(int index) void add(E element) } class ListOfCircle { Circle[] elements; int length; {…} Circle get(int index) void add(Circle element) { … } } 27 class ListOfShape { Shape[] elements; int length; {…} Shape get(int index) void add(Shape element) { … } } E är en typvariabel {…} {…} Kan ha värdet String, Shape, … class ListOfButton { Button[] elements; int length; {…} Button get(int index) void add(Button element) { … } } jonkv@ida Typparametrar till klasser 28 Generiska typer med typparametrar class MyList<E> { E[] elements; int length; E get(int index) void add(E element) } En array där elementen har typ E – verkliga typen är inte angiven än { return elements[index]; } { … } // Takes a parameter of type E Kan "instansieras" med olika typer som parameter MyList<String> – nästan exakt som: class MyList<String> { String[] elements; int length; {…} String get(int index) void add(String element) { … } } MyList<Shape> – nästan exakt som: class MyList<Shape> { Shape[] elements; int length; {…} Shape get(int index) void add(Shape element) { … } } jonkv@ida Generics 1: Intro class MyList<E> { E[] elements; int length; E get(int index) void add(E element) } 29 { return elements[index]; } {…} En lista där E=String: MyList<String> greetings = new MyList<String>(); greetings.add("hello"); // OK greetings.add(new Circle(1, 1, 3)); // Compile-time error: add(String) String str = greetings.get(0); // No cast needed: String get(int index) En lista där E=MyList<String> en lista av listor! MyList<MyList<String>> lists = new MyList<MyList<String>>(); lists.add(greetings); jonkv@ida Generics 2: Användningsexempel class MyList<E> { E[] elements; int length; E get(int index) void add(E element) } { return elements[index]; } {…} Mycket repetition: MyList<MyList<String>> listor = new MyList<MyList<String>>(); Syntaktiskt socker: Diamant-operatorn (betyder "samma som förut") MyList<MyList<String>> listor = new MyList<>(); DRY-principen: Don’t RepeatYourself! Regelbrott är WET: Write Everything Twice… 30 jonkv@ida Generics 3: Att skriva mindre class MyList<E> { E[] elements; int length; E get(int index) void add(E element) } { return elements[index]; } {…} Man kan använda en generisk typ utan att ange typparametrar: MyList listor = new MyList(); // Defaultvärde för E blir Object Enbart för kompatibilitet med gammal kod! ▪ Generics kom redan 2004 ▪ Gammal kod borde fortfarande gå genom kompilatorn, men med varningar ▪ Gör inte detta i ny kod! 31 jonkv@ida Generics 4: "Råa" typer Kallas generisk programmering, ger oss parametrisk polymorfism Samma namn (MyList) Olika beteende (beroende på typparameter) Jämför med subtypspolymorfism Samma metodnamn, flera implementationer inom en typhierarki Olika implementation väljs dynamiskt, beroende på verklig objekttyp 32 Jämför med ad-hoc-polymorfism (overloading) Samma metodnamn, flera implementationer i samma klass Olika implementation väljs statiskt, beroende på statiska parametertyper jonkv@ida Parametrisk polymorfism En typparameter måste ange en objekttyp! class List<E> { E[] elements; int length; E get(int index) void add(E element) } {…} {…} List<String> strings; // OK List<Button> buttons; // OK List<int> numbers; // Does not work! 34 …för egentligen skapas bara en klass! class List { Object[] elements; int length; {…} Object get(int index) void add(Object element) { … } } Kompilatorn tar hand om resten Sparar minne… men int är inget Object! jonkv@ida Typparametrar och objekttyper 35 Hur skapar vi en listklass som accepterar heltal? Implementera om strukturerna? class IntArrayList { private int[] elements; private int length; public int get(int index) { return elements[index]; } void add(int element) { … } } Repetera för 8 primitiva typer och för varje datastruktur Kan göras – finns färdiga bibliotek på nätet (GNU Trove, …) Använd wrappers! public class Integer { private final int value; public Integer(int value) { this.value = value; } public int intValue() { return value; } } Repetera för 8 primitiva typer klart jonkv@ida Wrappers 1: Intro Det finns en wrapper-klass för varje primitiv datatyp 36 jonkv@ida Wrappers 2: Wrapper-objekt 37 För att skapa wrapper-objekt: Kan använda vanlig konstruktor Number ten = new Integer(10); Number pi = new Double(3.14); Bättre: Använd statiska fabriksmetoden valueOf() Number ten = Integer.valueOf(10); Number pi = Double.valueOf(3.14); Sparar tid och minne: Återanvänder objekt för vanliga värden! public class Integer { public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); Fungerar för att wrappers är immutable: } Värden kan inte ändras } jonkv@ida Wrappers 3: Skapa Resulterar i objekt kan lagras i listor, objektpekare, … List<Number> numbers = new ArrayList<>(); numbers.add(Integer.valueOf(10)); numbers.add(Double.valueOf(3.14)); Det är BARA då vi behöver wrappers! Använd int, double, … i normalfallet! För att hämta ut värdet: Anropa typeValue() Number intobj int val0 = numbers.get(0); = intobj.intValue(); double val1 = numbers.get(1).doubleValue(); 38 jonkv@ida Wrappers 4: Användning Kan använda automatisk boxing och unboxing ("Paketinslagning") List<Number> numbers = new ArrayList<>(); numbers.add(10); numbers.add(3.14); double val1 = numbers.get(1); VARNING: Osynlig ineffektivitet! Kan skapa nya objekt Tar (lite) extra tid att plocka ut värden ur objekt Vissa rekommenderar explicit boxing / unboxing istället 39 jonkv@ida Wrappers 5: Användning int[] numbers = new int[] { 12, 14 ,16, 18, 20 } List<Integer> list = new ArrayList<>(); list.add(12); list.add(14); list.add(16); list.add(18); list.add(20); Array Object header: length [0] [1] [4] (data) 5 12 14 20 Wrappers ger mindre andel overhead om strukturerna är mer komplexa… 40 jonkv@ida Wrappers 6: Använder mer minne ArrayList Object header: size arr Object header: length [0] [1] [4] 5 Object header: value (data) Object header: value (data) (data) 12 (data) 14 5 Object header: value (data) 20 Python har inga primitiva typer, bara objekttyper Trevligare på ytan – slipper bry sig om skillnaden Vanliga heltal har metoder! ▪ >>> x = 10 ▪ >>> x.bit_length() 4 ▪ >>> x.__add__(10) 20 I Java: Kan välja mellan ▪ Primitiva typer – inte objekt, vissa begränsningar ▪ Wrapperklasser – är objekt, men långsammare, kräver mer minne 41 jonkv@ida Wrappers 7: Python? Java Collections Framework [email protected] – 2016 43 Collections Framework: Många sammansatta datastrukturer 1) Uppsättning gränssnitt för listor, köer, mängder, mappningar De viktigaste: Kom ihåg: Gränssnitt ger oss frihet att välja implementation! jonkv@ida Collections Framework 1: Intro 2) En uppsättning implementationer 44 jonkv@ida Collections Framework 2: Intro 3) Några hjälpklasser 45 jonkv@ida Collections Framework 3: Intro Collection<E>: Generell samling av objekt Vissa samlingar är ordnade ▪ Listor har ett första element – inte mängder Vissa tillåter dubblerade element ▪ Listor kan innehålla två identiska element – inte mängder 47 jonkv@ida Collection 1: Intro 48 Lägga till element: ▪ c.add(E) ▪ c.addAll(Collection) Testa innehåll: ▪ c.isEmpty(), c.size() ▪ c.contains(Object obj) ▪ c1.containsAll(Collection c2) – Alla element i c2 finns i c1? Hämta alla element: ▪ c.toArray() – En Object[ ] som innehåller samma element Ta bort element: ▪ c.clear() ▪ c.remove(Object) – Tar bort alla element jonkv@ida Collection 2: Grundläggande funktionalitet 49 List<E> extends Collection<E> Alltid ordnad: Element har index Implementeras av ▪ ArrayList – Mycket vanlig, implementation liknar våra tidigare exempel ▪ LinkedList – Ganska vanlig, andra egenskaper ▪ Stack, Vector – Använd inte, deprecated jonkv@ida List 1: Intro 50 Principen bakom länkade listor: LinkedList Object header: size first (data) 5 ListNode Object header: next prev value Object header: value (data) (data) 12 En extra listnod per element använder mer minne ListNode Object header: next prev value Object header: value (data) (data) 14 ListNode Object header: next prev value Object header: value (data) (data) 16 jonkv@ida Länkade listor (1) ListNode Object header: next prev value Snabbt att skjuta in / ta bort värden LinkedList Object header: size first (data) 5 ListNode Object header: next prev value Object header: value Object header: value (data) (data) 12 ListNode Object header: next prev value Object header: value (data) (data) 14 51 (data) (data) 15 ListNode Object header: next prev value Object header: value (data) (data) 16 jonkv@ida Länkade listor (2) 52 Tar lång tid att ta fram värde nummer n i listan LinkedList Object header: size first (data) 5 ListNode Object header: next prev value Object header: value (data) (data) 12 ListNode<E> get(int index) { ListNode<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } ListNode Object header: next prev value Object header: value (data) (data) 14 ListNode Object header: next prev value Object header: value (data) (data) 16 jonkv@ida Länkade listor (3) 53 Hämta / hitta element ▪ list.get(index) ▪ list.indexOf(Object needle), list.lastIndexOf(Object needle) ▪ Collections can hitta dellistor, göra binärsökning, hitta min/max-element Lägga till och ta bort ▪ list.add(E value) – ärvs från Collection! ▪ list.add(int index, E value) – flyttar element efter givet index ▪ list.addAll(int index, Collection c) ▪ list.remove(int index) Ändra element ▪ list.set(int index, E value) ▪ Collections kan söka/ersätta, fylla med ett värde, kopiera listor Omarrangera listor ▪ Collections kan blanda, sortera, rotera, reversera listor jonkv@ida List 2: Metoder 54 Arrayer används: För att implementera datatyper ArrayList måste använda en “primitiv” array När varje nanosekund spelar roll Bara efter CPU-profilering som visar att listhantering spelar roll Listor används: Nästan alltid! Många hjälpfunktioner tillgängliga Kan lätt lägga till och ta bort element, osv Används av många klasser i Javas klassbibliotek … När varje byte spelar roll Bara efter minnesprofilering… Ibland om storleken är fixerad Om storleken varierar: Låt listorna hantera detta! Tetrislabben använder arrayer eftersom Board-storleken är fixerad! jonkv@ida List 3: Listor vs. arrayer 55 Queue<E> extends Collection<E> Kan lägga till i slutet av kön Kan ta bort i början av kön Implementeras av ▪ ArrayDeque, LinkedList – grundläggande köstrukturer Varianter ▪ Deque: Även "på andra sidan" (Double-Ended QUEue) ▪ PriorityQueue – har element i sorterad ordning Vad händer om det är omöjligt? Operation Stoppa in element Ta bort element Se på första elementet Signalerar fel – exception add(e) remove() element() Returnerar speciellt värde offer(e) poll() peek() jonkv@ida Queue 1: Köer 56 Map<K,V> är Javas motsvarighet till dictionaries Associerar nycklar/keys K med värden V Vanlig klass, inte "språkfiness" mer att skriva >>> dict = {'a': 45, 'b': 39, 'c': 19} >>> dict['a'] 45 >>> dict['d'] = 4711 >>> dict {'a': 45, 'c': 19, 'b': 39, 'd': 4711} >>> len(dict) 4 ▪ TreeMap ▪ HashMap public static void main(String[] args) { Map<Character,Integer> dict = new HashMap<>(); dict.put('a', 45); dict.put('b', 39); dict.put('c', 19); System.out.println(dict.get('a')); // 45 dict.put('d', 4711); System.out.println(dict); // {a=45, b=39, c=19, d=4711} System.out.println(dict.size()); // 4 } – sorterar elementen, måste ange sorteringsordning – kräver hashkoder, förklaras i TDDD86 jonkv@ida Map: Mappningar Hur kan man iterera över alla element i en samling? Med en array eller ArrayList fungerar index utmärkt: static boolean contains(List<?> haystack, Object needle) { for (int i = 0; i < haystack.size(); i++) { if (haystack.get(i).equals(needle)) return true; } return false; } 58 jonkv@ida Iteration 1: Med index 59 Hur kan man iterera över alla element i en samling? Med en LinkedList fungerar index, men långsamt: static boolean contains(List<?> haystack, Object needle) { for (int i = 0; i < haystack.size(); i++) { if (haystack.get(i).equals(needle)) return true; } return false; } Node<E> get(int index) { Node<E> x = first; for (int j = 0; j < index; j++) x = x.next; return x; } get(0): get(1): get(2): get(3): get(4): … Gå genom element j=0 Gå genom element j=0, 1 Gå genom element j=0, 1, 2 Gå genom element j=0, 1, 2, 3 Gå genom element j=0, 1, 2, 3, 4 jonkv@ida Iteration 2: Med index Hur kan man iterera över alla element i en samling? Med en generell Collection (eller Set) finns inga index! static boolean contains(Collection<?> haystack, Object needle) { for (int i = 0; i < haystack.size(); i++) { if (haystack.get(i).equals(needle)) return true; } return false; } Vi är egentligen inte intresserade av index! Vi vill veta: Finns det fler element? Vad är nästa element? 60 jonkv@ida Iteration 3: Utan index 61 Lösning: Gränssnittet Iterator public interface Iterator<E> { public boolean hasNext(); public E next(); … } Finns det fler element? Vad är nästa element? static boolean contains(Iterator<?> haystack, Object needle) { while (haystack.hasNext()) { Specialsyntax: Object element = haystack.next(); Iterator för vilken elementtyp som helst if (element.equals(needle)) return true; Vet inte vilken elementtyp… men: } Det är i alla fall någon sorts Object! return false; } Har en egen implementation för varje datastruktur, eget sätt att hålla reda på "var vi är just nu" jonkv@ida Iteration 4: Iterator 62 Gränssnittet Iterable säger att objektet kan ge oss en iterator public interface Iterable<E> { public Iterator<E> iterator(); } Implementeras av Collections och arrayer, kan användas i for static boolean contains(Collection<?> haystack, Object needle) { for (Object element : haystack) { Loopen anropar haystack.iterator() if (element.equals(needle)) return true; } Anta haystack är LinkedList return false; } LinkedList.iterator() returnerar new LinkedListIterator(), som vet hur man int sum(int[] numbers) effektivt itererar över länkade listor for (int i : numbers) { … } } void printAll(List<String> greetings) { for (String str : greetings) { … } } jonkv@ida Iteration 5: Iterable och for(each)-loopar Om man ändrar en samling medan man itererar över den: ConcurrentModificationException Har inget att göra med multitrådning! static boolean contains(Iterable<?> haystack, Object needle) { for (Object element : haystack) { if (element.equals(needle)) return true; if (…) { ändra i haystack … } } return false; } jonkv@ida Iteration 6: ConcurrentModificationException 63 Iterator har en tredje metod package java.util; public interface Iterator<E> { public boolean hasNext(); public E next(); public void remove(); } Ta bort elementet som just returnerades av next() static void removeAllCopies(Iterable<String> haystack, Object needle) { Iterator<String> iter = haystack.iterator(); while (haystack.hasNext()) { String element = haystack.next(); if (element.equals(needle)) { iter.remove(); } } } Tas bort via iteratorn ingen ConcurrentModificationException 64 jonkv@ida Iteration 7: Ta bort element 65 jonkv@ida "Fortsättning" i nästa kurs Mer om datastrukturer: TDDD86 Datastrukturer, algoritmer och programmeringsparadigm, http://kdb5.liu.se/liu/lith/studiehandboken/svkursplan.lasso?&k_budget_year=2016&k_ku rskod=TDDD86