diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d973ee1854dc6f37789e28b60079c2a4a4640873..8e05cf053aa7958e7ca2fabea6e0d13e9f23455e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -22,3 +22,4 @@ include:
   - local: "/trip-service-kata-typescript/.gitlab-ci.yml"
   - local: "/roman-calculator/.gitlab-ci.yml"
   - local: "/h2g2/.gitlab-ci.yml"
+  - local: "/java-streams/.gitlab-ci.yml"
diff --git a/README.md b/README.md
index fcfc29ee791ffa641894ae6a604502ede24a1274..c7b7f35fff9a7d2a773719a5923c1689e5a51a30 100644
--- a/README.md
+++ b/README.md
@@ -46,3 +46,4 @@ Ce dépôt Git a pour but de partager les différents ateliers pouvant être ré
 | [Roman calculator](/roman-calculator)                                                                                 | Kata        | Moyenne    |
 | [Atomic Design I and II](https://gitlab.ippon.fr/arey/pattern-library)                                                | Front       | Moyenne    |
 | [H2G2 (TypeScript)](/h2g2)                                                                                            | Kata        | Moyenne    |
+| [Java streams](/java-streams)                                                                                         | Code&coffee | Moyenne    |
diff --git a/java-streams/.gitlab-ci.yml b/java-streams/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..af95a330e157dce9e241f1c223f5122c0bd1a1b1
--- /dev/null
+++ b/java-streams/.gitlab-ci.yml
@@ -0,0 +1,11 @@
+package-java-streams:
+  variables:
+    PROJECT_FOLDER: "java-streams"
+  extends: .java
+  only:
+    refs:
+      - master
+      - merge_requests
+    changes:
+      - ".gitlab-common-ci.yml"
+      - "java-streams/**/*"
diff --git a/java-streams/pom.xml b/java-streams/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c2cdc21e722cbd1c35662a0b4066bf401c609f34
--- /dev/null
+++ b/java-streams/pom.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <version>1.0.0</version>
+    <groupId>fr.ippon.kata</groupId>
+    <artifactId>java-parent</artifactId>
+    <relativePath>../java-parent</relativePath>
+  </parent>
+
+  <version>1.0.0-SNAPSHOT</version>
+  <artifactId>java-streams</artifactId>
+
+  <name>JavaStreams</name>
+
+  <developers>
+    <developer>
+      <email>arey@ippon.fr</email>
+      <name>Anthony REY</name>
+    </developer>
+    <developer>
+      <email>cdamon@ippon.fr</email>
+      <name>Colin DAMON</name>
+    </developer>
+  </developers>
+</project>
diff --git a/java-streams/readme.md b/java-streams/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..97d956934668f6528538f571ff85c66e5fb14567
--- /dev/null
+++ b/java-streams/readme.md
@@ -0,0 +1,9 @@
+# Java streams
+
+Code & coffee pour parler des streams en Java
+
+-   **Auteurs** : Anthony REY & Colin DAMON
+-   **Date** : 06/01/2021
+-   **Langage** : Java
+-   **Niveau** : Moyen
+-   **Replay** : TODO
diff --git a/java-streams/src/main/java/fr/ippon/streams/Employee.java b/java-streams/src/main/java/fr/ippon/streams/Employee.java
new file mode 100644
index 0000000000000000000000000000000000000000..529507115198b4133b47ac5bd1388d1184477da1
--- /dev/null
+++ b/java-streams/src/main/java/fr/ippon/streams/Employee.java
@@ -0,0 +1,19 @@
+package fr.ippon.streams;
+
+public class Employee {
+  private final String name;
+  private final int age;
+
+  public Employee(String name, int age) {
+    this.name = name;
+    this.age = age;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public int getAge() {
+    return age;
+  }
+}
diff --git a/java-streams/src/main/java/fr/ippon/streams/Mall.java b/java-streams/src/main/java/fr/ippon/streams/Mall.java
new file mode 100644
index 0000000000000000000000000000000000000000..33fe85555962257b1662c37ab397b1585cbb0806
--- /dev/null
+++ b/java-streams/src/main/java/fr/ippon/streams/Mall.java
@@ -0,0 +1,60 @@
+package fr.ippon.streams;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class Mall {
+  private final List<Shop> shops;
+
+  public Mall(Shop... shops) {
+    this.shops = Arrays.asList(shops);
+  }
+
+  public Collection<String> getShopNames() {
+    return shops.stream().map(Shop::getName).sorted().collect(Collectors.toList());
+  }
+
+  public String getEmployeesMeanAge() {
+    return employeesAgeStream()
+      .map(BigDecimal::valueOf)
+      .reduce(BigDecimal::add)
+      .map(this::toAverage)
+      .orElse(BigDecimal.ZERO)
+      .toPlainString();
+  }
+
+  private Stream<Integer> employeesAgeStream() {
+    return shops.stream().flatMap(this::toEmployeesAges);
+  }
+
+  private Stream<Integer> toEmployeesAges(Shop shop) {
+    return toEmployees(shop).map(Employee::getAge);
+  }
+
+  private BigDecimal toAverage(BigDecimal sum) {
+    return sum.divide(new BigDecimal(employeesAgeStream().count()), 2, RoundingMode.HALF_UP);
+  }
+
+  public Collection<String> getEmployeesOver(int age) {
+    return shops
+      .stream()
+      .flatMap(this::toEmployees)
+      .filter(employee -> overAge(age, employee))
+      .map(Employee::getName)
+      .sorted()
+      .collect(Collectors.toList());
+  }
+
+  private Stream<Employee> toEmployees(Shop shop) {
+    return shop.getEmployees().stream();
+  }
+
+  private boolean overAge(int age, Employee employee) {
+    return employee.getAge() > age;
+  }
+}
diff --git a/java-streams/src/main/java/fr/ippon/streams/Shop.java b/java-streams/src/main/java/fr/ippon/streams/Shop.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c4d1c301227a38dccbb05470cd5272d78c95810
--- /dev/null
+++ b/java-streams/src/main/java/fr/ippon/streams/Shop.java
@@ -0,0 +1,22 @@
+package fr.ippon.streams;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+public class Shop {
+  private final String name;
+  private final Collection<Employee> employees;
+
+  public Shop(String name, Employee... employees) {
+    this.name = name;
+    this.employees = Arrays.asList(employees);
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Collection<Employee> getEmployees() {
+    return employees;
+  }
+}
diff --git a/java-streams/src/test/java/fr/ippon/streams/MallUnitTest.java b/java-streams/src/test/java/fr/ippon/streams/MallUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4bdfd540fce8daeb4da73b98289b91510232c1ed
--- /dev/null
+++ b/java-streams/src/test/java/fr/ippon/streams/MallUnitTest.java
@@ -0,0 +1,41 @@
+package fr.ippon.streams;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+public class MallUnitTest {
+  private static final Mall mall = mall(shop("Nature", employee("Michel", 25)), shop("Beer", employee("Bob", 42), employee("John", 19)));
+
+  @Test
+  void shouldGetShopNames() {
+    assertThat(mall.getShopNames()).containsExactly("Beer", "Nature");
+  }
+
+  @Test
+  void shouldGetZeroAverageAgeWithoutShopInMall() {
+    assertThat(new Mall().getEmployeesMeanAge()).isEqualTo("0");
+  }
+
+  @Test
+  void shouldGetEmployeesAverageAge() {
+    assertThat(mall.getEmployeesMeanAge()).isEqualTo("28.67");
+  }
+
+  @Test
+  void shouldGetEmployeesOverAge() {
+    assertThat(mall.getEmployeesOver(20)).containsExactly("Bob", "Michel");
+  }
+
+  private static Mall mall(Shop... shops) {
+    return new Mall(shops);
+  }
+
+  private static Shop shop(String name, Employee... employees) {
+    return new Shop(name, employees);
+  }
+
+  private static Employee employee(String name, int age) {
+    return new Employee(name, age);
+  }
+}