Studiewijzer module 02
Design Patterns and Principles
Deze samenvatting is geschreven door Aron Kool tijdens het leren voor het OCP examen. Hij gaf geen garanties over de juistheid van deze samenvatting.
Algemeen
-
null instanceof Objectlevertfalseop. Compileert dus wel en geeft geenNullPointerException. -
FunctionalInterfaceis altijd een interface met exact 1abstracte methode. -
Volgens OCP heeft Composition altijd de voorkeur boven inheritance
-
java.util.Comparatorheeft de methodeint compare(T o1, To2) -
java.lang.Comparableheeft de methodeint compareTo(T o) -
Classes als
OptionalInthebben een methodegetAsInt()deze geeft een primitieveintterug -
Classes als
IntStreamgeven bij methodes alsmin()ofmax()eenOptionalIntterug. Omdat deze bij een lege lijst geen waarde opleveren geven ze dus eenOptionalIntterug. -
ThreadimplementsRunnable. -
Een
peek()op een stream is niet terminating, dus zonder een terminating methode zoalscollect()doet depeek()niets.
Collections
ArrayDeque
-
add(e)voegt toe aan het einde -
offer(e)voegt toe aan het einde -
push(e)voegt toe aan het begin -
remove()verwijdert en get aan het begin -
poll()verwijdert en get aan het begin -
pop()verwijdert en get aan het begin -
element()get aan het begin, laat element in collection -
peek()get aan het begin, laat element in collection
Map
De merge(key,value,BiFunction<V,V,V>) methode in een map werkt als
volgt:
-
Bestaat de key niet, dan wordt value gezet voor die key
-
Bestaat de key wel, dan gaat de oude value en de nieuwe value in de
BiFunctionen het resultaat wordt gezet voor de key
Generics
Simpel voorbeeldje voor de ? extends … en de ? super …:
List<? extends Number> foo3 = new ArrayList< Number >(); // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList< Integer >(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList< Double >(); // Double extends Number
List<? super Integer> foo3 = new ArrayList< Integer >(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList< Number >(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList< Object >(); // Object is a superclass of Integer
DateTime
-
Duration gaat over tijd (seconden, minuten, uren)
-
Period gaat over datums (days, months, years)
-
Duration.ofMinutes(1).equals(Duration.ofSeconds(60)); = true
-
Duration heeft wel een ofDays methode die 24 uur representeert.
-
Period.ofDays(7).equals(Period.ofWeeks(1)); = true
-
Period.ofDays(365).equals(Period.ofYears(1)); = false
Functional Interfaces
Consumer<T>-
Represents an operation that accepts a single input argument and returns no result.
BiConsumer<T,U>-
Represents an operation that accepts two input arguments and returns no result.
Supplier<T>-
Represents a supplier of results.
Function<T,R>-
Represents a function that accepts one argument and produces a result.
BiFunction<T,U,R>-
Represents a function that accepts two arguments and produces a result.
Predicate<T>-
Represents a predicate (boolean-valued function) of one argument.
BiPredicate<T,U>-
Represents a predicate (boolean-valued function) of two arguments.
UnaryOperator<T>-
Represents an operation on a single operand that produces a result of the same type as its operand.
BinaryOperator<T>-
Represents an operation upon two operands of the same type, producing a result of the same type as the operands.
Exceptions
Closable en Autoclosable
Closable-
void close() throws IOException Autoclosable-
void close() throws Exception
De close wordt in het geval van een try-with-resource aangeroepen in het 'magische' finally-block. Dit zorgt voor een verschil in de afhandeling ten opzicht van Closable:
-
Als zowel de try als de handmatige
close()een exception gooien, wordt de exceptie uit de try gesuppressed. -
Als zowel de try als de
close()van eenAutoClosablein een try-with-resource een exception gooien, wordt de exceptie uit declose()gesuppressed.
Binnen de try met auto closables, moet iedere constructor die een exception kan gooien, los gedefinieerd worden, omdat er een referentie naar het autocloseable object nodig is om deze te kunnen closen. Dus niet:
try(InputStream i = new ObjectInputStream(new FileInputStream())) { // (1)
}
-
Er is geen referentie naar de
FileInputStreamdus die kan niet automatisch geclosed worden
Concurrency
CyclicBarrier
Een CyclicBarrier laat threads wachten op andere threads. Dit is een handige manier om bijvoorbeeld threads tegelijkertijd te laten beginnen.
Een CyclicBarrier maak je aan via:
CyclicBarrier barrier = new CyclicBarrier(2); // (1)
... doe werk ...
barrier.await(); // (2)
-
Het constructor argument
2is het aantal threads die de Barrier moeten passeren om verder te gaan. -
laat de thread wachten totdat het aantal wachtende threads voor deze barrier de ingestelde limiet bereikt heeft. Alle wachtende threads worden daarna vrijgegeven.
Om live- en deadlocks te voorkomen kun je een timeout meegeven aan de
barrier: barrier.await(10, TimeUnit.SECONDS);
De CyclicBarrier#await(timeout, unit) kan de volgende exceptions
gooien (overgenomen vanuit de JavaDoc):
InterruptedException-
if the current thread was interrupted while waiting
TimeoutException-
if the specified timeout elapses. In this case the barrier will be broken.
BrokenBarrierException-
if another thread was interrupted or timed out while the current thread was waiting, or the barrier was reset, or the barrier was broken when
awaitwas called, or the barrier action (if present) failed due to an exception
ExecutorService
De class Executors is een factory voor executor services. Hiermee
kunnen eenvoudig Runnables en Callables uitgevoerd worden. Een
executor service is eigenlijk een thread pool of een object die het
uitvoeren van meerdere taken tegelijkertijd beheert, zoals hoeveel er
tegelijkertijd plaats kunnen vinden.
Voorbeelden hoe je een ExecutorService aanmaakt:
ExecutorService executorService1 = Executors.newSingleThreadExecutor(); // 1
ExecutorService executorService2 = Executors.newFixedThreadPool(10); // 2
ExecutorService executorService3 = Executors.newScheduledThreadPool(10); // 3
De FixedScheduledThreadPool lijkt op de ScheduledThreadPool. De laatste heeft de mogelijkheid om taken pas uit te voeren na een gespecificeerde tijd.
De methode execute() accepteert alleen een Runnable.
De methode submit() accepteert zowel een Runnable als een
Callable.
Callable heeft een generic, welke de methode call() throws Exception, returned. Runnable is een void
De Execute() is een Void. De submit() levert een Future op. Via future.get() kun je de resultwaarde opvragen. Voor Runnable is dit null, zodra de taak klaar is, voor Callable is dit het geretourneerde object.
Als je klaar bent met de ExecutorService moet je de ExecutorService.shutdown() aanroepen. Deze zorgt ervoor dat er geen nieuwe executes/submits meer geaccepteerd worden. Alles wat al bezig is, gaat gewoon door.
|
Note
|
De combinatie tussen een FixedThreadPool en een CyclicBarrier waarbij de ThreadPool kleiner is dan de Barrier, levert een Deadlock op omdat de Barrier te threads vasthoudt! |
ForkJoinTask
Een ForkJoinTask maak je aan via een JoinForkPool welke je aanmaakt als: ForkJoinPool pool = new ForkJoinPool(numberOfProcessors); of Executors.newWorkStealingPool(numberOfProcessors);.
ForkJoinPool is een implementatie van ExecutorService. Er is een extra submit(ForkJoinTask) en execute(ForkJoinTask).
In OCP komen de subclasses RecursiveTask<T> en RecursiveAction aan bod. RecursiveAction is in principe een RecursiveTask, maar dan zonder return type.
De methode die verplicht geimplementeerd moet worden is public T compute(). De inhoud is vergelijkbaar met een Runnable of een Callable behalve een recursieve toevoeging, wat meestal hier op neerkomt:
protected List< Integer > compute()
{
List< VoorbeeldTask > subTasks = new ArrayList<>();
List< Integer > result = new ArrayList<>();
if(zwareTaak.size()==1)
{
result.add(doeZelf(zwareTaak.remove(0)));
}
else
{
VoorbeeldTask subTask1 = new VoorbeeldTask(eersteHelft(zwareTaak));
VoorbeeldTask subTask2 = new VoorbeeldTask(tweedeHelft(zwareTaak));
subTask1.fork(); // (1)
subTask2.fork(); // (1)
subTasks.add(subTask1);
subTasks.add(subTask2);
}
for(VoorbeeldTask task : subTasks)
{
result.addAll(task.join()); // (2)
}
return result;
}
-
De
forkmethode laat dus een subtaak draaien met daarin een deelprobleem. De later aangeroepenjoin()geeft het resultaat van de subtaken terug en voegt dat bij het eigen resultaat. -
De
submitmethode op de Pool geeft in dit geval ook zelf een taak terug (wat in principe gewoon eenfork()is). Om het eindresultaat te bekijken, kun je hierop eenjoin()aanroepen.
ForkJoinTask< List< Integer > > task = pool.submit(new VoorbeeldTask(beginProbleem));
List< Integer > result = task.join();
Concurrent Collections
-
ConcurrentHashMapis een map met synchronized mutatiemethoden. DeConcurrentHashMapgeeft nog steeds eenConcurrentModificationExceptionbij aanpassen tijdens het itereren. -
CopyOnWriteArrayListgeeft iedere lezer een eigen lijst van de huidige status. EenConcurrentModificationExceptionkan hierbij dus niet optreden. Het schrijven naar de lijst heeft wel een lock. Hetzelfde geldt voor deCopyOnWriteArraySet. -
ConcurrentSkipListSetgarandeert sortering en is de threadsafe equivalent van deTreeSet. Er bestaat ook eenConcurrentSkipListMap.
Java IO
Serialisatie
-
ObjectInputStream, welke in de constructor een(File)InputStreammeekrijgt, heeft een methodereadObject()waarmee je een Object op kunt vragen. -
ObjectOutputStream, welke in de constructor een (File)OutputStream meekrijgt, heeft een methodewriteObject()waarmee je een Object weg kunt schrijven. -
Deserialisatie zet de state terug in het object zoals het was, daarbij wordt dus geen constructor of andere initialiserende code aangeroepen.
-
Deserialisatie levert een
Objectop, die je zelf nog moet casten. Dit komt omdat tijdens deserialisatie je een ander type object terug kan geven dan in de stream staat. Het type dat teruggegeven wordt is dus op compilatie tijd niet bekend en kan niet opgenomen worden als return type of via generics getypeerd worden.
Mark, reset, skip
InputStream heeft onder andere de methoden mark(), reset() en
skip().
-
Skip(n)slaat de eerst volgendenbytes over -
Mark(readlimit)markeert de huidige cursor, het limit is om de mark te invalideren naxaantal bytes (en heeft dus niets te maken met de plaats van de mark). -
Reset()zet de cursor terug op de plaats van de eerder gemaakte mark. Als er geen geldige mark meer is, wordt er eenIOExceptiongegooid.
Niet iedere stream heeft ondersteuning voor marks
NIO2
-
Files.lines()levert eenStream<String>op. -
Files.readAllLines()levert eenList<String>op. -
Files.isSameFile(p1,p2)controleert of er echt naar hetzelfde pad gewezen wordt. Er wordt dus niet gecontroleerd of een bestand identiek is. -
In het geval van een
isSamePath()geeft deequals()ook eentrueterug.
Normalize
The normalize method removes any redundant elements, which includes any "." or "directory/.." occurrences. Both of the preceding examples normalize to /home/joe/foo.
It is important to note that normalize doesn’t check at the file system when it cleans up a path. It is a purely syntactic operation. In the second example, if sally were a symbolic link, removing sally/.. might result in a Path that no longer locates the intended file.
Relativize
-
Path p1 = Paths.get("home");
-
Path p3 = Paths.get("home/sally/bar");
-
// Result is sally/bar
-
Path p1_to_p3 = p1.relativize(p3);
-
// Result is ../..
-
Path p3_to_p1 = p3.relativize(p1);
Find
Files.find(start, maxDepth, matcher, options). De MaxDepth is om
lussen de voorkomen bij symbolic links.
De FileVisitOptions kunnen alleen een FOLLOW_LINKS zijn.
In tegenstelling tot de find() uit java.io.File is de matcher geen
Predicate< File >, maar een BiPredicate< Path, BasicFileAttributes
>.
JDBC
Een JDBC 4+ Driver heeft altijd het bestand:
META-INF/services/java.sql.Driver.
Bij JDBC <4, moest altijd een eerste classloader-aanroep gedaan worden
naar de Driver. Bijvoorbeeld:
Class.forName("oracle.jdbc.driver.OracleDriver").
Statement
-
execute(sql)geeft een boolean terug, met true als het resultaat een resultset is, false als het een updatecount is. -
executeUpdate(sql)geeft het aantal rijen terug dat geüpdated is. -
executeQuery(sql)geeft eenResultSetterug. -
execute(sql)kan voor zowelSELECTalsCUD-queries gebruikt worden. De anderen gooien eenSQLExecptionbij verkeerd gebruik.
Resultset
-
CONCUR_READ_ONLY: The ResultSet object cannot be updated using the ResultSet interface. -
CONCUR_UPDATABLE: The ResultSet object can be updated using the ResultSet interface. -
TYPE_FORWARD_ONLY: The result set cannot be scrolled; its cursor moves forward only, from before the first row to after the last row. The rows contained in the result set depend on how the underlying database generates the results. That is, it contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved. -
TYPE_SCROLL_INSENSITIVE: The result can be scrolled; its cursor can move both forward and backward relative to the current position, and it can move to an absolute position. The result set is insensitive to changes made to the und
« Vorige module Volgende module »