Guava et Lombok au Bordeaux JUG
-
Upload
thierryler -
Category
Design
-
view
8.211 -
download
0
Transcript of Guava et Lombok au Bordeaux JUG
![Page 1: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/1.jpg)
Milou fait un régime Guava - Lombok
![Page 2: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/2.jpg)
SPONSORS
![Page 3: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/3.jpg)
Thierry Leriche-Dessirier
icauda.com
Consultant JEE freelance Professeur de Génie Logiciel à l’ESIEA Rédacteur pour Programmez Rédacteur pour Developpez.com
@thierryleriche
![Page 4: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/4.jpg)
Cours
FAQ
Interviews
Articles / tutoriels
Magazine
Forums
News
Agendas
Critiques
![Page 5: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/5.jpg)
13 OOO OOO pages vues par mois
5 500 000 visites par mois
2 500 000 visites uniques par mois
5 000 messages forum par jour
![Page 6: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/6.jpg)
Age
nd
a
Milou est trop lourd (intro)
Lombok (et Lombok-pg) en action
Tour d’horizon de Guava
![Page 7: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/7.jpg)
Milou est trop lourd (et doit faire un régime)
I am Milou
![Page 8: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/8.jpg)
public class Dog {
private Integer id ;
private String name ;
private String fullName ;
private SexeEnum sex ;
private Date birthday ;
private String race ;
private Boolean lof ;
private Double weight ;
private Double size ;
private List<String> colors ;
...
DO
G
5
![Page 9: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/9.jpg)
id
name
fullName
sex
birthday
race
lof
weight
size
Colors
Constructeurs Getters / setters toString () equals () hashCode () compareTo ()
![Page 10: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/10.jpg)
clic clic démo
id
name
fullName
sex
birthday
race
lof
weight
size
Colors
Constructeurs Getters / setters toString () equals () hashCode () compareTo ()
![Page 11: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/11.jpg)
public class Dog
implements Comparable<Dog> {
...
@Override
public int compareTo(Dog other) {
int result = 0;
result = name.compareTo(other.name);
if (result != 0) {
return result;
}
...
}
Code très limite… NPE ?...
![Page 12: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/12.jpg)
id
name
fullName
sex
birthday
race
lof
weight
size
Colors
Constructeurs Getters / setters toString () equals () hashCode () compareTo ()
210 lignes 10 attributs
![Page 13: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/13.jpg)
210 lignes de code
10 attributs
Java
![Page 14: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/14.jpg)
Va
cher
cher
Gu
ava
toString () equals () hashCode () compareTo ()
Commons FAQ 1-2
![Page 15: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/15.jpg)
Base
Objects
![Page 16: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/16.jpg)
public String toString() {
return "Dog [id=" + id
+ ", name=" + name
+ ", fullName=" + fullName
+ ", sex=" + sex
+ ", birthday=" + birthday
+ ", race=" + race
+ ", lof=" + lof
+ ", weight=" + weight
+ ", size=" + size
+ ", colors=" + colors + "]";
}
Java
5
5
toString ()
Simple, efficace et bien pourri
![Page 17: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/17.jpg)
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(Dog.class.getSimpleName())
.append("[id=").append(id)
.append(", name=").append(name)
.append(", fullName=").append(fullName)
...
.append(", colors=").append(colors);
return sb.toString();
}
Java
5
5
toString ()
Mieux mais sans plus
![Page 18: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/18.jpg)
public String toString() {
return Objects.toStringHelper(this)
.add("id", id)
.add("name", name)
.add("fullName", fullName)
...
.add("colors", colors)
.toString();
}
Gu
ava
G
toString ()
Builder
![Page 19: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/19.jpg)
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Dog other = (Dog) obj;
if (birthday == null) {
if (other.birthday != null) return false;
} else if (!birthday.equals(other.birthday)) return false;
if (fullName == null) {
if (other.fullName != null) return false;
...
} else if (!race.equals(other.race)) return false;
if (sex != other.sex) return false;
return true;
}
Java
5
5
equals ()
birthday, fullname, name, race et sex
Carrément illisible
![Page 20: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/20.jpg)
public boolean equals(Object obj) {
if (!(obj instanceof Dog)) return false;
Dog other = (Dog) obj;
return Objects.equal(birthday, other.birthday)
&& Objects.equal(fullname, other.fullname)
&& Objects.equal(name, other.name)
&& Objects.equal(race, other.race)
&& sex == other.sex;
}
Gu
ava
G
equals ()
birthday, fullname, name, race et sex
![Page 21: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/21.jpg)
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((birthday == null) ? 0 : birthday.hashCode());
result = prime * result
+ ((fullName == null) ? 0 : fullName.hashCode());
result = prime * result
+ ((name == null) ? 0 : name.hashCode());
result = prime * result
+ ((race == null) ? 0 : race.hashCode());
result = prime * result
+ ((sex == null) ? 0 : sex.hashCode());
return result;
}
Java
5
5
hashCode ()
birthday, fullname, name, race et sex
![Page 22: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/22.jpg)
public int hashCode() {
return Objects.hashCode(birthday, fullName,
name, race, sex);
}
Gu
ava
G
hasCode()
birthday, fullname, name, race et sex
![Page 23: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/23.jpg)
public int compareTo(Dog other) {
int result = 0;
result = name.compareTo(other.name);
if (result != 0) {
return result;
}
result = fullname.compareTo(other.fullname);
if (result != 0) {
return result;
}
...
}
Java
5
5
compareTo ()
name, fullname, birthday, weight, size, race et sex
![Page 24: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/24.jpg)
name.compareTo(other.name)
compareTo ()
other.name.compareTo(name)
Vs
![Page 25: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/25.jpg)
public int compareTo(Dog other) {
return ComparisonChain.start()
.compare(name, other.name)
.compare(fullName, other.fullName)
.compare(birthday, other.birthday)
.compare(weight, other.weight)
.compare(size, other.size)
.compare(race, other.race)
.compare(sex, other.sex)
.result();
}
Gu
ava
G
compareTo ()
name, fullname, birthday, weight, size, race et sex
![Page 26: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/26.jpg)
Lom
bo
k
en action
![Page 27: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/27.jpg)
Régime
Annotations de base
![Page 28: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/28.jpg)
@NoArgsConstructor / @RequiredArgsConstructor / @AllArgsConstructor constructeurs
@Getter / @Setter @ToString @EqualsAndHashCode @Data @Getter + @Setter + @ToString +
@EqualsAndHashCode + @RequiredArgsConstructor
Ré
gim
e
![Page 29: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/29.jpg)
clic clic démo
Ré
gim
e
@NoArgsConstructor / @RequiredArgsConstructor / @AllArgsConstructor
@Getter / @Setter @ToString @EqualsAndHashCode @Data
![Page 30: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/30.jpg)
210 lignes de code
10 attributs
Java
12 lignes + 2-3 @ + compareTo() Lombok
![Page 31: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/31.jpg)
name, sex
@RequiredArgsConstructor(staticName = "of")
public class Dog {
private Integer id;
@NonNull private String name;
private String fullName;
@NonNull private SexeEnum sex;
private Date birthday;
...
Dog dog = Dog.of("Milou", MALE);
Fact
ory
L
![Page 32: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/32.jpg)
name, sex
private Dog(@NonNull final String name,
@NonNull final SexeEnum sex) {
if (name == null) throw new NullPointerException("name");
if (sex == null) throw new NullPointerException("sex");
this.name = name;
this.sex = sex;
}
public static Dog of(@NonNull final String name,
@NonNull final SexeEnum sex) {
return new Dog(name, sex);
}
@RequiredArgsConstructor(staticName = "of")
public class Dog {
private Integer id;
@NonNull private String name;
private String fullName;
@NonNull private SexeEnum sex;
private Date birthday;
...
Dog dog = Dog.of("Milou", MALE);
Fact
ory
L
![Page 33: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/33.jpg)
Trucs pratiques
Se simplifier la vie
![Page 34: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/34.jpg)
@Cleanup @Synchronized @SneakyThrows @Log @Delegate
val P
rati
qu
e
![Page 35: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/35.jpg)
public void lireJava6(String from) {
InputStream in = null;
try {
in = new FileInputStream(from);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1)
break;
...
}
} catch (Exception e) {
...
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
...
}
}
...
Re
sso
urc
es 5
![Page 36: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/36.jpg)
public void lire(String from) throws IOException {
@Cleanup
InputStream in = new FileInputStream(from);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1)
break;
...
}
} Re
sso
urc
es L
![Page 37: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/37.jpg)
Délombok
Revenir sans la lib
![Page 38: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/38.jpg)
Dé
lom
bo
k <properties> <lombok.sourceDirectory>
${project.basedir}/src/main/java
</lombok.sourceDirectory>
...
<build>
<groupId>org.projectlombok</groupId>
<artifactId>maven-lombok-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
</execution>
</executions>
...
mvn lombok:delombok
java -jar lombok.jar delombok src -d src-delomboked
XML
![Page 39: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/39.jpg)
Dé
lom
bo
k @Data public class Dog {
private Integer id;
private String name;
private String fullName;
private SexeEnum sex;
private Date birthday;
private String race;
private Boolean lof;
private Double weight;
private Double size;
private List<String> colors;
}
5 public class Dog {
private Integer id;
private String name;
private String fullName;
...
private List<String> colors;
public DogLombok() {
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (o == null) return false;
if (o.getClass() != this.getClass()) return false;
final Dog other = (Dog)o;
if (this.getId() == null ? other.getId() != null : !this.getId().equals(other.getId())) return false;
...
@java.lang.Override
@java.lang.SuppressWarnings("all")
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = result * PRIME + (this.getId() == null ? 0 : this.getId().hashCode());
result = result * PRIME + (this.getName() == null ? 0 : this.getName().hashCode());
mvn
lombok:delombok
5
![Page 40: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/40.jpg)
Lombok-pg
Annotations supplémentaires
![Page 41: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/41.jpg)
@Action @Function @EnumId @Rethrow / @Rethrows @Singleton @AutoGenMethodStub @BoundPropertySupport / @BoundSetter @DoPrivileged @ExtensionMethod @ListenerSupport @WriteLock / @ReadLock @Await / @Signal / @AwaitBeforeAndSignalAfter @Sanitize.Normalize / .With @SwingInvokeLater / @SwingInvokeAndWait @Validate.NotEmpty / .NotNull / .With @VisibleForTesting
An
no
tati
on
s P
g @Builder @LazyGetter @FluentSetter @Predicate
![Page 42: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/42.jpg)
@FluentSetter
@Getter
public class Dog {
private Integer id ;
private String name ;
private String fullName ;
...
DogLombok dog = new DogLombok();
dog.name("Milou").sex(MALE);
Flu
en
t
println( dog.getName()); // Milou
println( dog.getSex()); // MALE
L
![Page 43: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/43.jpg)
@Builder
@Getter
public class Dog {
private Integer id ;
private String name ;
private String fullName ;
...
Dog dog = Dog.dog().name("Milou").sex(MALE).build();
Bu
ilde
r
println( dog.getName()); // Milou
println( dog.getSex()); // MALE
L
![Page 44: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/44.jpg)
@ExtensionMethod({ Dog.class, MyDogExtensionClass.class })
public class DogWithExtension {
public void foo() {
Dog milou = new Dog("Milou", 12.5, ...);
boolean isTooFat = milou.isTooFat();
}
}
exte
nsi
on
L
Avec paramètres FAQ 9
http://blog.developpez.com/todaystip/p11165/dev/java/extensionmethod-de-lombok-pg/
class MyDogExtensionClass {
public static boolean isTooFat(final Dog dog) {
double imc = dog.getWeight() / pow(dog.getSize(), 2);
return 31 < imc;
}
}
![Page 45: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/45.jpg)
Lombok or not Lombok ?
Avantages et inconvénients
![Page 46: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/46.jpg)
Pro
/ C
on
s
Byte code modifié Version en 0.x Documentation des prog ? Magique ?
Compacité Lecture simplifiée Code normée Délombok (pour essayer)
![Page 47: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/47.jpg)
Gu
ava
tour d’horizon
![Page 48: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/48.jpg)
Factory Methods
Les choses que j’aime
![Page 49: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/49.jpg)
List<Integer> primeNumbers = new ArrayList<Integer>();
Set<String> colors = new TreeSet<String>();
Map<String, Integer> ages = new HashMap<String, Integer>(); Java
5
5 < new Vs static factories >
![Page 50: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/50.jpg)
Java
5
Map<String, List<String>> trucs =
new HashMap<String, List<String>>();
Map<? extends Person, Map<String, List<String>>> trucs =
new TreeMap<? extends Person, Map<String, List<String>>>();
Map<? extends Wrapper<String, Sex, Person>, Map<String,
List<Set<Adress<String, Integer, Country>>>>> trucs = ...
du
r d
ur
?
5
List<Integer> primeNumbers = new ArrayList<Integer>();
Set<String> colors = new TreeSet<String>();
Map<String, Integer> ages = new HashMap<String, Integer>(); 5
< new Vs static factories >
![Page 51: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/51.jpg)
Java
5
List<Integer> primeNumbers = new ArrayList<>();
Set<String> colors = new TreeSet<>();
Map<String, Integer> ages = new HashMap<>(); Java
7
Qui utilise Java 7 en prod ?
7
List<Integer> primeNumbers = new ArrayList<Integer>();
Set<String> colors = new TreeSet<String>();
Map<String, Integer> ages = new HashMap<String, Integer>(); 5
< new Vs static factories >
![Page 52: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/52.jpg)
Java
5
Java
7
Qui utilise Java 7 en prod ?
List<Integer> primeNumbers = newArrayList();
Set<String> colors = newTreeSet();
Map<String, Integer> ages = newHashMap(); Gu
ava
Dès maintenant !
G
List<Integer> primeNumbers = new ArrayList<>();
Set<String> colors = new TreeSet<>();
Map<String, Integer> ages = new HashMap<>();
List<Integer> primeNumbers = new ArrayList<Integer>();
Set<String> colors = new TreeSet<String>();
Map<String, Integer> ages = new HashMap<String, Integer>(); 5
7
< new Vs static factories >
![Page 53: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/53.jpg)
Java
5
Java
7
Qui utilise Java 7 en prod ?
List<Integer> primeNumbers = newArrayList();
Set<String> colors = newTreeSet();
Map<String, Integer> ages = newHashMap(); Gu
ava
Dès maintenant !
G
List<Integer> primeNumbers = new ArrayList<>();
Set<String> colors = new TreeSet<>();
Map<String, Integer> ages = new HashMap<>();
List<Integer> primeNumbers = new ArrayList<Integer>();
Set<String> colors = new TreeSet<String>();
Map<String, Integer> ages = new HashMap<String, Integer>(); 5
7
var primeNumbers = new ArrayList<Integer>();
-> primeNumbers.size();
...
Lom
bo
k
< new Vs static factories >
L
![Page 54: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/54.jpg)
List<Dog> dogs = newArrayList(
new Dog("Milou", 12.5, MALE, ...),
new Dog("Rintintin", 45.0, MALE, ...),
new Dog("Volt", 10.3, MALE, ...),
new Dog("Lassie", 45.0, FEMALE, ...),
new Dog("Pluto", 22.0, MALE, ...),
new Dog("Medor", 35.6, MALE, ...));
List
of
do
gs
G
[Milou, Rintintin, Volt, Lassie, Pluto, Medor]
< new Vs static factories >
![Page 55: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/55.jpg)
Immutables
Pour que ça ne change pas
![Page 56: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/56.jpg)
Quand ? immutable
![Page 57: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/57.jpg)
Quand ? immutable
mutable
On se demande souvent si une liste doit être immutable mais c’est prendre le problème dans le mauvais sens. La plupart du temps, ce qu’il faut vraiment se demander, c’est si la liste a besoin d’être mutable.
![Page 58: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/58.jpg)
Java
5
Set<Integer> temp =
new LinkedHashSet<Integer>(Arrays.asList(1, 2, 3, 5, 7));
Set<Integer> primes = Collections.unmodifiableSet(temp);
< unmodifiables Vs immutables >
![Page 59: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/59.jpg)
Java
5
Set<Integer> primes = ImmutableSet.of(1, 2, 3, 5, 7);
Set<Integer> temp =
new LinkedHashSet<Integer>(Arrays.asList(1, 2, 3, 5, 7));
Set<Integer> primes = Collections.unmodifiableSet(temp);
Gu
ava
< unmodifiables Vs immutables >
G
![Page 60: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/60.jpg)
Of
ImmutableSet.of(E e1)
ImmutableSet.of(E e1, E e2)
ImmutableSet.of(E e1, E e2, E e3)
ImmutableSet.of(E e1, E e2, E e3, E e4)
ImmutableSet.of(E e1, E e2, E e3, E e4, E e5)
ImmutableSet.of(E e1, E e2, E e3, E e4, E e5, E e6, E...)
Ne prend pas de null
Of
ImmutableSet.of()
Vide
Map et List FAQ 4
< unmodifiables Vs immutables >
G
http://blog.developpez.com/guava/p10589/collection/title-212/
![Page 61: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/61.jpg)
Java
5
public class Dog {
private String name;
...
private List<String> colors;
public Dog(String name, List<String> colors) {
this.name = name;
...
this.colors = Collections.unmodifiableList(
new ArrayList<String>(colors));
}
public List<String> getColors() {
return colors;
}
5 < Copie de défense >
![Page 62: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/62.jpg)
Gu
ava public class Dog {
private String name;
...
private ImmutableList<String> colors;
public Dog(String name, List<String> colors) {
this.name = name;
...
this.colors = ImmutableList.copyOf(colors);
}
public ImmutableList<String> getColors() {
return colors;
}
G
Message clair
< Copie de défense >
![Page 63: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/63.jpg)
Collections en plus
Multimap, Bipap, Multiset, Table
![Page 64: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/64.jpg)
Java
5
Map<String, List<String>> dogFavoriteColors =
new HashMap<String, List<String>>();
5 < Multi Map >
List<String> milouColors = dogFavoriteColors.get("Milou");
if(milouColors == null) {
milouColors = new ArrayList<String>();
dogFavoriteColors.put("Milou",milouColors);
}
milouColors.add("Vert");
5
![Page 65: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/65.jpg)
Java
5
Map<String, List<String>> dogFavoriteColors =
new HashMap<String, List<String>>();
5 < Multi Map >
List<String> milouColors = dogFavoriteColors.get("Milou");
if(milouColors == null) {
milouColors = new ArrayList<String>();
dogFavoriteColors.put("Milou",milouColors);
}
milouColors.add("Vert");
5
Gu
ava Multimap<String, String> dogFavoriteColors =
HashMultimap.create();
dogFvoriteColors2.put("Milou", "Jaune");
dogFavoriteColors2.put("Milou", "Rouge");
G
![Page 66: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/66.jpg)
< Bi Map >
Gu
ava BiMap<String, Dog> tatouages = HashBiMap.create();
tatouages.put("ABC123", new Dog("Milou") );
tatouages.put("MBD324", new Dog("Volt") );
tatouages.put("JFT672", new Dog("Lassie") );
ABC123=Milou MDB324=Volt JFT672=Lassie Il est possible de changer la valeur associée à une clé mais pas d'avoir deux clés avec la même valeur (IllegalArgumentException).
println( tatouages );
Une map bijective
{ABC123=Milou, MBD324=Volt, JFT672=Lassie}
G
println( tatouages.inverse() );
{Milou=ABC123, Volt=MBD324, Lassie=JFT672}
![Page 67: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/67.jpg)
< Multi Set >
Gu
ava Multiset<Integer> ages = HashMultiset.create();
ages.add(2);
ages.add(3);
ages.add(7);
ages.add(11);
ages.add(3);
ages.add(5);
println( ages );
println( ages.count(3) )
[2, 3 x 2, 5, 7, 11]
2
G
![Page 68: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/68.jpg)
Base
Préconditions, joiner, splitter, optional
![Page 69: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/69.jpg)
toString () equals () hashCode () compareTo ()
![Page 70: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/70.jpg)
public class Dog {
private Integer id ;
private String name ;
private String fullName ;
...
public Dog(String name, String fullName, ...) {
if(name == null) {
throw new NPE("Le nom bla bla");
}
if(fullName == null) {
throw new NPE("bla bla");
}
...
this.name = name;
this.fullName = fullName;
...
}
DO
G
5 < Preconditions >
![Page 71: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/71.jpg)
import static com.google.common.base.Preconditions.*;
public class Dog {
private Integer id ;
private String name ;
private String fullName ;
...
public Dog(String name, String fullName, ...) {
this.name = checkNotNull(name, "bla bla");
this.fullName = checkNotNull(fullName, "bla bla");
...
}
DO
G
G < Preconditions >
checkNotNull() NPE checkArgument() IAE checkState() ISE
![Page 72: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/72.jpg)
Join
er
String names = Joiner.on(", ")
.join(newArrayList("Lassie", "Volt", "Milou"));
List<String> dogNames = newArrayList("Lassie", "Volt", "Milou");
StringBuilder sb = new StringBuilder();
boolean first = true;
for (String name : dogNames) {
if(name != null || name.trim().isEmpty()) {
continue;
}
if (!first) {
sb.append(", ");
}
sb.append(name);
first = false;
}
String names = sb.toString();
Java classique
G "Lassie, Volt, Milou"
![Page 73: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/73.jpg)
Join
er
String names = Joiner.on(", ")
.join(newArrayList("Lassie", "Volt", "Milou"));
String names = Joiner.on(", ")
.join(newArrayList("Lassie", "Volt", null, "Milou"));
NPE
G "Lassie, Volt, Milou"
![Page 74: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/74.jpg)
Join
er
String names = Joiner.on(", ")
.join(newArrayList("Lassie", "Volt", "Milou"));
String names = Joiner.on(", ")
.join(newArrayList("Lassie", "Volt", null, "Milou"));
String names = Joiner.on(", ")
.skipNulls()
.join(newArrayList("Lassie", "Volt", null, "Milou"));
"Lassie, Volt, Milou"
NPE
G "Lassie, Volt, Milou"
G
![Page 75: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/75.jpg)
Join
er
String names = Joiner.on(", ")
.join(newArrayList("Lassie", "Volt", "Milou"));
String names = Joiner.on(", ")
.join(newArrayList("Lassie", "Volt", null, "Milou"));
String names = Joiner.on(", ")
.skipNulls()
.join(newArrayList("Lassie", "Volt", null, "Milou"));
"Lassie, Volt, Milou"
NPE
String names = Joiner.on(", ")
.useForNull("Anonymous"))
.join(newArrayList("Lassie", "Volt", null, "Milou"));
"Lassie, Volt, Anonymous, Milou"
G "Lassie, Volt, Milou"
G
G http://blog.developpez.com/guava/p11054/base/joiner-pour-assembler-des-items/
![Page 76: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/76.jpg)
Split
ter
Iterable<String> dogNames =
Splitter.on(",")
.split("Lassie, Volt, Milou"); [ "Lassie", "Volt", "Milou" ]
![Page 77: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/77.jpg)
Split
ter
Iterable<String> dogNames =
Splitter.on(",")
.split("Lassie, Volt, Milou"); [ "Lassie", "Volt", "Milou" ]
Iterable<String> dogNames =
Splitter.on(",")
.split("Lassie, Volt, ,Milou"); [ "Lassie", "Volt", " ", "Milou" ]
![Page 78: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/78.jpg)
Split
ter
Iterable<String> dogNames =
Splitter.on(",")
.split("Lassie, Volt, Milou"); [ "Lassie", "Volt", "Milou" ]
Iterable<String> dogNames =
Splitter.on(",")
.split("Lassie, Volt, ,Milou"); [ "Lassie", "Volt", " ", "Milou" ]
Iterable<String> dogNames =
Splitter.on(",")
.trimResults()
.split("Lassie, Volt, ,Milou");
[ "Lassie", "Volt", "", "Milou" ]
![Page 79: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/79.jpg)
Split
ter
Iterable<String> dogNames =
Splitter.on(",")
.split("Lassie, Volt, Milou"); [ "Lassie", "Volt", "Milou" ]
Iterable<String> dogNames =
Splitter.on(",")
.split("Lassie, Volt, ,Milou"); [ "Lassie", "Volt", " ", "Milou" ]
Iterable<String> dogNames =
Splitter.on(",")
.trimResults()
.split("Lassie, Volt, ,Milou");
Iterable<String> dogNames =
Splitter.on(",")
.trimResults()
.omitEmptyStrings()
.split("Lassie, Volt, ,Milou");
G [ "Lassie", "Volt", "Milou" ]
http://blog.developpez.com/guava/p11045/annotation/splitter-pour-separer-des-items/
[ "Lassie", "Volt", "", "Milou" ]
![Page 80: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/80.jpg)
Op
tio
nal
Wrapper Optional <T>
Dog dog = new Dog("Milou", ...);
Optional<Dog> opt = Optional.of(dog);
assertTrue( opt.isPresent() );
assertEquals( "Milou", opt.get().getName() );
![Page 81: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/81.jpg)
Op
tio
nal
Wrapper Optional <T>
Dog dog = new Dog("Milou", ...);
Optional<Dog> opt = Optional.of(dog);
assertTrue( opt.isPresent() );
assertEquals( "Milou", opt.get().getName() );
Optional<Dog> opt = Optional.absent();
assertFalse( opt.isPresent() );
opt.get(); ISE
![Page 82: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/82.jpg)
Op
tio
nal
Wrapper Optional <T>
Dog dog = new Dog("Milou", ...);
Optional<Dog> opt = Optional.of(dog);
assertTrue( opt.isPresent() );
assertEquals( "Milou", opt.get().getName() );
Optional<Dog> opt = Optional.absent();
assertFalse( opt.isPresent() );
opt.get(); ISE
Dog dog = null;
Optional<Dog> opt = Optional.of(dog); NPE
Optional<Dog> opt = Optional.fromNullable(dog);
![Page 83: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/83.jpg)
http://blog.developpez.com/guava/p11163/base/le-wrapper-optional-de-guava/
Op
tio
nal
Wrapper Optional <T>
Dog dog = new Dog("Milou", ...);
Optional<Dog> opt = Optional.of(dog);
assertTrue( opt.isPresent() );
assertEquals( "Milou", opt.get().getName() );
Optional<Dog> opt = Optional.absent();
assertFalse( opt.isPresent() );
opt.get(); ISE
Dog dog = null;
Optional<Dog> opt = Optional.of(dog); NPE
Optional<Dog> opt = Optional.fromNullable(dog);
Dog dog = null;
Optional<Dog> opt = Optional.fromNullable(dog);
Dog dog2 = opt.or( new Dog("noname", ...) );
assertEquals( "noname", dog2.getName() );
![Page 84: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/84.jpg)
Functional Programming
todo
![Page 85: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/85.jpg)
Super chien
Dog
![Page 86: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/86.jpg)
public class SuperChien implements SuperHero {
private String surnom ;
private double poids ;
private Set<String> couleursCostume ;
private Set<String> pouvoirs ;
...
Sup
er
Ch
ien
5
Les héros peuvent avoir plusieurs costumes donc je n’utilise pas un ImmutableSet. Idem pour les pouvoirs
dont la liste augmente avec l’expérience.
![Page 87: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/87.jpg)
Tran
sfo
rmat
ion
List<SuperChien> superChiens =
Lists.transform(dogs,
new Function<Dog, SuperChien>() {
@Override
public SuperChien apply(Dog dog) {
SuperChien chien = new SuperChien();
chien.setSurnom("Super " + dog.getName());
chien.setPoids(dog.getWeight());
chien.setCouleursCostume(newHashSet(dog.getColors()))
chien.setPouvoirs(newHashSet("Code en Java", "Vole"))
...
return chien;
}
});
[Super Milou, Super Rintintin, Super Volt, Super Lassie, Super Pluto, Super Medor]
< Transformation >
G
![Page 88: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/88.jpg)
List<SuperChien> superChiens =
Lists.transform(dogs, new Function<Dog, SuperChien>() {
@Override
public SuperChien apply(Dog dog) {
SuperChien chien = new SuperChien();
...
return chien;
}
});
Vue (lazy) size / isEmpty dispo Pas pour traitements répétés FAQ 3
List<SuperChien> chiens = newArrayList(Lists.transform(...
ImmutableList<SuperChien> chiens =
ImmutableList.copyOf(Lists.transform(...
Tran
sfo
rmat
ion
< Transformation >
G
![Page 89: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/89.jpg)
Filt
re
Predicate<Dog> malePredicate =
new Predicate<Dog>() {
public boolean apply(Dog dog) {
return dog.getSex() == MALE;
}
}
Iterable<Dog> maleDogs =
Iterables.filter(dogs, malePredicate);
< Filtre >
G
G [Milou, Rintintin, Volt, Pluto, Medor]
![Page 90: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/90.jpg)
Filt
re
Predicate<Dog> malePredicate =
new Predicate<Dog>() {
public boolean apply(Dog dog) {
return dog.getSex() == MALE;
}
}
Iterable<Dog> maleDogs =
Iterables.filter(dogs, malePredicate);
Dog firstMaleDog =
Iterables.find(dogs, malePredicate);
< Filtre >
G
G [Milou, Rintintin, Volt, Pluto, Medor]
G Milou
![Page 91: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/91.jpg)
Filt
re
Predicate<Dog> malePredicate =
new Predicate<Dog>() {
public boolean apply(Dog dog) {
return dog.getSex() == MALE;
}
}
Iterable<Dog> maleDogs =
Iterables.filter(dogs, malePredicate);
Dog firstMaleDog =
Iterables.find(dogs, malePredicate);
Dog firstMaleDog =
Iterables.find(femaleDogs, malePredicate, DEFAULT_DOG );
Default dog
< Filtre >
G
G G Milou
[Milou, Rintintin, Volt, Pluto, Medor]
![Page 92: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/92.jpg)
Pas
flu
en
t Predicate<Dog> malePredicate =
new Predicate<Dog>() {
public boolean apply(Dog dog) {
return dog.getSex() == MALE;
}};
Function<FullDog, String> nameFunction =
new Function<FullDog, String>() {
public String apply(FullDog dog) {
return dog.getName();
}};
Iterable<FullDog> maleDogs =
Iterables.filter(dogs, malePredicate);
Iterable<String> maleNames =
Iterables.transform(maleDogs, nameFunction);
[Milou, Rintintin, Volt, Pluto, Medor]
< Fluent or not fluent ? >
G
G
G
![Page 93: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/93.jpg)
Pas
flu
en
t Iterable<FullDog> maleDogs =
Iterables.filter(dogs, malePredicate);
Iterable<String> maleNames =
Iterables.transform(maleDogs, nameFunction);
[Milou, Rintintin, Volt, Pluto, Medor]
List<String> maleNames2 =
FluentIterable.from(dogs)
.filter(malePredicate)
.transform(nameFunction)
.toImmutableList();
Flu
en
t
Guava 12.0
< Fluent or not fluent ? >
G
G
http://blog.developpez.com/guava/p11092/annotation/fluentiterable-sur-mon-chien-guava/
![Page 94: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/94.jpg)
Cache
todo
![Page 95: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/95.jpg)
We
b S
erv
ice
public class DogService {
@Inject
private PetShopWebService service;
public Integer getNumberDogsSoldYesterday() {
return service.checkSales( "dog" );
}
< Memoization >
5
![Page 96: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/96.jpg)
We
b S
erv
ice
public class DogService {
@Inject
private PetShopWebService service;
public Integer getNumberDogsSoldYesterday() {
return service.checkSales( "dog" );
}
< Memoization >
5 C
ach
e m
anu
el
private Integer nbOfDogsSold;
public Integer getNumberDogsSoldYesterday() {
if (nbOfDogsSold == null) {
nbOfDogsSold = service.checkSales( "dog" );
}
return nbOfDogsSold;
}
5
Double check null…
![Page 97: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/97.jpg)
Gu
ava public class DogService {
@Inject
private PetShopWebService service;
private Supplier<Integer> nbOfDogsSoldSupplier =
Suppliers.memoize(
new Supplier<Integer>() {
public Integer get() {
return service.checkSales( "dog" );
}
});
public Integer getNumberDogsSoldYesterday() {
return nbOfDogsSoldSupplier.get();
}
< Memoization >
G
![Page 98: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/98.jpg)
Gu
ava public class DogService {
@Inject
private PetShopWebService service;
private Supplier<Integer> nbOfDogsSoldSupplier =
Suppliers.memoizeWithExpiration(
new Supplier<Integer>() {
public Integer get() {
return service.checkSales( "dog" );
}
}, 1, TimeUnit.DAYS );
public Integer getNumberDogsSoldYesterday() {
return nbOfDogsSoldSupplier.get();
}
< Memoization >
G
![Page 99: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/99.jpg)
We
b S
erv
ice
public class DogService {
@Inject
private PetShopWebService service;
private Map<String, Dog> dogMap = Maps.newHashMap();
public Dog getDog(String name) {
Dog dog = dogMap.get(name);
if(dog == null) {
dog = service.getAnimal( "dog", name ); // type-name
dogMap.put( name, dog );
}
return dog;
}
< Cache >
5
Quid du timeout ? Max ?
![Page 100: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/100.jpg)
Gu
ava public class DogService {
@Inject
private PetShopWebService service;
private LoadingCache<String, Dog> dogCache =
CacheBuilder.newBuilder()
.maximumSize(2000)
.expireAfterWrite(30, TimeUnit.MINUTES)
.build(new CacheLoader<String, Dog>() {
public Dog load(String key) {
return service.getAnimal( "dog", key );
}
});
public Dog getDog(String name) {
return dogCache.get( name ); // + try-catch
}
< Cache >
G
![Page 101: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/101.jpg)
Hash
Fantôme
![Page 102: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/102.jpg)
Has
h
HashFunction hf = Hashing.md5();
HashCode hc = hf.newHasher()
.putInt(123)
.putString("Milou")
.hash();
byte[] bytes = hc.asBytes();
md5 Murmur3 128 bits Murmur3 32 bits Sha1 Sha256 Sha512 goodFastHash
G
![Page 103: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/103.jpg)
Pré
par
atio
n
int NB_OF_DOGS = 100000;
List<Dog> dogs = newArrayList();
Random rand = new Random();
for (int i = 0; i < NB_OF_DOGS; i++) {
Dog dog = new Dog();
dog.setName("abc" + rand.nextInt(999));
...
dogs.add(dog);
}
dogs.add(milou);
boolean isInList = dogs.contains(milou); true (14 ms)
final Dog milou = new Dog();
milou.setName("Milou");
...
boolean isInList = dogs.contains(milou); false (14 ms) co
nta
ins
< Is in list ? >
5
5
![Page 104: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/104.jpg)
Blo
om
filt
er
Funnel<Dog> dogFunnel = new Funnel<Dog>() {
public void funnel(Dogdog, PrimitiveSink sink) {
sink.putString(dog.getName())
.putString(dog.getFullName())
.putString(dog.getRace());
}};
BloomFilter<Dog> bloom =
BloomFilter.create(dogFunnel, NB_OF_DOGS, 0.01);
for (int i = 0; i < NB_OF_DOGS; i++) {
...
bloom.put(dog);
bloom.put(milou);
boolean isInList = bloom.mightContain(milou);
true (0 ms)
boolean isInList = bloom.mightContain(milou);
false (0 ms)
< Is in list ? >
G
http://blog.developpez.com/guava/p11149/collection/bloom-filter-de-guava-13/
Guava 13
![Page 105: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/105.jpg)
Guava or not Guava ?
Avantages et inconvénients
![Page 106: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/106.jpg)
Pro
/ C
on
s
Ne pas en abuser…
Utile Bonnes pratiques
![Page 107: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/107.jpg)
LIEN
S
![Page 108: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/108.jpg)
Guava http://code.google.com/p/guava-libraries
Lombok http://projectlombok.org
Lombok-pg https://github.com/peichhorn/lombok-pg
![Page 109: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/109.jpg)
ICAUDA http://icauda.com http://icauda.com/articles.html (articles) http://icauda.com/cours.html (slides)
Blog Guava http://blog.developpez.com/guava
« Simplifier le code de vos beans Java à l'aide de Commons Lang, Guava et Lombok » http://thierry-leriche-dessirier.developpez.com/tutoriels/ java/simplifier-code-guava-lombok (article)
@thierryleriche
![Page 110: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/110.jpg)
MER
CI
![Page 111: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/111.jpg)
FAQ
/ B
on
us 1. Guava Vs Commons
2. Régime façon Apache 3. Fonctionnal prog Vs boucle for 4. Créer des Maps 5. Charsets 6. Converter Spring 7. Orderings 8. Licences 9. Extension avec valeurs 10. Chrono 11. CharMatcher 12. Impl 13. And, or, in… 14. Partition, limit 15. Inférence de type 16. Coût du bloom 17. Table 18. Ecrasement des getters existants
![Page 112: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/112.jpg)
Guava Vs Commons ?
http://tinyurl.com/guava-vs-apache
1
![Page 113: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/113.jpg)
Régime : la méthode Commons ?
2
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("name", name)
.append("fullName", fullName)
...
.append("colors", colors)
.toString();
}
toSt
rin
g
L
![Page 114: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/114.jpg)
Régime : la méthode Commons ?
2
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof Dog)) return false;
Dog other = (Dog) obj;
return new EqualsBuilder()
.append(birthday, other.birthday)
.append(fullname, other.fullname)
.append(name, other.name)
.append(race, other.race)
.append(sex, other.sex)
.isEquals();
}
eq
ual
s
L
![Page 115: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/115.jpg)
Régime : la méthode Commons ?
2
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(birthday)
.append(fullname)
.append(name)
.append(race)
.append(sex)
.toHashCode();
}
has
hC
od
e
L
![Page 116: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/116.jpg)
Régime : la méthode Commons ?
2
public int compareTo(Dog other) {
return new CompareToBuilder()
.append(name, other.name)
.append(fullname, other.fullname)
.append(birthday, other.birthday)
...
.append(sex, other.sex)
.toComparison();
}
com
par
eTo
L
![Page 117: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/117.jpg)
List<SuperChien> superChiens = newArrayList();
for(Dog dog : dogs) {
SuperChien chien = new SuperChien();
...
superChiens.add(chien);
}
List<SuperChien> superChiens = newArrayList(
Lists.transform(dogs, new Function<Dog, SuperChien>() {
@Override
public SuperChien apply(Dog dog) {
SuperChien chien = new SuperChien();
...
return chien;
}
})); Tran
sfo
rmat
ion
Fonctionnal prog Vs boucle for : quand ?
http://code.google.com/p/guava-libraries/wiki/FunctionalExplained
Vs 3
G
G
![Page 118: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/118.jpg)
Créer des Maps
4
of
public static final ImmutableMap<String, Integer>
AGES = new ImmutableMap.Builder<String, Integer>()
.put("Milou", 32)
.put("Volt", 7)
.put("Pluto", 37)
.put("Lassie", 17)
.put("Medor", 5)
.put("Croquette", 8)
.put("Loulou", 2)
...
.build();
public static final ImmutableMap<String, Integer>
AGES = ImmutableMap.of("Milou", 32,
"Volt", 7,
"Pluto", 37,
"Lassie", 17);
Bu
ilde
r
G
G
![Page 119: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/119.jpg)
Charsets
5
Java
5
String name = "Milou";
byte[] bytes = name.getBytes(Charsets.UTF_8);
String name = "Milou";
try {
byte[] bytes = name.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
Gu
ava
Ca n’arrive jamais cette exception
5
G
![Page 120: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/120.jpg)
import org.springframework...Converter;
@Component("dogToChienConverter")
public class DogToChienConverter
implements Converter<List<Dog>,
List<SuperChien>> {
public List<SuperChien> convert(List<Dog> dogs) {
List<SuperChien> chiens = newArrayList(transform(dogs,
new Function<Dog, SuperChien>() {
public SuperChien apply(Dog dog) {
...
return chien;
}
}));
return chiens;
} 6
Converter Spring
Lazy or not lazy ?
G
![Page 121: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/121.jpg)
Orderings
7
![Page 122: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/122.jpg)
Licences
8
Lombok : MIT License Lombok-pg : MIT License
Guava : Apache License 2.0
Commons : Apache License 2.0
![Page 123: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/123.jpg)
@ExtensionMethod({ Object.class, MyOtherClass.class })
public class DogWithExtension {
public void foo() {
String s1 = "toto";
s1.print(); // toto
String s2 = null;
s2.print(); // null
}
}
class MyOtherClass {
public static <T> void print(final T value) {
System.out.println(value);
}
}
L
On peut mettre autre chose qu’un "Object", par exemple un "Arrays" , un "Dog" , etc.
9
Extension avec valeurs
![Page 124: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/124.jpg)
@ExtensionMethod({ Object.class, MyOtherClass.class })
public class DogWithExtension {
public void foo() {
String s1 = "toto";
s1.print(); // toto
String s2 = null;
s2.print(); // null
s2.print("vide"); // vide
}
}
class MyOtherClass {
public static <T> void print(final T value) {
System.out.println(value);
}
public static void print(String value, String other) {
if (value == null || value.isEmpty()) {
System.out.println(other);
} else {
System.out.println(value);
}
public static <T extends String> void print(final T value, final T otherValue) { if (value == null || value.isEmpty()) { System.out.println(otherValue); } }
9
Extension avec valeurs
L
![Page 125: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/125.jpg)
long start = new Date().getTime();
foo(); // traitement long (ou pas)
long end = new Date().getTime();
long duration = end - start; // 11 ms
Java
5
5 < Chrono >
10
Stopwatch sw = new Stopwatch();
sw.start();
foo(); // traitement long (ou pas)
sw.stop();
long duration = sw.elapsedMillis(); // 11 ms
G
Gu
ava
long nano = sw.elapsedTime(NANOSECONDS); // 11179739 ns
long micro = sw.elapsedTime(MICROSECONDS); // 11179 us
long millis = sw.elapsedTime(MILLISECONDS); // 11 ms
http://blog.developpez.com/guava/p11160/base/le-stop-watch-de-guava/
![Page 126: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/126.jpg)
CharMatcher
11
![Page 127: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/127.jpg)
Impl
12
public class Dog implements Comparable<Dog> {
private Integer id ;
private String name ;
private String fullName ;
...
@Override
public int compareTo(Dog dog) {
return ...;
}
implements List ? aie aie aie
5
![Page 128: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/128.jpg)
Impl
12
@AutoGenMethodStub
public class Dog implements Comparable<Dog> {
private Integer id ;
private String name ;
private String fullName ;
...
L
![Page 129: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/129.jpg)
List<Dog> dogs2 = newArrayList(
new Dog("Rintintin", 45.0, MALE, ...),
new Dog("Pluto", 22.0, MALE, ...),
new Dog("Lulu", 35.6, MALE, ...));
Seco
nd
e li
ste
G
[Rintintin, Pluto, Lulu]
[Milou, Rintintin, Volt, Lassie, Pluto, Medor]
Liste 2 : dogs2
Liste 1 : dogs
13
And, or, in…
![Page 130: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/130.jpg)
And, or, in…
13
An
d, o
r, in
...
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.in;
boolean isRintintinInBoth =
and( in(dogs), in(dogs2) )
.apply(new Dog("Rintintin")); true
import static com.google.common.base.Predicates.or;
boolean isTintinInOne =
or( in(dogs), in(dogs2) )
.apply(new Dog("Tintin"); false
G
G
[Rintintin, Pluto, Lulu]
[Milou, Rintintin, Volt, Lassie, Pluto, Medor] Li
ste
2 :
do
gs2
List
e 1
: d
ogs
![Page 131: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/131.jpg)
Partition, limit
14
Par
titi
on
List<List<FullDog>> partition =
Lists.partition(dogs, 4);
[Milou, Rintintin, Volt, Lassie]
[Pluto, Medor]
List<FullDog> first4Dogs =
newArrayList(Iterables.limit(dogs, 4));
[Milou, Rintintin, Volt, Lassie]
G
G Lim
it
![Page 132: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/132.jpg)
Inférence de type
15
Java
List<Integer> primeNumbers = new ArrayList<Integer>();
List<Integer> primeNumbers = newArrayList();
Gu
ava
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<E>();
}
http://blog.developpez.com/guava/p11334/collection/inference-de-type-avec-guava
![Page 133: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/133.jpg)
Coût du bloom
16
final List<Dog> dogs = Lists.newArrayList();
final Funnel<Dog> dogFunnel = new Funnel<Dog>() {
@Override
public void funnel(Dog dog, PrimitiveSink sink) {
sink.putString(dog.getName())
.putString(dog.getFullName())
.putString(dog.getRace());
}
};
BloomFilter<Dog> bloom
= BloomFilter.create(dogFunnel, NB_OF_DOGS, 0.01);
final Random rand = new Random();
Stopwatch sw = new Stopwatch();
sw.start();
for (int i = 0; i < NB_OF_DOGS; i++) {
final DogGuava dog = new DogGuava(...);
dogs.add(dog);
}
long duration1 = sw.elapsedTime(MICROSECONDS);
![Page 134: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/134.jpg)
Coût du bloom
16
for (Dog dog : dogs) {
bloom.put(dog);
}
long duration2 = sw.elapsedTime(MICROSECONDS);
boolean inside = dogs.contains(milou);
long duration3 = sw.elapsedTime(MICROSECONDS);
Chiens Add to list Add to bloom Recherche
1 828 17 971 430
10 938 26 643 749
100 2 159 21 859 754
1 000 9 312 49 564 1 192
10 000 42 232 126 505 5 613
100 000 156 065 261 168 14 353
1 000 000 1 594 113 775 300 41 904
![Page 135: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/135.jpg)
< Table >
Gu
ava // Sexe, couleur, nom
Table<SexeEnum, String, String> dogTable
= HashBasedTable.create();
dogTable.put(MALE, "jaune", "Pluto");
dogTable.put(MALE, "blanc", "Milou");
dogTable.put(MALE, "noir", "Medor");
dogTable.put(FEMALE, "noir", "Lassie");
dogTable.put(FEMALE, "blanc", "Pupuce");
G
17
![Page 136: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/136.jpg)
< Table >
Gu
ava // Sexe, couleur, nom
Table<SexeEnum, String, String> dogTable
= HashBasedTable.create();
dogTable.put(MALE, "jaune", "Pluto");
dogTable.put(MALE, "blanc", "Milou");
dogTable.put(MALE, "noir", "Medor");
dogTable.put(FEMALE, "noir", "Lassie");
dogTable.put(FEMALE, "blanc", "Pupuce");
Map<String, String> maleRow = dogTable.row(MALE);
println( maleRow )
{ jaune=Pluto, noir=Medor, blanc=Milou }
G
Map<String, String> femaleRow = dogTable.row(FEMALE);
println( femaleRow )
{ noir=Lassie, blanc=Pupuce }
17
![Page 137: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/137.jpg)
< Table >
Gu
ava // Sexe, couleur, nom
Table<SexeEnum, String, String> dogTable
= HashBasedTable.create();
dogTable.put(MALE, "jaune", "Pluto");
dogTable.put(MALE, "blanc", "Milou");
dogTable.put(MALE, "noir", "Medor");
dogTable.put(FEMALE, "noir", "Lassie");
dogTable.put(FEMALE, "blanc", "Pupuce");
Map<SexeEnum, String> blancColumn
= dogTable.column("blanc");
println( blancColumn )
{ FEMALE=Pupuce, MALE=Milou }
Map<SexeEnum, String> jauneColumn
= dogTable.column("jaune");
println( jauneColumn )
{ MALE=Pluto }
17
![Page 138: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/138.jpg)
Pas d’écrasement des getters existants
18
@Data
public class MicroDog {
private String name;
private Integer age;
public String getName() {
return "*" + name + "*";
}
}
@Test
public void testGetterExistant() {
final String name = "Milou";
final String requiredName = "*Milou*";
final MicroDog dog = new MicroDog();
dog.setName(name);
assertEquals(requiredName, dog.getName());
}
![Page 139: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/139.jpg)
Slides en préparation
![Page 140: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/140.jpg)
I/O
todo
![Page 141: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/141.jpg)
public void lireJava6(String from) {
InputStream in = null;
try {
in = new FileInputStream(from);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1)
break;
...
}
} catch (Exception e) {
...
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
...
}
}
...
Re
sso
urc
es 5
< I/O >
![Page 142: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/142.jpg)
public void lireJava7(String from) {
try(InputStream in = new FileInputStream(from)) {
...
while (true) {
...
}
}
}
Java
7
7 < I/O >
![Page 143: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/143.jpg)
Todo
G
uav
a G < I/O >
![Page 144: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/144.jpg)
Concurrent / future
todo
![Page 145: Guava et Lombok au Bordeaux JUG](https://reader033.fdocument.pub/reader033/viewer/2022050907/55a0e6c61a28ab10248b4760/html5/thumbnails/145.jpg)
Todo