From 05b27ca729100ed5828f10d602a2480cc133f9c9 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Tue, 26 Nov 2013 22:13:27 +0100 Subject: [PATCH 01/23] Tasks and unit tests for the streaming api hands-on; Change type of Person.birthdate to LocalDate - we do Java 8 ;-) --- .../de/codecentric/java8examples/Invoice.java | 28 ++++++++ .../java8examples/InvoiceItem.java | 28 ++++++++ .../de/codecentric/java8examples/Person.java | 36 ++++------ .../lambdas/SpringJdbcSupportWithLambdas.java | 6 +- .../java8examples/streaming/Collecting.java | 38 +++++++++++ .../streaming/FilteringAndMapping.java | 59 ++++++++++++++++ .../codecentric/java8examples/TestData.java | 36 ++++++++++ .../codecentric/java8examples/TestUtil.java | 27 -------- .../lambdas/LambdaBasedComparatorTest.java | 4 +- .../lambdas/LambdaExampleTest.java | 4 +- .../streaming/FilteringAndMappingTest.java | 68 +++++++++++++++++++ .../java8examples/streaming/FlatMapTest.java | 14 ++++ .../streaming/StreamingApiTest.java | 58 ---------------- 13 files changed, 291 insertions(+), 115 deletions(-) create mode 100644 src/main/java/de/codecentric/java8examples/Invoice.java create mode 100644 src/main/java/de/codecentric/java8examples/InvoiceItem.java create mode 100644 src/main/java/de/codecentric/java8examples/streaming/Collecting.java create mode 100644 src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java create mode 100644 src/test/java/de/codecentric/java8examples/TestData.java delete mode 100644 src/test/java/de/codecentric/java8examples/TestUtil.java create mode 100644 src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java create mode 100644 src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java delete mode 100644 src/test/java/de/codecentric/java8examples/streaming/StreamingApiTest.java diff --git a/src/main/java/de/codecentric/java8examples/Invoice.java b/src/main/java/de/codecentric/java8examples/Invoice.java new file mode 100644 index 0000000..65e0418 --- /dev/null +++ b/src/main/java/de/codecentric/java8examples/Invoice.java @@ -0,0 +1,28 @@ +package de.codecentric.java8examples; + +import java.util.List; + +public class Invoice { + + private String sender; + private String recipient; + private List items; + + public String getSender() { + return sender; + } + + public String getRecipient() { + return recipient; + } + + public List getItems() { + return items; + } + + public Invoice(String sender, String recipient, List items) { + this.sender = sender; + this.recipient = recipient; + this.items = items; + } +} diff --git a/src/main/java/de/codecentric/java8examples/InvoiceItem.java b/src/main/java/de/codecentric/java8examples/InvoiceItem.java new file mode 100644 index 0000000..44ed6a4 --- /dev/null +++ b/src/main/java/de/codecentric/java8examples/InvoiceItem.java @@ -0,0 +1,28 @@ +package de.codecentric.java8examples; + +import java.math.BigDecimal; + +public class InvoiceItem { + + private String product; + private Integer quantity; + private BigDecimal pricePerUnit; + + public String getProduct() { + return product; + } + + public Integer getQuantity() { + return quantity; + } + + public BigDecimal getPricePerUnit() { + return pricePerUnit; + } + + public InvoiceItem(String product, Integer quantity, BigDecimal pricePerUnit) { + this.product = product; + this.quantity = quantity; + this.pricePerUnit = pricePerUnit; + } +} diff --git a/src/main/java/de/codecentric/java8examples/Person.java b/src/main/java/de/codecentric/java8examples/Person.java index d2b3518..6cc8de8 100644 --- a/src/main/java/de/codecentric/java8examples/Person.java +++ b/src/main/java/de/codecentric/java8examples/Person.java @@ -1,7 +1,7 @@ package de.codecentric.java8examples; -import java.util.Calendar; -import java.util.Date; +import java.time.LocalDate; +import java.time.Period; /** * A simple class that represents a person @@ -12,27 +12,27 @@ public enum Gender { MALE, FEMALE } - private final String name; + private final String firstName; private final String lastName; - private final Date birthDay; + private final LocalDate birthDay; private Gender gender; - public Person(String name, String lastName, Date birthDay, Gender gender) { - this.name = name; + public Person(String firstname, String lastName, LocalDate birthDay, Gender gender) { + this.firstName = firstname; this.lastName = lastName; this.birthDay = birthDay; this.gender = gender; } - public String getName() { - return name; + public String getFirstName() { + return firstName; } public String getLastName() { return lastName; } - public Date getBirthDay() { + public LocalDate getBirthDay() { return birthDay; } @@ -45,17 +45,7 @@ public void setGender(Gender gender) { } public int getAge() { - Calendar now = Calendar.getInstance(); - Calendar birth = Calendar.getInstance(); - birth.setTime(getBirthDay()); - - int years = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR); - if(now.get(Calendar.MONTH) > birth.get(Calendar.MONTH) || - now.get(Calendar.MONTH) == birth.get(Calendar.MONTH) && birth.get(Calendar.DATE) > now.get(Calendar.DATE)) { - years--; - } - - return years; + return Period.between(getBirthDay(), LocalDate.now()).getYears(); } @Override @@ -68,14 +58,14 @@ public boolean equals(Object o) { if (birthDay != null ? !birthDay.equals(person.birthDay) : person.birthDay != null) return false; if (gender != person.gender) return false; if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) return false; - if (name != null ? !name.equals(person.name) : person.name != null) return false; + if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) return false; return true; } @Override public int hashCode() { - int result = name != null ? name.hashCode() : 0; + int result = firstName != null ? firstName.hashCode() : 0; result = 31 * result + (lastName != null ? lastName.hashCode() : 0); result = 31 * result + (birthDay != null ? birthDay.hashCode() : 0); result = 31 * result + (gender != null ? gender.hashCode() : 0); @@ -85,7 +75,7 @@ public int hashCode() { @Override public String toString() { return "Person{" + - "name='" + name + '\'' + + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", birthDay=" + birthDay + ", gender=" + gender + diff --git a/src/main/java/de/codecentric/java8examples/lambdas/SpringJdbcSupportWithLambdas.java b/src/main/java/de/codecentric/java8examples/lambdas/SpringJdbcSupportWithLambdas.java index cebb772..ad1d284 100644 --- a/src/main/java/de/codecentric/java8examples/lambdas/SpringJdbcSupportWithLambdas.java +++ b/src/main/java/de/codecentric/java8examples/lambdas/SpringJdbcSupportWithLambdas.java @@ -19,7 +19,7 @@ public Person findPersonById(String id) { new RowMapper() { @Override public Person mapRow(ResultSet rs, int i) throws SQLException { - return new Person(rs.getString("FIRST_NAME"), rs.getString("LAST_NAME"), rs.getDate(3), Person.Gender.MALE); + return new Person(rs.getString("FIRST_NAME"), rs.getString("LAST_NAME"), rs.getDate(3).toLocalDate(), Person.Gender.MALE); } }); } @@ -27,7 +27,7 @@ public Person mapRow(ResultSet rs, int i) throws SQLException { public Person findPersonByIdWithLambdas(String id) { return getJdbcTemplate().queryForObject( "SELECT * FROM persons WHERE id = " + id, - (rs, i) -> new Person(rs.getString("FIRST_NAME"), rs.getString("LAST_NAME"), rs.getDate(3), Person.Gender.MALE)); + (rs, i) -> new Person(rs.getString("FIRST_NAME"), rs.getString("LAST_NAME"), rs.getDate(3).toLocalDate(), Person.Gender.MALE)); } // if things get messy, use a method reference @@ -40,7 +40,7 @@ private Person mapPerson(ResultSet rs, int i) throws SQLException { return new Person( rs.getString("FIRST_NAME"), rs.getString("LAST_NAME"), - rs.getDate(3), + rs.getDate(3).toLocalDate(), Person.Gender.MALE); } } diff --git a/src/main/java/de/codecentric/java8examples/streaming/Collecting.java b/src/main/java/de/codecentric/java8examples/streaming/Collecting.java new file mode 100644 index 0000000..a13661b --- /dev/null +++ b/src/main/java/de/codecentric/java8examples/streaming/Collecting.java @@ -0,0 +1,38 @@ +package de.codecentric.java8examples.streaming; + +import de.codecentric.java8examples.Invoice; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Your task: Implement the following methods and make the tests passs. + */ +public class Collecting { + + /** + * Identify the cheapest product (by pricePerUnit) in all invoices. + */ + public static String cheapestProduct(List invoices) { + return ""; + } + + /** + * Identify the invoice with the highest total amount. + */ + public static Invoice mostExpensiveInvoice(List invoices) { + return null; + } + + /** + * For every product, compute the cheapest dealer. Return as a Map where the key is the product name and the value + * is the dealer (=sender of the invoice). + */ + public static Map cheapestDealersByProduct() { + return Collections.emptyMap(); + } + +} diff --git a/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java new file mode 100644 index 0000000..c751e9f --- /dev/null +++ b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java @@ -0,0 +1,59 @@ +package de.codecentric.java8examples.streaming; + +import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.Person; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * Your task: Implement the following methods and make the tests passs. + */ +public class FilteringAndMapping { + + /** + * Extract a list of names (firstname and lastname separated by space) from a given list of Person objects. + */ + public static List extractNames(List persons) { + return Collections.emptyList(); + } + + /** + * Extract a sorted (ascending by lastname) list of names (firstname and lastname separated by space) from a + * given list of Person objects. + */ + public static List extractNamesSortedByLastname(List persons) { + return Collections.emptyList(); + } + + /** + * From a given list of Person objects, extract a list of female firstnames + */ + public static List extractFemaleFirstnames(List persons) { + return Collections.emptyList(); + } + + /** + * Extract all females older than 18 years from a given list of Person objects. + */ + public static List extractAdultWomen(List persons) { + return Collections.emptyList(); + } + + /** + * From a given list of Person objects, extract a set of firstnames of the people whose lastname starts + * with the given string. + */ + public static Set extractFirstnamesWhereLastnameStartsWith(List persons, String startsWith) { + return Collections.emptySet(); + } + + /** + * From a given list of invoices, extract a set of all product names. + */ + public static Set extractAllProducts(List invoices) { + return Collections.emptySet(); + } +} + diff --git a/src/test/java/de/codecentric/java8examples/TestData.java b/src/test/java/de/codecentric/java8examples/TestData.java new file mode 100644 index 0000000..ce92165 --- /dev/null +++ b/src/test/java/de/codecentric/java8examples/TestData.java @@ -0,0 +1,36 @@ +package de.codecentric.java8examples; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Utility class that generates some test data for us. + */ +public class TestData { + public static List listOfPersons() { + return Arrays.asList( + new Person("Jane", "Jungle", LocalDate.of(1978, 12, 15), Person.Gender.FEMALE), + new Person("Mary", "Smith", LocalDate.of(1980, 10, 19), Person.Gender.FEMALE), + new Person("John", "Dole", LocalDate.of(1973, 5, 31), Person.Gender.MALE), + new Person("Michael", "Abrahams", LocalDate.of(1967, 2, 1), Person.Gender.MALE), + new Person("Chris", "Cross", LocalDate.of(1985, 8, 22), Person.Gender.MALE), + new Person("Pete", "Power", LocalDate.of(1981, 3, 18), Person.Gender.MALE), + new Person("Maggie", "Simpson", LocalDate.of(2012, 10, 18), Person.Gender.FEMALE) + ); + } + + public static List listOfInvoices() { + return Arrays.asList( + new Invoice("Moe", "Homer", Arrays.asList( + new InvoiceItem("Beer", 13, BigDecimal.valueOf(1.5)), + new InvoiceItem("Burger", 3, BigDecimal.valueOf(4.5)))), + new Invoice("Crusty Burger", "Homer", Arrays.asList( + new InvoiceItem("Burger", 5, BigDecimal.valueOf(5)), + new InvoiceItem("Coke", 1, BigDecimal.valueOf(5)))), + new Invoice("Crusty Burger", "Bart", Arrays.asList( + new InvoiceItem("Coke", 1, BigDecimal.valueOf(5))))); + } +} diff --git a/src/test/java/de/codecentric/java8examples/TestUtil.java b/src/test/java/de/codecentric/java8examples/TestUtil.java deleted file mode 100644 index 36b71ee..0000000 --- a/src/test/java/de/codecentric/java8examples/TestUtil.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.codecentric.java8examples; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Utility class that generates some test data for us. - */ -public class TestUtil { - - public static Date dateOf(int month, int day, int year) { - return new Date(LocalDate.of(year, month, day).toEpochDay()); - } - - public static List getPersons() { - List list = new ArrayList<>(); - list.add(new Person("Jane", "Jungle", dateOf(12, 15, 1978), Person.Gender.FEMALE)); - list.add(new Person("Mary", "Smith", dateOf(10, 19, 1980), Person.Gender.FEMALE)); - list.add(new Person("John", "Dole", dateOf(5, 31, 1973), Person.Gender.MALE)); - list.add(new Person("Michael", "Abrahams", dateOf(2, 1, 1967), Person.Gender.MALE)); - list.add(new Person("Chris", "Cross", dateOf(8, 22, 1985), Person.Gender.MALE)); - list.add(new Person("Pete", "Power", dateOf(3, 18, 1981), Person.Gender.MALE)); - return list; - } -} diff --git a/src/test/java/de/codecentric/java8examples/lambdas/LambdaBasedComparatorTest.java b/src/test/java/de/codecentric/java8examples/lambdas/LambdaBasedComparatorTest.java index 1d1a737..e9e7f58 100644 --- a/src/test/java/de/codecentric/java8examples/lambdas/LambdaBasedComparatorTest.java +++ b/src/test/java/de/codecentric/java8examples/lambdas/LambdaBasedComparatorTest.java @@ -1,6 +1,6 @@ package de.codecentric.java8examples.lambdas; -import static de.codecentric.java8examples.TestUtil.getPersons; +import static de.codecentric.java8examples.TestData.listOfPersons; import static org.hamcrest.number.OrderingComparison.lessThanOrEqualTo; import static org.junit.Assert.assertThat; @@ -21,7 +21,7 @@ public class LambdaBasedComparatorTest { @Before public void setUp() throws Exception { - persons = getPersons(); + persons = listOfPersons(); } @Test diff --git a/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java b/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java index 676c108..abe63fd 100644 --- a/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java +++ b/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java @@ -1,9 +1,9 @@ package de.codecentric.java8examples.lambdas; -import static de.codecentric.java8examples.TestUtil.dateOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.time.LocalDate; import java.util.function.Predicate; import de.codecentric.java8examples.Person; @@ -21,7 +21,7 @@ public class LambdaExampleTest { @Before public void setUp() throws Exception { // Nerd info: 5/15/1962 was the release date of Amazing Fantasy #15, where Spider Man had his first appearance - peter = new Person("Peter", "Parker", dateOf(8, 15, 1962), Person.Gender.MALE); + peter = new Person("Peter", "Parker", LocalDate.of(1962, 8, 15), Person.Gender.MALE); example = new LambdaExample<>(peter); } diff --git a/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java b/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java new file mode 100644 index 0000000..e060896 --- /dev/null +++ b/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java @@ -0,0 +1,68 @@ +package de.codecentric.java8examples.streaming; + +import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.Person; +import de.codecentric.java8examples.TestData; +import org.hamcrest.MatcherAssert; +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.assertThat; + +/** + * Tests for mapping and filtering feature of the streaming api. Once you have completed the stub-methods in + * {@link FilteringAndMapping}, these tests should pass. + */ +public class FilteringAndMappingTest { + + private List persons = TestData.listOfPersons(); + + private List invoices = TestData.listOfInvoices(); + + @Test + public void collectFirstNamesOfFemales() throws Exception { + // Matchers.contains should really be called "containsExactlyTheseElementsAndNoOtherElementsInExactlyThisOrder" + // I hate hamcrest :( + assertThat(FilteringAndMapping.extractFemaleFirstnames(persons), contains("Jane", "Mary", "Maggie")); + } + + @Test + public void extractNames() { + assertThat( + FilteringAndMapping.extractNames(persons.subList(0, 6)), + contains("Jane Jungle", "Mary Smitch", "John Dole", "Michael Abrams", "Chris Cross", "Peter Power")); + } + + @Test + public void extractNamesSortedByLastname() { + assertThat( + FilteringAndMapping.extractNamesSortedByLastname(persons.subList(0, 6)), + contains("Michael Abrams", "Chris Cross", "John Dole", "Jane Jungle", "Peter Power", "Mary Smitch")); + } + + @Test + public void extractAdultWomen() { + // Yes, I know, this test is time-dependent and will break in a few months/years... + assertThat( + FilteringAndMapping.extractAdultWomen(persons), + contains( + persons.get(0), + persons.get(1))); + } + + @Test + public void extractFirstnamesWhereLastnameStartsWith() { + assertThat( + FilteringAndMapping.extractFirstnamesWhereLastnameStartsWith(persons, "S"), + contains("Mary", "Maggie")); + } + + @Test + public void testExtractAllProducts() throws Exception { + MatcherAssert.assertThat(FilteringAndMapping.extractAllProducts(invoices), + containsInAnyOrder("Beer", "Burrito", "Coke")); + } +} diff --git a/src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java b/src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java new file mode 100644 index 0000000..a63f256 --- /dev/null +++ b/src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java @@ -0,0 +1,14 @@ +package de.codecentric.java8examples.streaming; + + +import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.TestData; +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class FlatMapTest { +} diff --git a/src/test/java/de/codecentric/java8examples/streaming/StreamingApiTest.java b/src/test/java/de/codecentric/java8examples/streaming/StreamingApiTest.java deleted file mode 100644 index 142bdbb..0000000 --- a/src/test/java/de/codecentric/java8examples/streaming/StreamingApiTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package de.codecentric.java8examples.streaming; - -import static de.codecentric.java8examples.TestUtil.getPersons; -import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; -import static org.junit.Assert.assertThat; - -import java.util.List; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.junit.Before; -import org.junit.Test; - -import de.codecentric.java8examples.Person; - -/** - * Test case showing the use of the streaming API. - */ -public class StreamingApiTest { - - private List persons; - - @Before - public void setUp() throws Exception { - persons = getPersons(); - } - - @Test - public void collectLastNamesOfFemales() throws Exception { - List femaleLastNames = - persons.stream() - .filter(p -> p.getGender().equals(Person.Gender.FEMALE)) - . map(p -> p.getLastName()) - .collect(Collectors. toList()); - - assertThat(femaleLastNames, containsInAnyOrder("Jungle", "Smith")); - } - - @Test - public void testName() throws Exception { - Stream stream = Stream.generate(new Supplier() { - int count = 0; - - @Override - public Integer get() { - System.out.println("get" + count); - return count++; - } - }); - - stream - .filter(i -> i.intValue() % 2 == 0) - .limit(100); - - - } -} From 05df5bbad9bdcc6b139e7dfba5f4cdca823df185 Mon Sep 17 00:00:00 2001 From: "daniel.reuter@codecentric.de" Date: Thu, 28 Nov 2013 12:49:42 +0100 Subject: [PATCH 02/23] Maven und Time-Test --- pom.xml | 3 --- .../codecentric/java8examples/timeapi/TimeApiTest.java | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index fd23cad..3d02b42 100644 --- a/pom.xml +++ b/pom.xml @@ -39,9 +39,6 @@ org.apache.maven.plugins maven-eclipse-plugin - - org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0 - true true 1.8 diff --git a/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java b/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java index 2a6e6e7..a86fec7 100644 --- a/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java +++ b/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java @@ -80,14 +80,14 @@ public void timeBetweenToDates() { Period between = Period.between(birthday, LocalDate.now()); System.out.println(between.getYears() + " Years " + between.getMonths() + " Months " + between.getDays() + " Days."); assertEquals(32, between.getYears()); - assertEquals(1, between.getMonths()); + assertEquals(2, between.getMonths()); // Joda org.joda.time.LocalDate birthdayJoda = new org.joda.time.LocalDate(1981, 9, 3); org.joda.time.Period betweenJoda = new org.joda.time.Period(birthdayJoda, org.joda.time.LocalDate.now()); System.out.println(betweenJoda.getYears() + " Years " + betweenJoda.getMonths() + " Months " + betweenJoda.getDays() + " Days."); assertEquals(32, betweenJoda.getYears()); - assertEquals(1, betweenJoda.getMonths()); + assertEquals(2, betweenJoda.getMonths()); } @Test @@ -152,7 +152,7 @@ public void timezoneAndOffset() { ZonedDateTime zonedDateTimeEurope = ZonedDateTime.now(); ZonedDateTime zonedDateTimeUTC = ZonedDateTime.now(ZoneId.of("UTC")); - assertEquals(60 * 60 * 2, zonedDateTimeEurope.getOffset().getTotalSeconds()); + assertEquals(60 * 60 * 1, zonedDateTimeEurope.getOffset().getTotalSeconds()); assertEquals("Europe/Berlin", zonedDateTimeEurope.getZone().getId()); assertFalse(zonedDateTimeEurope.isBefore(zonedDateTimeUTC)); assertFalse(zonedDateTimeEurope.isAfter(zonedDateTimeUTC)); @@ -162,7 +162,7 @@ public void timezoneAndOffset() { DateTime dateTimeEuropeJoda = DateTime.now(); DateTime dateTimeUTCJoda = DateTime.now(DateTimeZone.UTC); - assertEquals(60 * 60 * 2 * 1000, dateTimeEuropeJoda.getZone().getOffset(dateTimeEuropeJoda.getMillis())); + assertEquals(60 * 60 * 1 * 1000, dateTimeEuropeJoda.getZone().getOffset(dateTimeEuropeJoda.getMillis())); assertEquals("Europe/Berlin", dateTimeEuropeJoda.getZone().getID()); assertFalse(dateTimeEuropeJoda.isBefore(dateTimeUTCJoda)); assertFalse(dateTimeEuropeJoda.isAfter(dateTimeUTCJoda)); @@ -170,7 +170,7 @@ public void timezoneAndOffset() { } // TODO Formatting & Parsing - // TODO Conversion Hibernate? SQL - zurück zu util.date + // TODO Conversion Hibernate? SQL - zur��ck zu util.date // TODO Null-Handling und beschriebene Unterschiede } \ No newline at end of file From c7486795652a152d99d2f2fd781d3b0265c7a07f Mon Sep 17 00:00:00 2001 From: Daniel Reuter Date: Thu, 28 Nov 2013 19:23:13 +0100 Subject: [PATCH 03/23] JSR-310 Parsing-Formatting --- .../java8examples/timeapi/TimeApiTest.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java b/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java index a86fec7..b21cfe2 100644 --- a/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java +++ b/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java @@ -10,6 +10,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.chrono.ThaiBuddhistDate; +import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; import org.joda.time.DateTime; @@ -17,15 +18,14 @@ import org.joda.time.DateTimeZone; import org.joda.time.Interval; import org.joda.time.chrono.BuddhistChronology; +import org.joda.time.format.DateTimeFormat; import org.junit.Test; /** * Why JSR-310 isn't Joda-Time
* nice presentation (JUG Ukraine)
* project page
- * examples 1
- * examples 2
- * Java-Doc/a>
+ *
Java-Doc
* *
*

Joda

@@ -87,7 +87,7 @@ public void timeBetweenToDates() { org.joda.time.Period betweenJoda = new org.joda.time.Period(birthdayJoda, org.joda.time.LocalDate.now()); System.out.println(betweenJoda.getYears() + " Years " + betweenJoda.getMonths() + " Months " + betweenJoda.getDays() + " Days."); assertEquals(32, betweenJoda.getYears()); - assertEquals(2, betweenJoda.getMonths()); + assertEquals(2, betweenJoda.getMonths()); } @Test @@ -154,7 +154,7 @@ public void timezoneAndOffset() { assertEquals(60 * 60 * 1, zonedDateTimeEurope.getOffset().getTotalSeconds()); assertEquals("Europe/Berlin", zonedDateTimeEurope.getZone().getId()); - assertFalse(zonedDateTimeEurope.isBefore(zonedDateTimeUTC)); + assertFalse(zonedDateTimeEurope.isBefore(zonedDateTimeUTC)); assertFalse(zonedDateTimeEurope.isAfter(zonedDateTimeUTC)); assertTrue(zonedDateTimeEurope.isEqual(zonedDateTimeUTC)); @@ -169,8 +169,19 @@ public void timezoneAndOffset() { assertTrue(dateTimeEuropeJoda.isEqual(dateTimeUTCJoda)); } - // TODO Formatting & Parsing - // TODO Conversion Hibernate? SQL - zur��ck zu util.date - // TODO Null-Handling und beschriebene Unterschiede + @Test + public void parsingAndFormatting() { + // JSR-310 + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + LocalDate parsedDate = LocalDate.parse("03.09.1981", fmt); + assertEquals(LocalDate.of(1981, 9, 3), parsedDate); + assertEquals("03.09.1981", fmt.format(LocalDate.of(1981, 9, 3))); + + // Joda + org.joda.time.format.DateTimeFormatter fmtJoda = DateTimeFormat.forPattern("dd.MM.yyyy"); + org.joda.time.LocalDate parsedDateJoda = org.joda.time.LocalDate.parse("03.09.1981", fmtJoda); + assertEquals(new org.joda.time.LocalDate(1981, 9, 3), parsedDateJoda); + assertEquals("03.09.1981", fmtJoda.print(new org.joda.time.LocalDate(1981, 9, 3))); + } } \ No newline at end of file From f99f0afeae65c2e2ebd7f2560689b6601bf5b3a8 Mon Sep 17 00:00:00 2001 From: Daniel Reuter Date: Fri, 29 Nov 2013 10:52:43 +0100 Subject: [PATCH 04/23] java.util.Date - examples --- .../java8examples/timeapi/TimeApiTest.java | 93 ++++++++++++++++--- 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java b/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java index b21cfe2..419aee6 100644 --- a/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java +++ b/src/test/java/de/codecentric/java8examples/timeapi/TimeApiTest.java @@ -4,7 +4,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.Month; import java.time.Period; import java.time.ZoneId; @@ -12,6 +16,10 @@ import java.time.chrono.ThaiBuddhistDate; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; import org.joda.time.DateTime; import org.joda.time.DateTimeFieldType; @@ -21,6 +29,8 @@ import org.joda.time.format.DateTimeFormat; import org.junit.Test; +import sun.util.BuddhistCalendar; + /** * Why JSR-310 isn't Joda-Time
* nice presentation (JUG Ukraine)
@@ -88,6 +98,14 @@ public void timeBetweenToDates() { System.out.println(betweenJoda.getYears() + " Years " + betweenJoda.getMonths() + " Months " + betweenJoda.getDays() + " Days."); assertEquals(32, betweenJoda.getYears()); assertEquals(2, betweenJoda.getMonths()); + + // Date & Calendar + Calendar birthdayCalendar = Calendar.getInstance(); + birthdayCalendar.set(1981, Calendar.SEPTEMBER, 3); + int diffYears = Calendar.getInstance().get(Calendar.YEAR) - birthdayCalendar.get(Calendar.YEAR); + int diffMonth = Calendar.getInstance().get(Calendar.MONTH) - birthdayCalendar.get(Calendar.MONTH); + assertEquals(32, diffYears); + assertEquals(2, diffMonth); } @Test @@ -102,11 +120,23 @@ public void checkDateIsInInterval() { Interval interval = new Interval(new DateTime(1981, 9, 3, 12, 0), DateTime.now()); assertFalse(interval.contains(new DateTime(1980, 1, 1, 12, 0))); assertTrue(interval.contains(new DateTime(1985, 1, 1, 12, 0))); + + // Date & Calendar + Calendar birthdayCalendar = Calendar.getInstance(); + birthdayCalendar.set(1981, Calendar.SEPTEMBER, 3); + Calendar nowCalendar = Calendar.getInstance(); + assertFalse(checkInterval(birthdayCalendar, nowCalendar, new GregorianCalendar(1980, 1, 1))); + assertTrue(checkInterval(birthdayCalendar, nowCalendar, new GregorianCalendar(1985, 1, 1))); + } private boolean checkInterval(LocalDate from, LocalDate to, LocalDate date) { return from.isBefore(date) && to.isAfter(date); } + + private boolean checkInterval(Calendar from, Calendar to, Calendar date) { + return date.getTime().after(from.getTime()) && date.getTime().before(to.getTime()); + } @Test public void calculate5Years() { @@ -123,18 +153,24 @@ public void calculate5Years() { assertEquals(birthdayPlusJoda.getDayOfMonth(), 3); assertEquals(birthdayPlusJoda.getMonthOfYear(), 9); assertEquals(birthdayPlusJoda.getYear(), 1991); + + // Date & Calendar + Calendar birthdayCalendar = Calendar.getInstance(); + birthdayCalendar.set(1981, Calendar.SEPTEMBER, 3); + birthdayCalendar.add(Calendar.YEAR,10); + assertEquals(birthdayCalendar.get(Calendar.DAY_OF_MONTH), 3); + // !! 0-based + assertEquals(birthdayCalendar.get(Calendar.MONTH), Calendar.SEPTEMBER); + assertEquals(birthdayCalendar.get(Calendar.YEAR), 1991); } @Test public void chronologies() { // JSR-310 ThaiBuddhistDate thaiBuddhistDate = ThaiBuddhistDate.now(); - System.out.println(thaiBuddhistDate.getChronology()); int thaiYear = thaiBuddhistDate.get(ChronoField.YEAR); LocalDate isoDate = LocalDate.now(); - System.out.println(isoDate.getChronology()); int isoYear = isoDate.get(ChronoField.YEAR); - assertEquals(thaiYear, isoYear + 543); // Joda @@ -142,39 +178,59 @@ public void chronologies() { int buddhistYearJoda = buddhistDateJoda.get(DateTimeFieldType.year()); org.joda.time.LocalDate dateJoda = new org.joda.time.LocalDate(); int yearJoda = dateJoda.get(DateTimeFieldType.year()); - assertEquals(buddhistYearJoda, yearJoda + 543); + + // Date & Calendar + BuddhistCalendar buddhistCalendar = new BuddhistCalendar(); + int buddhistYearCalendar = buddhistCalendar.get(BuddhistCalendar.YEAR); + Calendar calendar = Calendar.getInstance(); + int yearCalendar = calendar.get(Calendar.YEAR); + assertEquals(buddhistYearCalendar, yearCalendar + 543); } + @Test - public void timezoneAndOffset() { + public void timezoneAndOffset() throws InterruptedException { // JSR-310 - ZonedDateTime zonedDateTimeEurope = ZonedDateTime.now(); - ZonedDateTime zonedDateTimeUTC = ZonedDateTime.now(ZoneId.of("UTC")); + LocalDateTime dateTime = LocalDateTime.now(); + ZonedDateTime zonedDateTimeEurope = ZonedDateTime.of(dateTime, ZoneId.systemDefault()); + ZonedDateTime zonedDateTimeUTC = ZonedDateTime.of(dateTime, ZoneId.of("UTC")); assertEquals(60 * 60 * 1, zonedDateTimeEurope.getOffset().getTotalSeconds()); assertEquals("Europe/Berlin", zonedDateTimeEurope.getZone().getId()); - assertFalse(zonedDateTimeEurope.isBefore(zonedDateTimeUTC)); + //!! + assertTrue(zonedDateTimeEurope.isBefore(zonedDateTimeUTC)); assertFalse(zonedDateTimeEurope.isAfter(zonedDateTimeUTC)); - assertTrue(zonedDateTimeEurope.isEqual(zonedDateTimeUTC)); + assertFalse(zonedDateTimeEurope.isEqual(zonedDateTimeUTC)); // Joda - DateTime dateTimeEuropeJoda = DateTime.now(); - DateTime dateTimeUTCJoda = DateTime.now(DateTimeZone.UTC); + Date date = new Date(); + DateTime dateTimeEuropeJoda = new DateTime(date.getTime(),DateTimeZone.getDefault()); + DateTime dateTimeUTCJoda = new DateTime(date.getTime(),DateTimeZone.UTC); assertEquals(60 * 60 * 1 * 1000, dateTimeEuropeJoda.getZone().getOffset(dateTimeEuropeJoda.getMillis())); assertEquals("Europe/Berlin", dateTimeEuropeJoda.getZone().getID()); + //!! assertFalse(dateTimeEuropeJoda.isBefore(dateTimeUTCJoda)); assertFalse(dateTimeEuropeJoda.isAfter(dateTimeUTCJoda)); assertTrue(dateTimeEuropeJoda.isEqual(dateTimeUTCJoda)); + + // Date & Calendar + Calendar calendarEurope = Calendar.getInstance(); + calendarEurope.setTime(date); + Calendar calendarUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + calendarEurope.setTime(date); + assertFalse(calendarEurope.getTime().before(calendarUTC.getTime())); + assertFalse(calendarEurope.getTime().after(calendarUTC.getTime())); + assertTrue(calendarEurope.getTime().equals(calendarUTC.getTime())); } @Test public void parsingAndFormatting() { // JSR-310 DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd.MM.yyyy"); - LocalDate parsedDate = LocalDate.parse("03.09.1981", fmt); - assertEquals(LocalDate.of(1981, 9, 3), parsedDate); + LocalDate parsedLocalDate = LocalDate.parse("03.09.1981", fmt); + assertEquals(LocalDate.of(1981, 9, 3), parsedLocalDate); assertEquals("03.09.1981", fmt.format(LocalDate.of(1981, 9, 3))); // Joda @@ -182,6 +238,17 @@ public void parsingAndFormatting() { org.joda.time.LocalDate parsedDateJoda = org.joda.time.LocalDate.parse("03.09.1981", fmtJoda); assertEquals(new org.joda.time.LocalDate(1981, 9, 3), parsedDateJoda); assertEquals("03.09.1981", fmtJoda.print(new org.joda.time.LocalDate(1981, 9, 3))); + + // Date & Calendar + DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); + Date parsedDate = null; + try { + parsedDate= dateFormat.parse("03.09.1981"); + } catch (ParseException e) { + // handle + } + assertEquals(new GregorianCalendar(1981, Calendar.SEPTEMBER,3).getTime(), parsedDate); + assertEquals("03.09.1981", dateFormat.format(new GregorianCalendar(1981, Calendar.SEPTEMBER,3).getTime())); } } \ No newline at end of file From d301105ef0f2edec1b15b1c8f63d4aa829020c73 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Fri, 29 Nov 2013 11:02:33 +0100 Subject: [PATCH 05/23] Tasks for collecting and reducing streams. --- .../java8examples/streaming/Collecting.java | 38 ------ .../streaming/CollectingAndReducing.java | 125 ++++++++++++++++++ .../codecentric/java8examples/TestData.java | 18 ++- .../streaming/CollectingAndReducingTest.java | 78 +++++++++++ .../java8examples/streaming/FlatMapTest.java | 14 -- 5 files changed, 220 insertions(+), 53 deletions(-) delete mode 100644 src/main/java/de/codecentric/java8examples/streaming/Collecting.java create mode 100644 src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java create mode 100644 src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java delete mode 100644 src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java diff --git a/src/main/java/de/codecentric/java8examples/streaming/Collecting.java b/src/main/java/de/codecentric/java8examples/streaming/Collecting.java deleted file mode 100644 index a13661b..0000000 --- a/src/main/java/de/codecentric/java8examples/streaming/Collecting.java +++ /dev/null @@ -1,38 +0,0 @@ -package de.codecentric.java8examples.streaming; - -import de.codecentric.java8examples.Invoice; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -/** - * Your task: Implement the following methods and make the tests passs. - */ -public class Collecting { - - /** - * Identify the cheapest product (by pricePerUnit) in all invoices. - */ - public static String cheapestProduct(List invoices) { - return ""; - } - - /** - * Identify the invoice with the highest total amount. - */ - public static Invoice mostExpensiveInvoice(List invoices) { - return null; - } - - /** - * For every product, compute the cheapest dealer. Return as a Map where the key is the product name and the value - * is the dealer (=sender of the invoice). - */ - public static Map cheapestDealersByProduct() { - return Collections.emptyMap(); - } - -} diff --git a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java new file mode 100644 index 0000000..ce04d53 --- /dev/null +++ b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java @@ -0,0 +1,125 @@ +package de.codecentric.java8examples.streaming; + +import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.Person; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Stream; + +/** + * Your task: Implement the following methods and make the tests passs. + */ +public class CollectingAndReducing { + + /** + * Compute the average age of the given list of Persons. + */ + public static Double averageAge(List persons) { + return Double.valueOf(0); + } + + /** + * How old is the oldest person in the given list. + */ + public static Integer maxAge(List persons) { + return Integer.valueOf(0); + } + + /** + * Compute Age-Statistics (max, min, average, ...) for the given list of Persons. + */ + public static DoubleSummaryStatistics ageStatistics(List persons) { + return null; + } + + /** + * Build a comma-separated list of the firstnames of a list of Persons. + * + * Example-Result: "Maggie, Marge, Mary" + */ + public static String buildCommaSeparatedListOfFirstNames(List persons) { + return ""; + } + + /** + * Identify the cheapest product (by pricePerUnit) in all invoices. + */ + public static String cheapestProduct(List invoices) { + return ""; + } + + /** + * Identify the invoice with the highest total amount. + */ + public static Invoice mostExpensiveInvoice(List invoices) { + return null; + } + + /** + * Just what the method name says. + */ + public static Map> groupInvoicesByReceiver(List invoices) { + return Collections.emptyMap(); + } + + /** + * Compute the total amount, that each receiver spent. + * + * Hint: Use the two-argument version of Collectors.groupingBy together with Collectors.mapping. + */ + public static Map expensesByReceiver(List invoices) { + return Collections.emptyMap(); + } + + /** + * How many items of each product have been purchased? + */ + public static Map countByProduct(List invoices) { + return Collections.emptyMap(); + } + + /** + * For every product, compute the cheapest dealer. Return as a Map where the key is the product name and the value + * is the dealer (=sender of the invoice). + */ + public static Map cheapestDealersByProduct(List invoices) { + return Collections.emptyMap(); + } + + /** + * From a given list of invoices, compute for every dealer the available products together with its price. + */ + public static Map computeDealerInventory(List invoices) { + return Collections.emptyMap(); + } + + /** + * For every buyer, compute a list of his favorite products (that is: a list of products ordered by the total count + * of items bought). + * For example: Homer bought 5 beers at Moes, 2 beers and a burger at Crustys. Then the result should look like this: + * {"Homer" -> ["Beer", "Burger"]} + */ + public static Map> favoriteArticlesByBuyer(List invoices) { + return Collections.EMPTY_MAP; + } + + public static class ProductWithPrice { + private String productName; + private BigDecimal price; + + public ProductWithPrice(String productName, BigDecimal price) { + this.productName = productName; + this.price = price; + } + + public String getProductName() { + return productName; + } + + public BigDecimal getPrice() { + return price; + } + } + +} diff --git a/src/test/java/de/codecentric/java8examples/TestData.java b/src/test/java/de/codecentric/java8examples/TestData.java index ce92165..26ffe1b 100644 --- a/src/test/java/de/codecentric/java8examples/TestData.java +++ b/src/test/java/de/codecentric/java8examples/TestData.java @@ -31,6 +31,22 @@ public static List listOfInvoices() { new InvoiceItem("Burger", 5, BigDecimal.valueOf(5)), new InvoiceItem("Coke", 1, BigDecimal.valueOf(5)))), new Invoice("Crusty Burger", "Bart", Arrays.asList( - new InvoiceItem("Coke", 1, BigDecimal.valueOf(5))))); + new InvoiceItem("Coke", 1, BigDecimal.valueOf(5)))), + new Invoice("Kwik-E-Mart", "Homer", Arrays.asList( + new InvoiceItem("Beer", 9, BigDecimal.valueOf(0.9)), + new InvoiceItem("Chips", 2, BigDecimal.valueOf(0.5)))), + new Invoice("Moe", "Marge", Arrays.asList( + new InvoiceItem("Beer", 1, BigDecimal.valueOf(1.5)))), + new Invoice("Kwik-E-Mart", "Bart", Arrays.asList( + new InvoiceItem("Coke", 2, BigDecimal.valueOf(2.5)), + new InvoiceItem("Chips", 2, BigDecimal.valueOf(0.5)))), + new Invoice("Kwik-E-Mart", "Marge", Arrays.asList( + new InvoiceItem("Cake", 2, BigDecimal.valueOf(3.4)), + new InvoiceItem("Corn Flakes", 5, BigDecimal.valueOf(2.3)))), + new Invoice("Moe", "Homer", Arrays.asList( + new InvoiceItem("Beer", 5, BigDecimal.valueOf(1.5)))), + new Invoice("Flander's Left-Handed Store", "Marge", Arrays.asList( + new InvoiceItem("Left-Handed Scissors", 1, BigDecimal.valueOf(10.0)))) + ); } } diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java new file mode 100644 index 0000000..208eaa2 --- /dev/null +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -0,0 +1,78 @@ +package de.codecentric.java8examples.streaming; + +import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.Person; +import de.codecentric.java8examples.TestData; +import org.junit.Test; + +import java.util.List; + +/** + * Tests for mapping and filtering feature of the streaming api. Once you have completed the stub-methods in + * {@link FilteringAndMapping}, these tests should pass. + */ +public class CollectingAndReducingTest { + private List persons = TestData.listOfPersons(); + + private List invoices = TestData.listOfInvoices(); + + @Test + public void testAverageAge() throws Exception { + + } + + @Test + public void testMaxAge() throws Exception { + + } + + @Test + public void testAgeStatistics() throws Exception { + + } + + @Test + public void testBuildCommaSeparatedListOfFirstNames() throws Exception { + + } + + @Test + public void testCheapestProduct() throws Exception { + + } + + @Test + public void testMostExpensiveInvoice() throws Exception { + + } + + @Test + public void testGroupInvoicesByReceiver() throws Exception { + + } + + @Test + public void testExpensesByReceiver() throws Exception { + + } + + @Test + public void testCountByProduct() throws Exception { + + } + + @Test + public void testCheapestDealersByProduct() throws Exception { + + } + + @Test + public void testComputeDealerInventory() throws Exception { + + } + + @Test + public void testFavoriteArticlesByBuyer() throws Exception { + + } +} diff --git a/src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java b/src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java deleted file mode 100644 index a63f256..0000000 --- a/src/test/java/de/codecentric/java8examples/streaming/FlatMapTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.codecentric.java8examples.streaming; - - -import de.codecentric.java8examples.Invoice; -import de.codecentric.java8examples.TestData; -import org.junit.Test; - -import java.util.List; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class FlatMapTest { -} From 414add4efd8df7c22e040c9602664967587d2005 Mon Sep 17 00:00:00 2001 From: Benedikt Ritter Date: Fri, 29 Nov 2013 11:07:20 +0100 Subject: [PATCH 06/23] Add example for anonymous implementation of callback --- .../MethodReferenceExampleTest.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/codecentric/java8examples/methodreference/MethodReferenceExampleTest.java b/src/test/java/de/codecentric/java8examples/methodreference/MethodReferenceExampleTest.java index 783d30b..ebff4c1 100644 --- a/src/test/java/de/codecentric/java8examples/methodreference/MethodReferenceExampleTest.java +++ b/src/test/java/de/codecentric/java8examples/methodreference/MethodReferenceExampleTest.java @@ -20,7 +20,19 @@ public void setUp() throws Exception { } @Test - public void methodReferencToFooMethod() throws Exception { + public void callbackWithoutMethodReference() throws Exception { + Callable callable = new Callable() { + @Override + public String call() throws Exception { + return myFoo.doSomething(); + } + }; + + assertEquals(myFoo.doSomething(), callable.call()); + } + + @Test + public void callbackWithMethodReference() throws Exception { Callable callable = myFoo::doSomething; assertEquals(myFoo.doSomething(), callable.call()); From 280ecaee497da0a3d10793c74b13cd0f01217d27 Mon Sep 17 00:00:00 2001 From: Benedikt Ritter Date: Fri, 29 Nov 2013 11:17:59 +0100 Subject: [PATCH 07/23] Add example for different favors of implementing a lambda --- .../java8examples/lambdas/LambdaExampleTest.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java b/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java index abe63fd..3feb748 100644 --- a/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java +++ b/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java @@ -34,10 +34,24 @@ public boolean test(Person person) { return person.getAge() > 30; } })); + } + + @Test + public void peterIsOlderThan30WithBlockLambda() throws Exception { + // new: implement the predicate using a block lambda expression + assertTrue(example.matches((Person p) -> { + return p.getAge() > 30; + })); + } - // new: implement the predicate using lambda expression + @Test + public void peterIsOlderThan30WithOneLineLambda() throws Exception { + // implement the predicate using a one line lambda expression assertTrue(example.matches((Person person) -> person.getAge() > 30)); + } + @Test + public void peterIsOlderThan30WithTypeInference() throws Exception { // even shorter: let the compiler work out the correct type assertTrue(example.matches(p -> p.getAge() > 30)); } From d082c8efbb8070d8e5cbde3e88630d4f0a580560 Mon Sep 17 00:00:00 2001 From: Daniel Reuter Date: Fri, 29 Nov 2013 13:23:12 +0100 Subject: [PATCH 08/23] Fixed test cases --- .../streaming/FilteringAndMappingTest.java | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java b/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java index e060896..ea28169 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java @@ -13,8 +13,8 @@ import static org.junit.Assert.assertThat; /** - * Tests for mapping and filtering feature of the streaming api. Once you have completed the stub-methods in - * {@link FilteringAndMapping}, these tests should pass. + * Tests for mapping and filtering feature of the streaming api. Once you have completed the stub-methods in {@link FilteringAndMapping}, these tests should + * pass. */ public class FilteringAndMappingTest { @@ -24,45 +24,36 @@ public class FilteringAndMappingTest { @Test public void collectFirstNamesOfFemales() throws Exception { - // Matchers.contains should really be called "containsExactlyTheseElementsAndNoOtherElementsInExactlyThisOrder" - // I hate hamcrest :( - assertThat(FilteringAndMapping.extractFemaleFirstnames(persons), contains("Jane", "Mary", "Maggie")); + // Matchers.contains should really be called "containsExactlyTheseElementsAndNoOtherElementsInExactlyThisOrder" + // I hate hamcrest :( + assertThat(FilteringAndMapping.extractFemaleFirstnames(persons), contains("Jane", "Mary", "Maggie")); } @Test public void extractNames() { - assertThat( - FilteringAndMapping.extractNames(persons.subList(0, 6)), - contains("Jane Jungle", "Mary Smitch", "John Dole", "Michael Abrams", "Chris Cross", "Peter Power")); + assertThat(FilteringAndMapping.extractNames(persons.subList(0, 6)), + contains("Jane Jungle", "Mary Smith", "John Dole", "Michael Abrahams", "Chris Cross", "Pete Power")); } @Test public void extractNamesSortedByLastname() { - assertThat( - FilteringAndMapping.extractNamesSortedByLastname(persons.subList(0, 6)), - contains("Michael Abrams", "Chris Cross", "John Dole", "Jane Jungle", "Peter Power", "Mary Smitch")); + assertThat(FilteringAndMapping.extractNamesSortedByLastname(persons.subList(0, 6)), + contains("Michael Abrahams", "Chris Cross", "John Dole", "Jane Jungle", "Pete Power", "Mary Smith")); } @Test public void extractAdultWomen() { - // Yes, I know, this test is time-dependent and will break in a few months/years... - assertThat( - FilteringAndMapping.extractAdultWomen(persons), - contains( - persons.get(0), - persons.get(1))); + // Yes, I know, this test is time-dependent and will break in a few months/years... + assertThat(FilteringAndMapping.extractAdultWomen(persons), contains(persons.get(0), persons.get(1))); } @Test public void extractFirstnamesWhereLastnameStartsWith() { - assertThat( - FilteringAndMapping.extractFirstnamesWhereLastnameStartsWith(persons, "S"), - contains("Mary", "Maggie")); + assertThat(FilteringAndMapping.extractFirstnamesWhereLastnameStartsWith(persons, "S"), contains("Maggie", "Mary")); } @Test public void testExtractAllProducts() throws Exception { - MatcherAssert.assertThat(FilteringAndMapping.extractAllProducts(invoices), - containsInAnyOrder("Beer", "Burrito", "Coke")); + MatcherAssert.assertThat(FilteringAndMapping.extractAllProducts(invoices), containsInAnyOrder("Beer", "Burrito", "Coke")); } } From e164a3b7b28965acf5ef5cba2f428b96266d08c4 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Fri, 29 Nov 2013 13:51:35 +0100 Subject: [PATCH 09/23] Tests for CollectingAndReducing. --- .../de/codecentric/java8examples/Invoice.java | 43 ++++++++++++ .../java8examples/InvoiceItem.java | 31 +++++++++ .../streaming/CollectingAndReducing.java | 61 ++++++++++++----- .../streaming/FilteringAndMapping.java | 1 + .../codecentric/java8examples/TestData.java | 6 +- .../streaming/CollectingAndReducingTest.java | 67 ++++++++++++++++--- 6 files changed, 180 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/codecentric/java8examples/Invoice.java b/src/main/java/de/codecentric/java8examples/Invoice.java index 65e0418..bc82460 100644 --- a/src/main/java/de/codecentric/java8examples/Invoice.java +++ b/src/main/java/de/codecentric/java8examples/Invoice.java @@ -1,6 +1,8 @@ package de.codecentric.java8examples; +import java.math.BigDecimal; import java.util.List; +import java.util.stream.Collectors; public class Invoice { @@ -20,9 +22,50 @@ public List getItems() { return items; } + public BigDecimal getTotal() { + return getItems().stream() + .map(invoice -> invoice + .getPricePerUnit() + .multiply(BigDecimal.valueOf(invoice.getQuantity()))) + .collect(Collectors.reducing( + BigDecimal.ZERO, + (sum, elem) -> sum.add(elem))); + } + public Invoice(String sender, String recipient, List items) { this.sender = sender; this.recipient = recipient; this.items = items; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Invoice invoice = (Invoice) o; + + if (items != null ? !items.equals(invoice.items) : invoice.items != null) return false; + if (recipient != null ? !recipient.equals(invoice.recipient) : invoice.recipient != null) return false; + if (sender != null ? !sender.equals(invoice.sender) : invoice.sender != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = sender != null ? sender.hashCode() : 0; + result = 31 * result + (recipient != null ? recipient.hashCode() : 0); + result = 31 * result + (items != null ? items.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Invoice{" + + "sender='" + sender + '\'' + + ", recipient='" + recipient + '\'' + + ", items=" + items + + '}'; + } } diff --git a/src/main/java/de/codecentric/java8examples/InvoiceItem.java b/src/main/java/de/codecentric/java8examples/InvoiceItem.java index 44ed6a4..3fb33bf 100644 --- a/src/main/java/de/codecentric/java8examples/InvoiceItem.java +++ b/src/main/java/de/codecentric/java8examples/InvoiceItem.java @@ -25,4 +25,35 @@ public InvoiceItem(String product, Integer quantity, BigDecimal pricePerUnit) { this.quantity = quantity; this.pricePerUnit = pricePerUnit; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InvoiceItem that = (InvoiceItem) o; + + if (pricePerUnit != null ? !pricePerUnit.equals(that.pricePerUnit) : that.pricePerUnit != null) return false; + if (product != null ? !product.equals(that.product) : that.product != null) return false; + if (quantity != null ? !quantity.equals(that.quantity) : that.quantity != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = product != null ? product.hashCode() : 0; + result = 31 * result + (quantity != null ? quantity.hashCode() : 0); + result = 31 * result + (pricePerUnit != null ? pricePerUnit.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "InvoiceItem{" + + "product='" + product + '\'' + + ", quantity=" + quantity + + ", pricePerUnit=" + pricePerUnit + + '}'; + } } diff --git a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java index ce04d53..9e74c6e 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java +++ b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java @@ -1,11 +1,12 @@ package de.codecentric.java8examples.streaming; import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.InvoiceItem; import de.codecentric.java8examples.Person; import java.math.BigDecimal; import java.util.*; -import java.util.stream.Stream; +import java.util.stream.Collectors; /** * Your task: Implement the following methods and make the tests passs. @@ -16,67 +17,93 @@ public class CollectingAndReducing { * Compute the average age of the given list of Persons. */ public static Double averageAge(List persons) { - return Double.valueOf(0); + return persons.stream() + .mapToInt(Person::getAge) + .average().getAsDouble(); + } /** * How old is the oldest person in the given list. */ public static Integer maxAge(List persons) { - return Integer.valueOf(0); + return persons.stream() + .mapToInt(Person::getAge) + .max().getAsInt(); } /** * Compute Age-Statistics (max, min, average, ...) for the given list of Persons. */ - public static DoubleSummaryStatistics ageStatistics(List persons) { - return null; + public static IntSummaryStatistics ageStatistics(List persons) { + return persons.stream() + .mapToInt(Person::getAge) + .summaryStatistics(); } /** * Build a comma-separated list of the firstnames of a list of Persons. - * + *

* Example-Result: "Maggie, Marge, Mary" */ public static String buildCommaSeparatedListOfFirstNames(List persons) { - return ""; + return persons.stream() + .map(Person::getFirstName) + .collect(Collectors.joining(", ")); } /** * Identify the cheapest product (by pricePerUnit) in all invoices. */ public static String cheapestProduct(List invoices) { - return ""; + return invoices.stream() + .flatMap(invoice -> invoice.getItems().stream()) + .min(Comparator.comparing(InvoiceItem::getPricePerUnit)) + .get().getProduct(); } /** * Identify the invoice with the highest total amount. */ public static Invoice mostExpensiveInvoice(List invoices) { - return null; + return invoices.stream() + .collect(Collectors.maxBy( + Comparator.comparing(Invoice::getTotal))).get(); } /** * Just what the method name says. */ - public static Map> groupInvoicesByReceiver(List invoices) { - return Collections.emptyMap(); + public static Map> groupInvoicesByRecipient(List invoices) { + return invoices.stream() + .collect(Collectors.groupingBy(Invoice::getRecipient)); } /** * Compute the total amount, that each receiver spent. - * + *

* Hint: Use the two-argument version of Collectors.groupingBy together with Collectors.mapping. */ - public static Map expensesByReceiver(List invoices) { - return Collections.emptyMap(); + public static Map expensesByRecipient(List invoices) { + return invoices.stream() + .collect(Collectors.groupingBy( + Invoice::getRecipient, + Collectors.mapping( + Invoice::getTotal, + Collectors.reducing( + BigDecimal.ZERO, + (sum, elem) -> sum.add(elem))))); } /** * How many items of each product have been purchased? */ - public static Map countByProduct(List invoices) { - return Collections.emptyMap(); + public static Map countByProduct(List invoices) { + return invoices.stream() + .flatMap(invoice -> invoice.getItems().stream()) + .collect(Collectors.groupingBy( + InvoiceItem::getProduct, + Collectors.summingInt(InvoiceItem::getQuantity))); } /** @@ -101,7 +128,7 @@ public static Map computeDealerInventory(List * {"Homer" -> ["Beer", "Burger"]} */ public static Map> favoriteArticlesByBuyer(List invoices) { - return Collections.EMPTY_MAP; + return Collections.emptyMap(); } public static class ProductWithPrice { diff --git a/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java index c751e9f..25c8574 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java +++ b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java @@ -1,6 +1,7 @@ package de.codecentric.java8examples.streaming; import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.InvoiceItem; import de.codecentric.java8examples.Person; import java.util.Collections; diff --git a/src/test/java/de/codecentric/java8examples/TestData.java b/src/test/java/de/codecentric/java8examples/TestData.java index 26ffe1b..e694e76 100644 --- a/src/test/java/de/codecentric/java8examples/TestData.java +++ b/src/test/java/de/codecentric/java8examples/TestData.java @@ -24,14 +24,14 @@ public static List listOfPersons() { public static List listOfInvoices() { return Arrays.asList( - new Invoice("Moe", "Homer", Arrays.asList( - new InvoiceItem("Beer", 13, BigDecimal.valueOf(1.5)), - new InvoiceItem("Burger", 3, BigDecimal.valueOf(4.5)))), new Invoice("Crusty Burger", "Homer", Arrays.asList( new InvoiceItem("Burger", 5, BigDecimal.valueOf(5)), new InvoiceItem("Coke", 1, BigDecimal.valueOf(5)))), new Invoice("Crusty Burger", "Bart", Arrays.asList( new InvoiceItem("Coke", 1, BigDecimal.valueOf(5)))), + new Invoice("Moe", "Homer", Arrays.asList( + new InvoiceItem("Beer", 13, BigDecimal.valueOf(1.5)), + new InvoiceItem("Burger", 3, BigDecimal.valueOf(4.5)))), new Invoice("Kwik-E-Mart", "Homer", Arrays.asList( new InvoiceItem("Beer", 9, BigDecimal.valueOf(0.9)), new InvoiceItem("Chips", 2, BigDecimal.valueOf(0.5)))), diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java index 208eaa2..d87330a 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -5,7 +5,14 @@ import de.codecentric.java8examples.TestData; import org.junit.Test; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.IntSummaryStatistics; import java.util.List; +import java.util.Map; + +import static org.hamcrest.Matchers.*; +import static org.hamcrest.MatcherAssert.assertThat; /** * Tests for mapping and filtering feature of the streaming api. Once you have completed the stub-methods in @@ -15,45 +22,87 @@ public class CollectingAndReducingTest { private List persons = TestData.listOfPersons(); private List invoices = TestData.listOfInvoices(); + private List recipients = Arrays.asList("Homer", "Bart", "Marge"); @Test public void testAverageAge() throws Exception { - + assertThat( + CollectingAndReducing.averageAge(persons), + closeTo(30.57D, 0.01)); } @Test public void testMaxAge() throws Exception { - + assertThat( + CollectingAndReducing.maxAge(persons), + equalTo(46)); } @Test public void testAgeStatistics() throws Exception { - + IntSummaryStatistics statistic = CollectingAndReducing.ageStatistics(persons); + assertThat(statistic.getAverage(), equalTo(30.571428571428573)); + assertThat(statistic.getCount(), equalTo(7l)); + assertThat(statistic.getMax(), equalTo(46)); + assertThat(statistic.getMin(), equalTo(1)); + assertThat(statistic.getSum(), equalTo(214l)); } @Test public void testBuildCommaSeparatedListOfFirstNames() throws Exception { - + assertThat( + CollectingAndReducing.buildCommaSeparatedListOfFirstNames(persons), + equalTo("Jane, Mary, John, Michael, Chris, Pete, Maggie")); } @Test public void testCheapestProduct() throws Exception { - + assertThat( + CollectingAndReducing.cheapestProduct(invoices), + equalTo("Chips")); } @Test public void testMostExpensiveInvoice() throws Exception { + assertThat( + CollectingAndReducing.mostExpensiveInvoice(invoices), + equalTo(invoices.get(2))); } @Test - public void testGroupInvoicesByReceiver() throws Exception { - + public void testGroupInvoicesByRecipient() throws Exception { + Map> invoicesByRecipient = + CollectingAndReducing.groupInvoicesByRecipient(invoices); + assertThat(invoicesByRecipient.keySet(), hasSize(recipients.size())); + + for (String recipient: recipients) { + for (Invoice invoice: invoices) { + if (recipient.equals(invoice.getRecipient())) { + assertThat(invoicesByRecipient.get(recipient), + hasItem(invoice)); + } else { + assertThat(invoicesByRecipient.get(recipient), + not(hasItem(invoice))); + } + } + } } @Test - public void testExpensesByReceiver() throws Exception { - + public void testExpensesByRecipient() throws Exception { + Map expencesByRecipient = + CollectingAndReducing.expensesByRecipient(invoices); + assertThat(expencesByRecipient.keySet(), hasSize(invoices.size())); + for (String recipient: recipients) { + BigDecimal expenses = BigDecimal.ZERO; + for (Invoice invoice: invoices) { + if (recipient.equals(invoice.getRecipient())) { + expenses = expenses.add(invoice.getTotal()); + } + } + assertThat(expencesByRecipient.get(recipient), equalTo(expenses)); + } } @Test From a30316f5d4fd18f54b90a5a9baf33ce32957a857 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Fri, 29 Nov 2013 13:51:35 +0100 Subject: [PATCH 10/23] Tests for CollectingAndReducing. --- .../de/codecentric/java8examples/Invoice.java | 43 ++++++++++++ .../java8examples/InvoiceItem.java | 31 +++++++++ .../streaming/CollectingAndReducing.java | 61 ++++++++++++----- .../streaming/FilteringAndMapping.java | 1 + .../codecentric/java8examples/TestData.java | 6 +- .../streaming/CollectingAndReducingTest.java | 67 ++++++++++++++++--- 6 files changed, 180 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/codecentric/java8examples/Invoice.java b/src/main/java/de/codecentric/java8examples/Invoice.java index 65e0418..bc82460 100644 --- a/src/main/java/de/codecentric/java8examples/Invoice.java +++ b/src/main/java/de/codecentric/java8examples/Invoice.java @@ -1,6 +1,8 @@ package de.codecentric.java8examples; +import java.math.BigDecimal; import java.util.List; +import java.util.stream.Collectors; public class Invoice { @@ -20,9 +22,50 @@ public List getItems() { return items; } + public BigDecimal getTotal() { + return getItems().stream() + .map(invoice -> invoice + .getPricePerUnit() + .multiply(BigDecimal.valueOf(invoice.getQuantity()))) + .collect(Collectors.reducing( + BigDecimal.ZERO, + (sum, elem) -> sum.add(elem))); + } + public Invoice(String sender, String recipient, List items) { this.sender = sender; this.recipient = recipient; this.items = items; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Invoice invoice = (Invoice) o; + + if (items != null ? !items.equals(invoice.items) : invoice.items != null) return false; + if (recipient != null ? !recipient.equals(invoice.recipient) : invoice.recipient != null) return false; + if (sender != null ? !sender.equals(invoice.sender) : invoice.sender != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = sender != null ? sender.hashCode() : 0; + result = 31 * result + (recipient != null ? recipient.hashCode() : 0); + result = 31 * result + (items != null ? items.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Invoice{" + + "sender='" + sender + '\'' + + ", recipient='" + recipient + '\'' + + ", items=" + items + + '}'; + } } diff --git a/src/main/java/de/codecentric/java8examples/InvoiceItem.java b/src/main/java/de/codecentric/java8examples/InvoiceItem.java index 44ed6a4..3fb33bf 100644 --- a/src/main/java/de/codecentric/java8examples/InvoiceItem.java +++ b/src/main/java/de/codecentric/java8examples/InvoiceItem.java @@ -25,4 +25,35 @@ public InvoiceItem(String product, Integer quantity, BigDecimal pricePerUnit) { this.quantity = quantity; this.pricePerUnit = pricePerUnit; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InvoiceItem that = (InvoiceItem) o; + + if (pricePerUnit != null ? !pricePerUnit.equals(that.pricePerUnit) : that.pricePerUnit != null) return false; + if (product != null ? !product.equals(that.product) : that.product != null) return false; + if (quantity != null ? !quantity.equals(that.quantity) : that.quantity != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = product != null ? product.hashCode() : 0; + result = 31 * result + (quantity != null ? quantity.hashCode() : 0); + result = 31 * result + (pricePerUnit != null ? pricePerUnit.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "InvoiceItem{" + + "product='" + product + '\'' + + ", quantity=" + quantity + + ", pricePerUnit=" + pricePerUnit + + '}'; + } } diff --git a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java index ce04d53..9e74c6e 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java +++ b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java @@ -1,11 +1,12 @@ package de.codecentric.java8examples.streaming; import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.InvoiceItem; import de.codecentric.java8examples.Person; import java.math.BigDecimal; import java.util.*; -import java.util.stream.Stream; +import java.util.stream.Collectors; /** * Your task: Implement the following methods and make the tests passs. @@ -16,67 +17,93 @@ public class CollectingAndReducing { * Compute the average age of the given list of Persons. */ public static Double averageAge(List persons) { - return Double.valueOf(0); + return persons.stream() + .mapToInt(Person::getAge) + .average().getAsDouble(); + } /** * How old is the oldest person in the given list. */ public static Integer maxAge(List persons) { - return Integer.valueOf(0); + return persons.stream() + .mapToInt(Person::getAge) + .max().getAsInt(); } /** * Compute Age-Statistics (max, min, average, ...) for the given list of Persons. */ - public static DoubleSummaryStatistics ageStatistics(List persons) { - return null; + public static IntSummaryStatistics ageStatistics(List persons) { + return persons.stream() + .mapToInt(Person::getAge) + .summaryStatistics(); } /** * Build a comma-separated list of the firstnames of a list of Persons. - * + *

* Example-Result: "Maggie, Marge, Mary" */ public static String buildCommaSeparatedListOfFirstNames(List persons) { - return ""; + return persons.stream() + .map(Person::getFirstName) + .collect(Collectors.joining(", ")); } /** * Identify the cheapest product (by pricePerUnit) in all invoices. */ public static String cheapestProduct(List invoices) { - return ""; + return invoices.stream() + .flatMap(invoice -> invoice.getItems().stream()) + .min(Comparator.comparing(InvoiceItem::getPricePerUnit)) + .get().getProduct(); } /** * Identify the invoice with the highest total amount. */ public static Invoice mostExpensiveInvoice(List invoices) { - return null; + return invoices.stream() + .collect(Collectors.maxBy( + Comparator.comparing(Invoice::getTotal))).get(); } /** * Just what the method name says. */ - public static Map> groupInvoicesByReceiver(List invoices) { - return Collections.emptyMap(); + public static Map> groupInvoicesByRecipient(List invoices) { + return invoices.stream() + .collect(Collectors.groupingBy(Invoice::getRecipient)); } /** * Compute the total amount, that each receiver spent. - * + *

* Hint: Use the two-argument version of Collectors.groupingBy together with Collectors.mapping. */ - public static Map expensesByReceiver(List invoices) { - return Collections.emptyMap(); + public static Map expensesByRecipient(List invoices) { + return invoices.stream() + .collect(Collectors.groupingBy( + Invoice::getRecipient, + Collectors.mapping( + Invoice::getTotal, + Collectors.reducing( + BigDecimal.ZERO, + (sum, elem) -> sum.add(elem))))); } /** * How many items of each product have been purchased? */ - public static Map countByProduct(List invoices) { - return Collections.emptyMap(); + public static Map countByProduct(List invoices) { + return invoices.stream() + .flatMap(invoice -> invoice.getItems().stream()) + .collect(Collectors.groupingBy( + InvoiceItem::getProduct, + Collectors.summingInt(InvoiceItem::getQuantity))); } /** @@ -101,7 +128,7 @@ public static Map computeDealerInventory(List * {"Homer" -> ["Beer", "Burger"]} */ public static Map> favoriteArticlesByBuyer(List invoices) { - return Collections.EMPTY_MAP; + return Collections.emptyMap(); } public static class ProductWithPrice { diff --git a/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java index c751e9f..25c8574 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java +++ b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java @@ -1,6 +1,7 @@ package de.codecentric.java8examples.streaming; import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.InvoiceItem; import de.codecentric.java8examples.Person; import java.util.Collections; diff --git a/src/test/java/de/codecentric/java8examples/TestData.java b/src/test/java/de/codecentric/java8examples/TestData.java index 26ffe1b..e694e76 100644 --- a/src/test/java/de/codecentric/java8examples/TestData.java +++ b/src/test/java/de/codecentric/java8examples/TestData.java @@ -24,14 +24,14 @@ public static List listOfPersons() { public static List listOfInvoices() { return Arrays.asList( - new Invoice("Moe", "Homer", Arrays.asList( - new InvoiceItem("Beer", 13, BigDecimal.valueOf(1.5)), - new InvoiceItem("Burger", 3, BigDecimal.valueOf(4.5)))), new Invoice("Crusty Burger", "Homer", Arrays.asList( new InvoiceItem("Burger", 5, BigDecimal.valueOf(5)), new InvoiceItem("Coke", 1, BigDecimal.valueOf(5)))), new Invoice("Crusty Burger", "Bart", Arrays.asList( new InvoiceItem("Coke", 1, BigDecimal.valueOf(5)))), + new Invoice("Moe", "Homer", Arrays.asList( + new InvoiceItem("Beer", 13, BigDecimal.valueOf(1.5)), + new InvoiceItem("Burger", 3, BigDecimal.valueOf(4.5)))), new Invoice("Kwik-E-Mart", "Homer", Arrays.asList( new InvoiceItem("Beer", 9, BigDecimal.valueOf(0.9)), new InvoiceItem("Chips", 2, BigDecimal.valueOf(0.5)))), diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java index 208eaa2..d87330a 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -5,7 +5,14 @@ import de.codecentric.java8examples.TestData; import org.junit.Test; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.IntSummaryStatistics; import java.util.List; +import java.util.Map; + +import static org.hamcrest.Matchers.*; +import static org.hamcrest.MatcherAssert.assertThat; /** * Tests for mapping and filtering feature of the streaming api. Once you have completed the stub-methods in @@ -15,45 +22,87 @@ public class CollectingAndReducingTest { private List persons = TestData.listOfPersons(); private List invoices = TestData.listOfInvoices(); + private List recipients = Arrays.asList("Homer", "Bart", "Marge"); @Test public void testAverageAge() throws Exception { - + assertThat( + CollectingAndReducing.averageAge(persons), + closeTo(30.57D, 0.01)); } @Test public void testMaxAge() throws Exception { - + assertThat( + CollectingAndReducing.maxAge(persons), + equalTo(46)); } @Test public void testAgeStatistics() throws Exception { - + IntSummaryStatistics statistic = CollectingAndReducing.ageStatistics(persons); + assertThat(statistic.getAverage(), equalTo(30.571428571428573)); + assertThat(statistic.getCount(), equalTo(7l)); + assertThat(statistic.getMax(), equalTo(46)); + assertThat(statistic.getMin(), equalTo(1)); + assertThat(statistic.getSum(), equalTo(214l)); } @Test public void testBuildCommaSeparatedListOfFirstNames() throws Exception { - + assertThat( + CollectingAndReducing.buildCommaSeparatedListOfFirstNames(persons), + equalTo("Jane, Mary, John, Michael, Chris, Pete, Maggie")); } @Test public void testCheapestProduct() throws Exception { - + assertThat( + CollectingAndReducing.cheapestProduct(invoices), + equalTo("Chips")); } @Test public void testMostExpensiveInvoice() throws Exception { + assertThat( + CollectingAndReducing.mostExpensiveInvoice(invoices), + equalTo(invoices.get(2))); } @Test - public void testGroupInvoicesByReceiver() throws Exception { - + public void testGroupInvoicesByRecipient() throws Exception { + Map> invoicesByRecipient = + CollectingAndReducing.groupInvoicesByRecipient(invoices); + assertThat(invoicesByRecipient.keySet(), hasSize(recipients.size())); + + for (String recipient: recipients) { + for (Invoice invoice: invoices) { + if (recipient.equals(invoice.getRecipient())) { + assertThat(invoicesByRecipient.get(recipient), + hasItem(invoice)); + } else { + assertThat(invoicesByRecipient.get(recipient), + not(hasItem(invoice))); + } + } + } } @Test - public void testExpensesByReceiver() throws Exception { - + public void testExpensesByRecipient() throws Exception { + Map expencesByRecipient = + CollectingAndReducing.expensesByRecipient(invoices); + assertThat(expencesByRecipient.keySet(), hasSize(invoices.size())); + for (String recipient: recipients) { + BigDecimal expenses = BigDecimal.ZERO; + for (Invoice invoice: invoices) { + if (recipient.equals(invoice.getRecipient())) { + expenses = expenses.add(invoice.getTotal()); + } + } + assertThat(expencesByRecipient.get(recipient), equalTo(expenses)); + } } @Test From af7a65db028193e709a4930640d3383d0d83de91 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Fri, 29 Nov 2013 13:57:43 +0100 Subject: [PATCH 11/23] Remove solutions ;-) --- .../streaming/CollectingAndReducing.java | 44 ++++--------------- .../streaming/CollectingAndReducingTest.java | 2 + 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java index 9e74c6e..ae6be2b 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java +++ b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java @@ -17,28 +17,21 @@ public class CollectingAndReducing { * Compute the average age of the given list of Persons. */ public static Double averageAge(List persons) { - return persons.stream() - .mapToInt(Person::getAge) - .average().getAsDouble(); - + return 0d; } /** * How old is the oldest person in the given list. */ public static Integer maxAge(List persons) { - return persons.stream() - .mapToInt(Person::getAge) - .max().getAsInt(); + return 0; } /** * Compute Age-Statistics (max, min, average, ...) for the given list of Persons. */ public static IntSummaryStatistics ageStatistics(List persons) { - return persons.stream() - .mapToInt(Person::getAge) - .summaryStatistics(); + return null; } /** @@ -47,36 +40,28 @@ public static IntSummaryStatistics ageStatistics(List persons) { * Example-Result: "Maggie, Marge, Mary" */ public static String buildCommaSeparatedListOfFirstNames(List persons) { - return persons.stream() - .map(Person::getFirstName) - .collect(Collectors.joining(", ")); + return ""; } /** * Identify the cheapest product (by pricePerUnit) in all invoices. */ public static String cheapestProduct(List invoices) { - return invoices.stream() - .flatMap(invoice -> invoice.getItems().stream()) - .min(Comparator.comparing(InvoiceItem::getPricePerUnit)) - .get().getProduct(); + return ""; } /** * Identify the invoice with the highest total amount. */ public static Invoice mostExpensiveInvoice(List invoices) { - return invoices.stream() - .collect(Collectors.maxBy( - Comparator.comparing(Invoice::getTotal))).get(); + return null; } /** * Just what the method name says. */ public static Map> groupInvoicesByRecipient(List invoices) { - return invoices.stream() - .collect(Collectors.groupingBy(Invoice::getRecipient)); + return Collections.emptyMap(); } /** @@ -85,25 +70,14 @@ public static Map> groupInvoicesByRecipient(List * Hint: Use the two-argument version of Collectors.groupingBy together with Collectors.mapping. */ public static Map expensesByRecipient(List invoices) { - return invoices.stream() - .collect(Collectors.groupingBy( - Invoice::getRecipient, - Collectors.mapping( - Invoice::getTotal, - Collectors.reducing( - BigDecimal.ZERO, - (sum, elem) -> sum.add(elem))))); + return Collections.emptyMap(); } /** * How many items of each product have been purchased? */ public static Map countByProduct(List invoices) { - return invoices.stream() - .flatMap(invoice -> invoice.getItems().stream()) - .collect(Collectors.groupingBy( - InvoiceItem::getProduct, - Collectors.summingInt(InvoiceItem::getQuantity))); + return Collections.emptyMap(); } /** diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java index d87330a..719cb09 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; +import static junit.framework.Assert.assertNotNull; import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; @@ -41,6 +42,7 @@ public void testMaxAge() throws Exception { @Test public void testAgeStatistics() throws Exception { IntSummaryStatistics statistic = CollectingAndReducing.ageStatistics(persons); + assertNotNull(statistic); assertThat(statistic.getAverage(), equalTo(30.571428571428573)); assertThat(statistic.getCount(), equalTo(7l)); assertThat(statistic.getMax(), equalTo(46)); From 05b2802c2ed035798d10583ad52846a6619768c3 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Fri, 29 Nov 2013 14:10:07 +0100 Subject: [PATCH 12/23] Test for another task. --- .../streaming/CollectingAndReducingTest.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java index 719cb09..d77063d 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -1,15 +1,13 @@ package de.codecentric.java8examples.streaming; import de.codecentric.java8examples.Invoice; +import de.codecentric.java8examples.InvoiceItem; import de.codecentric.java8examples.Person; import de.codecentric.java8examples.TestData; import org.junit.Test; import java.math.BigDecimal; -import java.util.Arrays; -import java.util.IntSummaryStatistics; -import java.util.List; -import java.util.Map; +import java.util.*; import static junit.framework.Assert.assertNotNull; import static org.hamcrest.Matchers.*; @@ -109,7 +107,24 @@ public void testExpensesByRecipient() throws Exception { @Test public void testCountByProduct() throws Exception { + Map expected = new HashMap<>(); + for (Invoice invoice: invoices) { + for (InvoiceItem item: invoice.getItems()) { + String product = item.getProduct(); + if (expected.get(product) == null) { + expected.put(product, Integer.valueOf(0)); + } + expected.put( + product, + expected.get(product) + item.getQuantity()); + } + } + Map actual = CollectingAndReducing.countByProduct(invoices); + assertThat(actual.keySet(), hasSize(expected.size())); + for (Map.Entry entry: expected.entrySet()) { + assertThat(actual, hasEntry(entry.getKey(), entry.getValue())); + } } @Test From 6b2922dcdefb38e9933944ea8342f6823e78a2b5 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Fri, 29 Nov 2013 14:18:22 +0100 Subject: [PATCH 13/23] Fix one test. --- .../java8examples/streaming/CollectingAndReducingTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java index d77063d..10eb624 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -19,7 +19,6 @@ */ public class CollectingAndReducingTest { private List persons = TestData.listOfPersons(); - private List invoices = TestData.listOfInvoices(); private List recipients = Arrays.asList("Homer", "Bart", "Marge"); @@ -93,7 +92,7 @@ public void testGroupInvoicesByRecipient() throws Exception { public void testExpensesByRecipient() throws Exception { Map expencesByRecipient = CollectingAndReducing.expensesByRecipient(invoices); - assertThat(expencesByRecipient.keySet(), hasSize(invoices.size())); + assertThat(expencesByRecipient.keySet(), hasSize(recipients.size())); for (String recipient: recipients) { BigDecimal expenses = BigDecimal.ZERO; for (Invoice invoice: invoices) { From 6fb7af834175f27123c3d9c0e4e6395d5bc84c5b Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Fri, 29 Nov 2013 14:18:22 +0100 Subject: [PATCH 14/23] Fix one test. --- .../java8examples/streaming/CollectingAndReducingTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java index d77063d..10eb624 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -19,7 +19,6 @@ */ public class CollectingAndReducingTest { private List persons = TestData.listOfPersons(); - private List invoices = TestData.listOfInvoices(); private List recipients = Arrays.asList("Homer", "Bart", "Marge"); @@ -93,7 +92,7 @@ public void testGroupInvoicesByRecipient() throws Exception { public void testExpensesByRecipient() throws Exception { Map expencesByRecipient = CollectingAndReducing.expensesByRecipient(invoices); - assertThat(expencesByRecipient.keySet(), hasSize(invoices.size())); + assertThat(expencesByRecipient.keySet(), hasSize(recipients.size())); for (String recipient: recipients) { BigDecimal expenses = BigDecimal.ZERO; for (Invoice invoice: invoices) { From 0604f8626e830630a72d07e81610dce9f5d76ec9 Mon Sep 17 00:00:00 2001 From: Daniel Reuter Date: Fri, 29 Nov 2013 15:15:28 +0100 Subject: [PATCH 15/23] Fixed testdata --- .../java8examples/streaming/FilteringAndMappingTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java b/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java index ea28169..103723a 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/FilteringAndMappingTest.java @@ -54,6 +54,7 @@ public void extractFirstnamesWhereLastnameStartsWith() { @Test public void testExtractAllProducts() throws Exception { - MatcherAssert.assertThat(FilteringAndMapping.extractAllProducts(invoices), containsInAnyOrder("Beer", "Burrito", "Coke")); + MatcherAssert.assertThat(FilteringAndMapping.extractAllProducts(invoices), + containsInAnyOrder("Beer", "Burger", "Corn Flakes", "Chips", "Coke", "Cake", "Left-Handed Scissors")); } } From 21ba27e8452167caed2d9924d264eae2b3e60ac7 Mon Sep 17 00:00:00 2001 From: Daniel Reuter Date: Fri, 29 Nov 2013 15:27:59 +0100 Subject: [PATCH 16/23] Eclipse! --- .../java/de/codecentric/java8examples/Invoice.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/codecentric/java8examples/Invoice.java b/src/main/java/de/codecentric/java8examples/Invoice.java index bc82460..1f88105 100644 --- a/src/main/java/de/codecentric/java8examples/Invoice.java +++ b/src/main/java/de/codecentric/java8examples/Invoice.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.stream.Collectors; +import sun.reflect.generics.reflectiveObjects.NotImplementedException; + public class Invoice { private String sender; @@ -23,13 +25,7 @@ public List getItems() { } public BigDecimal getTotal() { - return getItems().stream() - .map(invoice -> invoice - .getPricePerUnit() - .multiply(BigDecimal.valueOf(invoice.getQuantity()))) - .collect(Collectors.reducing( - BigDecimal.ZERO, - (sum, elem) -> sum.add(elem))); + throw new NotImplementedException(); } public Invoice(String sender, String recipient, List items) { From 34cc0db8abec610c0e0749ba28da34bb66b4292d Mon Sep 17 00:00:00 2001 From: Daniel Reuter Date: Fri, 29 Nov 2013 15:29:38 +0100 Subject: [PATCH 17/23] Solutions --- .../streaming/FilteringAndMapping.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java index 25c8574..22be36b 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java +++ b/src/main/java/de/codecentric/java8examples/streaming/FilteringAndMapping.java @@ -1,13 +1,16 @@ package de.codecentric.java8examples.streaming; +import java.time.LocalDate; +import java.time.Period; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import de.codecentric.java8examples.Invoice; import de.codecentric.java8examples.InvoiceItem; import de.codecentric.java8examples.Person; -import java.util.Collections; -import java.util.List; -import java.util.Set; - /** * Your task: Implement the following methods and make the tests passs. */ @@ -17,44 +20,58 @@ public class FilteringAndMapping { * Extract a list of names (firstname and lastname separated by space) from a given list of Person objects. */ public static List extractNames(List persons) { - return Collections.emptyList(); + return persons.stream()// + . map(p -> p.getFirstName() + " " + p.getLastName())// + .collect(Collectors. toList()); } /** - * Extract a sorted (ascending by lastname) list of names (firstname and lastname separated by space) from a - * given list of Person objects. + * Extract a sorted (ascending by lastname) list of names (firstname and lastname separated by space) from a given list of Person objects. */ public static List extractNamesSortedByLastname(List persons) { - return Collections.emptyList(); + return persons.stream()// + .sorted((Person p1, Person p2) -> (p1.getLastName().compareTo(p2.getLastName())))// + . map(p -> p.getFirstName() + " " + p.getLastName())// + .collect(Collectors. toList()); } /** * From a given list of Person objects, extract a list of female firstnames */ public static List extractFemaleFirstnames(List persons) { - return Collections.emptyList(); + return persons.stream()// + .filter(p -> p.getGender().equals(Person.Gender.FEMALE))// + . map(p -> p.getFirstName())// + .collect(Collectors. toList()); } /** * Extract all females older than 18 years from a given list of Person objects. */ public static List extractAdultWomen(List persons) { - return Collections.emptyList(); + return persons.stream()// + .filter(p -> p.getGender().equals(Person.Gender.FEMALE))// + .filter((Person p) -> Period.between(p.getBirthDay(), LocalDate.now()).getYears() >= 18)// + .collect(Collectors. toList()); } /** - * From a given list of Person objects, extract a set of firstnames of the people whose lastname starts - * with the given string. + * From a given list of Person objects, extract a set of firstnames of the people whose lastname starts with the given string. */ public static Set extractFirstnamesWhereLastnameStartsWith(List persons, String startsWith) { - return Collections.emptySet(); + return persons.stream()// + .filter((Person p) -> p.getLastName().startsWith(startsWith))// + . map(p -> p.getFirstName())// + .collect(Collectors. toSet()); } /** * From a given list of invoices, extract a set of all product names. */ public static Set extractAllProducts(List invoices) { - return Collections.emptySet(); + return invoices.stream()// + . flatMap((Invoice i) -> i.getItems().stream())// + . map((InvoiceItem i) -> i.getProduct())// + .collect(Collectors. toSet()); } } - From c9b6e26af2cee45e5c08101476ecafb1d69326b4 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Wed, 4 Dec 2013 13:40:36 +0100 Subject: [PATCH 18/23] One more test --- .../streaming/CollectingAndReducing.java | 32 ++++++++++++++++++- .../streaming/CollectingAndReducingTest.java | 21 ++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java index ae6be2b..e6edb92 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java +++ b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java @@ -5,7 +5,9 @@ import de.codecentric.java8examples.Person; import java.math.BigDecimal; +import java.util.AbstractMap.SimpleEntry; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -91,7 +93,7 @@ public static Map cheapestDealersByProduct(List invoice /** * From a given list of invoices, compute for every dealer the available products together with its price. */ - public static Map computeDealerInventory(List invoices) { + public static Map> computeDealerInventory(List invoices) { return Collections.emptyMap(); } @@ -121,6 +123,34 @@ public String getProductName() { public BigDecimal getPrice() { return price; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ProductWithPrice that = (ProductWithPrice) o; + + if (price != null ? !price.equals(that.price) : that.price != null) return false; + if (productName != null ? !productName.equals(that.productName) : that.productName != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = productName != null ? productName.hashCode() : 0; + result = 31 * result + (price != null ? price.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ProductWithPrice{" + + "productName='" + productName + '\'' + + ", price=" + price + + '}'; + } } } diff --git a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java index 10eb624..6e93505 100644 --- a/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java +++ b/src/test/java/de/codecentric/java8examples/streaming/CollectingAndReducingTest.java @@ -133,7 +133,28 @@ public void testCheapestDealersByProduct() throws Exception { @Test public void testComputeDealerInventory() throws Exception { + HashMap> expected = new HashMap<>(); + for (Invoice invoice: invoices) { + String sender = invoice.getSender(); + if (expected.get(sender) == null) { + expected.put(sender, new ArrayList()); + } + List itemsOfSender = expected.get(sender); + for (InvoiceItem item: invoice.getItems()) { + CollectingAndReducing.ProductWithPrice newItem = new CollectingAndReducing.ProductWithPrice(item.getProduct(), item.getPricePerUnit()); + if (!itemsOfSender.contains(newItem)) { + itemsOfSender.add(newItem); + } + } + } + + Map> actual = + CollectingAndReducing.computeDealerInventory(invoices); + assertThat(actual.keySet(), hasSize(expected.size())); + for (String sender: expected.keySet()) { + assertThat("Unexpected item set for dealer " + sender, actual.get(sender), containsInAnyOrder(expected.get(sender).toArray())); + } } @Test From 3f8756aad5b30fbc45db023daf7a47b687f4c92f Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Wed, 4 Dec 2013 13:42:29 +0100 Subject: [PATCH 19/23] One more (crazy) solution. --- .../streaming/CollectingAndReducing.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java index 1d82e14..597e1dc 100644 --- a/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java +++ b/src/main/java/de/codecentric/java8examples/streaming/CollectingAndReducing.java @@ -120,7 +120,25 @@ public static Map cheapestDealersByProduct(List invoice * From a given list of invoices, compute for every dealer the available products together with its price. */ public static Map> computeDealerInventory(List invoices) { - return Collections.emptyMap(); + Function, String> classifier = + (SimpleEntry entry) -> (String) entry.getKey(); + Function, ProductWithPrice> mapper = + (SimpleEntry entry) -> (ProductWithPrice) entry.getValue(); + + Map> invoicesBySender = invoices.stream() + .collect(Collectors.groupingBy(Invoice::getSender)); + return invoicesBySender.entrySet().stream() + .>flatMap(entry -> entry.getValue().stream() + .flatMap((Invoice invoice) -> invoice.getItems().stream()) + .map((InvoiceItem item) -> new SimpleEntry( + entry.getKey(), + new ProductWithPrice(item.getProduct(), item.getPricePerUnit())))) + .distinct() + .collect(Collectors.groupingBy( + classifier, + Collectors.mapping( + mapper, + Collectors.toList()))); } /** From cd7869469c8bb3fedd399ce9c9d933b5dfc1a8b9 Mon Sep 17 00:00:00 2001 From: Michael Lex Date: Wed, 4 Dec 2013 13:44:43 +0100 Subject: [PATCH 20/23] Revivive accidentally deleted method Invoice.getTotal. --- src/main/java/de/codecentric/java8examples/Invoice.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/codecentric/java8examples/Invoice.java b/src/main/java/de/codecentric/java8examples/Invoice.java index 1f88105..b510a07 100644 --- a/src/main/java/de/codecentric/java8examples/Invoice.java +++ b/src/main/java/de/codecentric/java8examples/Invoice.java @@ -25,7 +25,13 @@ public List getItems() { } public BigDecimal getTotal() { - throw new NotImplementedException(); + return getItems().stream() + .map(invoice -> invoice + .getPricePerUnit() + .multiply(BigDecimal.valueOf(invoice.getQuantity()))) + .collect(Collectors.reducing( + BigDecimal.ZERO, + (sum, elem) -> sum.add(elem))); } public Invoice(String sender, String recipient, List items) { From 1030082b968d593b06ec634851f2d4c67fcb7913 Mon Sep 17 00:00:00 2001 From: Benedikt Ritter Date: Fri, 13 Dec 2013 13:16:09 +0100 Subject: [PATCH 21/23] JavaDoc for default method implementation --- .../java8examples/defaultmethods/GreetingService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/de/codecentric/java8examples/defaultmethods/GreetingService.java b/src/main/java/de/codecentric/java8examples/defaultmethods/GreetingService.java index 16e4c6d..473dbd8 100644 --- a/src/main/java/de/codecentric/java8examples/defaultmethods/GreetingService.java +++ b/src/main/java/de/codecentric/java8examples/defaultmethods/GreetingService.java @@ -5,6 +5,11 @@ */ public interface GreetingService { + /** + * Creates a greeting message. The provided default implementation simply returns "Hello world!" + * + * @return A greeting message. + */ default String greet() { return "Hello World!"; } From 206def815c1b9e54600678324e4d28bb65b622d3 Mon Sep 17 00:00:00 2001 From: Benedikt Ritter Date: Fri, 13 Dec 2013 13:17:46 +0100 Subject: [PATCH 22/23] Add an example showing how to work with unrealted default methods --- .../CombinedGreetingService.java | 20 +++++++++++++++++++ .../defaultmethods/GreetingServiceTest.java | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 src/main/java/de/codecentric/java8examples/defaultmethods/CombinedGreetingService.java diff --git a/src/main/java/de/codecentric/java8examples/defaultmethods/CombinedGreetingService.java b/src/main/java/de/codecentric/java8examples/defaultmethods/CombinedGreetingService.java new file mode 100644 index 0000000..f8db072 --- /dev/null +++ b/src/main/java/de/codecentric/java8examples/defaultmethods/CombinedGreetingService.java @@ -0,0 +1,20 @@ +package de.codecentric.java8examples.defaultmethods; + +/** + * A greeting service implementation that inherits {@link #greet()} from two unrelated interfaces. It has to provide + * an implementation for {@code greet()}. + */ +public class CombinedGreetingService implements GreetingService, AlternativeGreetingService { + + /** + * An implementation of the {@code greet()} method which is defined in both, {@link GreetingService} and + * {@link AlternativeGreetingService}. This implementation simply delegates to the default {@code greet()} + * implementation of the {@code GreetingService} interface + * + * @return the result of calling {@link GreetingService#greet()}. + */ + @Override + public String greet() { + return GreetingService.super.greet(); + } +} diff --git a/src/test/java/de/codecentric/java8examples/defaultmethods/GreetingServiceTest.java b/src/test/java/de/codecentric/java8examples/defaultmethods/GreetingServiceTest.java index 7e3d72e..81a5ee1 100644 --- a/src/test/java/de/codecentric/java8examples/defaultmethods/GreetingServiceTest.java +++ b/src/test/java/de/codecentric/java8examples/defaultmethods/GreetingServiceTest.java @@ -23,4 +23,10 @@ public void greetFromExtended() throws Exception { public void greetFromDerived() throws Exception { assertEquals("Salut le monde!", new DerivedGreetingService().greet()); } + + @Test + public void testName() throws Exception { + assertEquals("Hello World!", new CombinedGreetingService().greet()); + + } } From c6ed53948203dc52aa146928b8f4c06063f0ae78 Mon Sep 17 00:00:00 2001 From: Benedikt Ritter Date: Fri, 13 Dec 2013 13:20:34 +0100 Subject: [PATCH 23/23] Add example for using a method reference to implemente a function --- .../de/codecentric/java8examples/lambdas/LambdaExampleTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java b/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java index 3feb748..3d7dd1d 100644 --- a/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java +++ b/src/test/java/de/codecentric/java8examples/lambdas/LambdaExampleTest.java @@ -60,6 +60,8 @@ public void peterIsOlderThan30WithTypeInference() throws Exception { public void getAgeFromWrappedElementViaFunctionApplication() throws Exception { // type is inferred from context assertEquals("Parker", example.apply(p -> p.getLastName())); + // different notation using a method reference + assertEquals("Parker", example.apply(Person::getLastName)); } @Test