-
Notifications
You must be signed in to change notification settings - Fork 0
Java and co
Pour récupérer seulement quelques champs via Spring Data JPA, on peut utiliser les projections
https://docs.spring.io/spring-data/jpa/reference/repositories/projections.html
(soit en déclarant des interfaces, soit en déclarant des records)
Doc pour construire les requêtes https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html
@EntityGraph allows you to define a graph of entities that should be fetched from the database in a single selection for a specific use case. We can define an EntityGraph on the repository method to eagerly fetch the required associations. This makes sure the data is already loaded when the session is open, preventing the LazyInitializationException. Yet, we preserve the benefits of lazy loading, since we have complete control over when the eager fetch is applied.
source : https://www.tomaszezula.com/optimizing-eager-fetch-with-spring-data-and-entitygraph-annotation/
But : stocker des données pour les traitements effectués dans un thread
Bien penser à déclarer la variable ThreadLocal en static (question de perf) et à nettoyer après
Pour valider des données (par exemple en entrée d'un controleur Rest ou d'un consumer Kafka), on peut ajouter des annotations sur le DTO. Il existe certaines annotations pré codées (@NotNull par exemple) mais il est possible d'en coder des spécifiques avec une classe implémentant ConstraintValidator
Si on une liste d'objets sur lesquels on veut faire des assertions, par exemple une liste de livres, on peut faire
assertThat(books)
.extracting(Book::getTitle, Book::getLanguage, Book::getAuthor)
.containsExactlyInAnyOrder(
tuple("LoTR","English","JRR Tolkien"),
tuple("La nuit des temps", "French", "Barjavel"));
Si on doit vérifier qu'un message fait partie d'une liste (cas d'un message s'affichant en français en local et en anglais sur la pic), on peut utiliser
assertThat(result)
.extracting(result::getMessage)
.singleElement()
.satisfies(
m ->
assertThat(m)
.containsAnyOf(taille)
.containsAnyOf(taille, "la taille doit être", "size must be"));
// "taille" en local sur PC français et "size" sur PIC
https://ivan.canet.dev/blog/2024/10/07/flee-throwable.html
https://medium.com/@wakefulinsomnia/how-does-java-classloader-system-work-82eaf378f73b
https://advancedweb.hu/a-categorized-list-of-all-java-and-jvm-features-since-jdk-8-to-21/
https://javaconceptoftheday.com/java-9-try-with-resources-improvements/ (d'autres pages expliquant les changements entre une version et une autre)
https://inside.java/2025/01/28/jvm-start-up/
https://www.youtube.com/@JakobJenkov
https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Record.java
https://nipafx.dev/#channels~~articles dev at Oracle (or at least publish videos on official Java YT channel)
Validation dans un builder https://softwareengineering.stackexchange.com/questions/241309/builder-pattern-when-to-fail/241319#241319
Pour cela on va utiliser une des méthodes de Executors, par exemple newFixedThreadPool si on souhaite avoir un pool de thread fixe.
On va utiliser soit du Callable soit du Runnable. Puis on va utiliser la méthode submit pour lui passer notre code.
Il faut bien penser à supprimer le pool de thread à l'extinction de l'application, sinon la JVM ne va pas s'arrêter.
Certaines variables ne sont pas partagées entre les différents threads.
Mockito possède une méthode timeout qui permet d'attendre qu'une méthode soit appelée.
Aller jeter un oeil dans les classes du package java.util.concurrent
Pour debugger un erreur 400 bad request sur un controller Spring, passer en debug les logs de org.springframework.web.servlet.mvc.method.annotation
Stack memory : variables locales, appels de méthodes, références de données (si plein : stack overflow). Allocation statique. Valeurs primitives. N'existe que le temps de l'exécution d'une méthode. Propre à un seul thread.
Heap memory : new objets et données dynamiques au run time, pool de strings, stockage de données. Différentes générations (young, old, permanent) Si plein : out of memory. Nettoyé par GC. Partagée entre les différents threads.
Heap Size > Stack size
heap : zone sans ordre alors que stack : LIFO (permet de faire de la récursivité) https://www.baeldung.com/java-memory-management-interview-questions + https://javamidnight.blogspot.com/2017/11/la-difference-entre-la-memoire-heap-et.html
Meta Space : pour stocker les méta données. Sa taille peut varier (au contraire de la heap). Remplace la permanent generation depuis Java 8.
Une fuite mémoire est présente quand des objets sont encore présents dans la heap mais ne sont plus utilisés et ne sont pas nettoyés par le GC (conséquence finale : OutOfMemory Error). GC nettoie que les objets qui ne sont plus référencés.
Parmi les causes, on a les champs static, les ressources non fermées (streams, connexions => bien fermer dans les finally ou faire un try with resources). On a aussi une mauvaise implémentation de hashcode/equals qui va empêcher certains caches de fonctionner comme prévu ou bien une mauvaise utilisation des ThreadLocals
https://www.baeldung.com/java-memory-leaks
Hashcode permet d'être plus performant (surtout si on a beaucoup de champs à comparer dans le equals) car comparaison d'entiers plutôt que champs à champs. Si deux objets sont égaux alors ils doivent avoir le même hashcode (réciproque fausse)
https://codegym.cc/fr/groups/posts/fr.264.methodes-equals-et-hashcode-bonnes-pratiques
Checked exception : celles qu'on va vérifier avec les try/catch (ex : FileNotFound). Erreurs "attendues". (super classe : Exception) Vérifiées à la compilation.
Unchecked exception : erreurs inatendues, type NullPointer (super classe : RuntimeException)
Le mot clé synchronize a deux rôles :
- il empêche deux threads de modifier une donnée en même temps
- il prévient l'ensemble des threads qu'une donnée a été modifiée
=> besoin de synchroniser la lecture ET l'écriture
Le mot clé volatile ne gère pas l'exclusion mutuelle. Il assure qu'un thread va bien lire la version la plus à jour d'une donnée.
i++ n'est pas thread safe car il y a deux opérations en une (une lecture de i et une écriture de i)
Pour générer des images Docker sans dockerfile : https://github.com/GoogleContainerTools/jib