diff --git a/pom.xml b/pom.xml index 10e5035e..dc64656c 100644 --- a/pom.xml +++ b/pom.xml @@ -37,8 +37,8 @@ maven-compiler-plugin 3.1 - 1.9 - 1.9 + 9 + 9 diff --git a/src/main/java/lambdasinaction/TestMain.java b/src/main/java/lambdasinaction/TestMain.java new file mode 100644 index 00000000..ed389b3f --- /dev/null +++ b/src/main/java/lambdasinaction/TestMain.java @@ -0,0 +1,45 @@ +package lambdasinaction; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +/** + * 功能说明:
+ * 系统版本: v1.0
+ * 开发人员: @author yejg
+ * 开发时间: 2018年11月08日
+ */ +public class TestMain { + + public static void main(String[] args) { + long fastest = Long.MAX_VALUE; + Map sourceMap = new HashMap(); + for (int i = 0; i < 5000; i++) { + sourceMap.put("" + i, "" + i); + } + long start = System.nanoTime(); + for (int i = 0; i < 10; i++) { + sourceMap.entrySet().parallelStream().forEach(e -> System.out.print(e.getKey() + " ")); + System.out.println(); + long duration = (System.nanoTime() - start) / 1_000_000; + if (duration < fastest) { + fastest = duration; + } + System.out.println("done in " + duration); + } + System.out.println("fast in " + fastest); + } +} + +// Map stringMap = Stream.generate(() -> { +// Map tmpMap = new HashMap(); +// tmpMap.put("1", "1"); +// return tmpMap; +// }).limit(20).flatMap(x -> x.entrySet().stream()).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue())); +// +// stringMap.entrySet().stream().forEach(x-> System.out.println(x.getKey())); \ No newline at end of file diff --git a/src/main/java/lambdasinaction/chap10/OperationsWithOptional.java b/src/main/java/lambdasinaction/chap10/OperationsWithOptional.java index d2940969..2bf75fcf 100644 --- a/src/main/java/lambdasinaction/chap10/OperationsWithOptional.java +++ b/src/main/java/lambdasinaction/chap10/OperationsWithOptional.java @@ -7,19 +7,16 @@ public class OperationsWithOptional { - public static void main(String... args) { - System.out.println(max(of(3), of(5))); - System.out.println(max(empty(), of(5))); + public static void main(String... args) { + System.out.println(max(of(3), of(5))); + System.out.println(max(empty(), of(5))); - Optional opt1 = of(5); - Optional opt2 = opt1.or(() -> of(4)); + Optional opt1 = of(5); +// Optional opt2 = opt1.or(() -> of(4)); +// System.out.println(of(5).or(() -> of(4))); + } - System.out.println( - of(5).or(() -> of(4)) - ); - } - - public static final Optional max(Optional i, Optional j) { - return i.flatMap(a -> j.map(b -> Math.max(a, b))); - } + public static final Optional max(Optional i, Optional j) { + return i.flatMap(a -> j.map(b -> Math.max(a, b))); + } } diff --git a/src/main/java/lambdasinaction/chap11/BestPriceFinder.java b/src/main/java/lambdasinaction/chap11/BestPriceFinder.java index 51412e93..93856ac1 100644 --- a/src/main/java/lambdasinaction/chap11/BestPriceFinder.java +++ b/src/main/java/lambdasinaction/chap11/BestPriceFinder.java @@ -55,6 +55,10 @@ public Stream> findPricesStream(String product) { return shops.stream() .map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor)) .map(future -> future.thenApply(Quote::parse)) + // thenCompose方法允许你对两个异步操作进行流水线,第一个操作完成时,将其结果作为参数传递给第二个操作 + // thenComposeAsync、thenApplyAsync + // 名称中不带Async的方法和它的前一个任务一样,在同一个线程中运行; + // 而名称以Async结尾的方法会将后续的任务提交到一个线程池,所以每个任务是由不同的线程处理的。 .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor))); } diff --git a/src/main/java/lambdasinaction/chap12/DateTimeExamples.java b/src/main/java/lambdasinaction/chap12/DateTimeExamples.java index 46895cc5..16544230 100644 --- a/src/main/java/lambdasinaction/chap12/DateTimeExamples.java +++ b/src/main/java/lambdasinaction/chap12/DateTimeExamples.java @@ -1,8 +1,5 @@ package lambdasinaction.chap12; -import static java.time.temporal.TemporalAdjusters.lastDayOfMonth; -import static java.time.temporal.TemporalAdjusters.nextOrSame; - import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.DayOfWeek; @@ -12,6 +9,9 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.chrono.JapaneseDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; @@ -22,20 +22,81 @@ import java.util.Calendar; import java.util.Date; import java.util.Locale; +import java.util.TimeZone; + +import static java.time.temporal.TemporalAdjusters.dayOfWeekInMonth; +import static java.time.temporal.TemporalAdjusters.lastDayOfMonth; +import static java.time.temporal.TemporalAdjusters.nextOrSame; public class DateTimeExamples { + private static final ThreadLocal formatters2 = new ThreadLocal(); + + static { + System.out.println("static code..."); + formatters2.set(new SimpleDateFormat("dd-MMM-yyyy")); + } + private static final ThreadLocal formatters = new ThreadLocal() { protected DateFormat initialValue() { + System.out.println("initialValue..."); return new SimpleDateFormat("dd-MMM-yyyy"); } }; public static void main(String[] args) { + System.out.println("main..."); + + usePeriod(); + useZoneId(); + useOldDate(); useLocalDate(); useTemporalAdjuster(); useDateFormatter(); + + Date dateNow = localDateTime2Date(LocalDateTime.now()); + LocalDateTime localDateTimeNow = date2LocalDateTime(dateNow); + System.out.println("done."); + } + + + public static Date localDateTime2Date(LocalDateTime localDateTime) { + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zdt = localDateTime.atZone(zoneId); + Date date = Date.from(zdt.toInstant()); + System.out.println(date.toString()); + return date; + } + + public static LocalDateTime date2LocalDateTime(Date date) { + ZoneId zoneId = ZoneId.systemDefault(); + Instant instant = date.toInstant(); + LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime(); + return localDateTime; + } + + private static void useZoneId() { + ZoneId zoneId = TimeZone.getDefault().toZoneId(); + ZoneId romeZone = ZoneId.of("Europe/Rome"); + LocalDate date = LocalDate.of(2014, Month.MARCH, 18); + ZonedDateTime zdt1 = date.atStartOfDay(romeZone); + LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45); + ZonedDateTime zdt2 = dateTime.atZone(romeZone); + Instant instant = Instant.now(); + ZonedDateTime zdt3 = instant.atZone(romeZone); + } + + private static void usePeriod() { + Period period = Period.of(2018, 11, 30); + + Period between = Period.between(LocalDate.of(2018, 11, 29), LocalDate.of(2018, 11, 30)); + System.out.println(between.getDays()); + + // 由于Duration类主要用于以秒和纳 秒衡量时间的长短,你不能向between方法传递LocalDate对象做参数 + // Duration duration = Duration.between(LocalDate.of(2018, 11, 19), LocalDate.of(2018, 11, 30));// error + Duration duration = Duration.between(LocalTime.of(13, 45, 20), LocalTime.of(13, 45, 19)); + duration.getSeconds(); } private static void useOldDate() { @@ -45,13 +106,13 @@ private static void useOldDate() { System.out.println(formatters.get().format(date)); Calendar calendar = Calendar.getInstance(); - calendar.set(2014, Calendar.FEBRUARY, 18); + calendar.set(2018, Calendar.FEBRUARY, 18); System.out.println(calendar); } private static void useLocalDate() { - LocalDate date = LocalDate.of(2014, 3, 18); - int year = date.getYear(); // 2014 + LocalDate date = LocalDate.of(2018, 3, 18); + int year = date.getYear(); // 2018 Month month = date.getMonth(); // MARCH int day = date.getDayOfMonth(); // 18 DayOfWeek dow = date.getDayOfWeek(); // TUESDAY @@ -69,7 +130,8 @@ private static void useLocalDate() { int second = time.getSecond(); // 20 System.out.println(time); - LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20); // 2014-03-18T13:45 + LocalDateTime localDateTime = LocalDateTime.parse("20181130140100", DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + LocalDateTime dt1 = LocalDateTime.of(2018, Month.MARCH, 18, 13, 45, 20); // 2018-03-18T13:45 LocalDateTime dt2 = LocalDateTime.of(date, time); LocalDateTime dt3 = date.atTime(13, 45, 20); LocalDateTime dt4 = date.atTime(time); @@ -97,7 +159,10 @@ private static void useLocalDate() { } private static void useTemporalAdjuster() { - LocalDate date = LocalDate.of(2014, 3, 18); + LocalDate date = LocalDate.of(2018, 11, 30); + TemporalAdjuster adjuster = dayOfWeekInMonth(1, DayOfWeek.MONDAY); + LocalDate with = date.with(adjuster); + date = date.with(nextOrSame(DayOfWeek.SUNDAY)); System.out.println(date); date = date.with(lastDayOfMonth()); @@ -122,6 +187,7 @@ private static void useTemporalAdjuster() { System.out.println(date); } + // 自定义TemporalAdjuster private static class NextWorkingDay implements TemporalAdjuster { @Override public Temporal adjustInto(Temporal temporal) { @@ -134,7 +200,7 @@ public Temporal adjustInto(Temporal temporal) { } private static void useDateFormatter() { - LocalDate date = LocalDate.of(2014, 3, 18); + LocalDate date = LocalDate.of(2018, 3, 18); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); DateTimeFormatter italianFormatter = DateTimeFormatter.ofPattern("d. MMMM yyyy", Locale.ITALIAN); diff --git a/src/main/java/lambdasinaction/chap2/FilteringApples.java b/src/main/java/lambdasinaction/chap2/FilteringApples.java index 0f61fd08..f328749b 100644 --- a/src/main/java/lambdasinaction/chap2/FilteringApples.java +++ b/src/main/java/lambdasinaction/chap2/FilteringApples.java @@ -1,12 +1,28 @@ package lambdasinaction.chap2; import java.util.*; +import java.util.stream.Collectors; public class FilteringApples{ public static void main(String ... args){ - List inventory = Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")); + List inventory = Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")); + + List collect = inventory.stream().filter(apple -> apple.getWeight() > 80).collect(Collectors.toList()); + collect.stream().forEach(System.out::println); + + System.out.println("----------------"); + inventory.stream().sorted((a1,a2) -> a1.getWeight().compareTo(a2.getWeight())).forEach(System.out::println); + System.out.println("----------------"); + inventory.stream().sorted(Comparator.comparing(Apple::getWeight).reversed()).forEach(System.out::println); + System.out.println("----------------"); + inventory.stream().forEach(System.out::println);// 顺序遍历打印 + System.out.println("----------------"); + inventory.parallelStream().forEach(System.out::println);// 并行遍历打印,顺序随机 + + System.out.println("----------------"); + // [Apple{color='green', weight=80}, Apple{color='green', weight=155}] List greenApples = filterApplesByColor(inventory, "green"); diff --git a/src/main/java/lambdasinaction/chap3/ExecuteAround.java b/src/main/java/lambdasinaction/chap3/ExecuteAround.java index 6c15fb6a..93932acc 100644 --- a/src/main/java/lambdasinaction/chap3/ExecuteAround.java +++ b/src/main/java/lambdasinaction/chap3/ExecuteAround.java @@ -4,6 +4,9 @@ public class ExecuteAround { public static void main(String ...args) throws IOException{ + String path = "src/main/resources/lambdasinaction/chap3/data.txt"; + File f = new File(path); + System.out.println(f.getAbsolutePath()); // method we want to refactor to make more flexible String result = processFileLimited(); @@ -17,6 +20,10 @@ public static void main(String ...args) throws IOException{ String twoLines = processFile((BufferedReader b) -> b.readLine() + b.readLine()); System.out.println(twoLines); + System.out.println("-----------------------------"); + BufferedReaderProcessor processor = (BufferedReader b) -> b.readLine(); + String s = processor.process(new BufferedReader(new FileReader("lambdasinaction/chap3/data.txt"))); + System.out.println(s); } public static String processFileLimited() throws IOException { @@ -34,6 +41,7 @@ public static String processFile(BufferedReaderProcessor p) throws IOException { } + @FunctionalInterface public interface BufferedReaderProcessor{ public String process(BufferedReader b) throws IOException; diff --git a/src/main/java/lambdasinaction/chap3/data1.txt b/src/main/java/lambdasinaction/chap3/data1.txt new file mode 100644 index 00000000..20764bbf --- /dev/null +++ b/src/main/java/lambdasinaction/chap3/data1.txt @@ -0,0 +1,5 @@ +Java +8 +Lambdas +In +Action \ No newline at end of file diff --git a/src/main/java/lambdasinaction/chap6/Grouping.java b/src/main/java/lambdasinaction/chap6/Grouping.java index 9105cc80..48d96b43 100644 --- a/src/main/java/lambdasinaction/chap6/Grouping.java +++ b/src/main/java/lambdasinaction/chap6/Grouping.java @@ -33,12 +33,13 @@ private static Map> groupDishNamesByType() { } private static Map> groupDishTagsByType() { - return menu.stream().collect(groupingBy(Dish::getType, flatMapping(dish -> dishTags.get( dish.getName() ).stream(), toSet()))); + // flatMapping since jdk 9 + return menu.stream().collect(groupingBy(Dish::getType, flatMapping((Dish dish) -> dishTags.get( dish.getName() ).stream(), toSet()))); } private static Map> groupCaloricDishesByType() { // return menu.stream().filter(dish -> dish.getCalories() > 500).collect(groupingBy(Dish::getType)); - return menu.stream().collect(groupingBy(Dish::getType, filtering(dish -> dish.getCalories() > 500, toList()))); + return menu.stream().collect(groupingBy(Dish::getType, filtering((Dish dish) -> dish.getCalories() > 500, toList()))); } private static Map> groupDishesByCaloricLevel() { diff --git a/src/main/java/lambdasinaction/chap6/PartitionPrimeNumbers.java b/src/main/java/lambdasinaction/chap6/PartitionPrimeNumbers.java index 69d7c4ca..39b6cdd7 100644 --- a/src/main/java/lambdasinaction/chap6/PartitionPrimeNumbers.java +++ b/src/main/java/lambdasinaction/chap6/PartitionPrimeNumbers.java @@ -9,98 +9,98 @@ public class PartitionPrimeNumbers { - public static void main(String ... args) { - System.out.println("Numbers partitioned in prime and non-prime: " + partitionPrimes(100)); - System.out.println("Numbers partitioned in prime and non-prime: " + partitionPrimesWithCustomCollector(100)); + public static void main(String ... args) { + System.out.println("Numbers partitioned in prime and non-prime: " + partitionPrimes(100)); + System.out.println("Numbers partitioned in prime and non-prime: " + partitionPrimesWithCustomCollector(100)); - } + } - public static Map> partitionPrimes(int n) { - return IntStream.rangeClosed(2, n).boxed() - .collect(partitioningBy(candidate -> isPrime(candidate))); - } + public static Map> partitionPrimes(int n) { + return IntStream.rangeClosed(2, n).boxed() + .collect(partitioningBy(candidate -> isPrime(candidate))); + } - public static boolean isPrime(int candidate) { - return IntStream.rangeClosed(2, candidate-1) - .limit((long) Math.floor(Math.sqrt((double) candidate)) - 1) - .noneMatch(i -> candidate % i == 0); - } + public static boolean isPrime(int candidate) { + return IntStream.rangeClosed(2, candidate-1) + .limit((long) Math.floor(Math.sqrt((double) candidate)) - 1) + .noneMatch(i -> candidate % i == 0); + } - public static Map> partitionPrimesWithCustomCollector(int n) { - return IntStream.rangeClosed(2, n).boxed().collect(new PrimeNumbersCollector()); - } + public static Map> partitionPrimesWithCustomCollector(int n) { + return IntStream.rangeClosed(2, n).boxed().collect(new PrimeNumbersCollector()); + } - public static boolean isPrime(List primes, Integer candidate) { - double candidateRoot = Math.sqrt((double) candidate); - //return takeWhile(primes, i -> i <= candidateRoot).stream().noneMatch(i -> candidate % i == 0); - return primes.stream().takeWhile(i -> i <= candidateRoot).noneMatch(i -> candidate % i == 0); - } + public static boolean isPrime(List primes, Integer candidate) { + double candidateRoot = Math.sqrt((double) candidate); + //return takeWhile(primes, i -> i <= candidateRoot).stream().noneMatch(i -> candidate % i == 0); + return primes.stream().takeWhile(i -> i <= candidateRoot).noneMatch(i -> candidate % i == 0); + } /* - public static List takeWhile(List list, Predicate p) { - int i = 0; - for (A item : list) { - if (!p.test(item)) { - return list.subList(0, i); - } - i++; - } - return list; - } + public static List takeWhile(List list, Predicate p) { + int i = 0; + for (A item : list) { + if (!p.test(item)) { + return list.subList(0, i); + } + i++; + } + return list; + } */ - public static class PrimeNumbersCollector - implements Collector>, Map>> { + public static class PrimeNumbersCollector + implements Collector>, Map>> { - @Override - public Supplier>> supplier() { - return () -> new HashMap>() {{ - put(true, new ArrayList()); - put(false, new ArrayList()); - }}; - } + @Override + public Supplier>> supplier() { + return () -> new HashMap>() {{ + put(true, new ArrayList()); + put(false, new ArrayList()); + }}; + } - @Override - public BiConsumer>, Integer> accumulator() { - return (Map> acc, Integer candidate) -> { - acc.get( isPrime( acc.get(true), - candidate) ) - .add(candidate); - }; - } + @Override + public BiConsumer>, Integer> accumulator() { + return (Map> acc, Integer candidate) -> { + acc.get( isPrime( acc.get(true), + candidate) ) + .add(candidate); + }; + } - @Override - public BinaryOperator>> combiner() { - return (Map> map1, Map> map2) -> { - map1.get(true).addAll(map2.get(true)); - map1.get(false).addAll(map2.get(false)); - return map1; - }; - } + @Override + public BinaryOperator>> combiner() { + return (Map> map1, Map> map2) -> { + map1.get(true).addAll(map2.get(true)); + map1.get(false).addAll(map2.get(false)); + return map1; + }; + } - @Override - public Function>, Map>> finisher() { - return i -> i; - } + @Override + public Function>, Map>> finisher() { + return i -> i; + } - @Override - public Set characteristics() { - return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH)); - } - } + @Override + public Set characteristics() { + return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH)); + } + } - public Map> partitionPrimesWithInlineCollector(int n) { - return Stream.iterate(2, i -> i + 1).limit(n) - .collect( - () -> new HashMap>() {{ - put(true, new ArrayList()); - put(false, new ArrayList()); - }}, - (acc, candidate) -> { - acc.get( isPrime(acc.get(true), candidate) ) - .add(candidate); - }, - (map1, map2) -> { - map1.get(true).addAll(map2.get(true)); - map1.get(false).addAll(map2.get(false)); - }); - } + public Map> partitionPrimesWithInlineCollector(int n) { + return Stream.iterate(2, i -> i + 1).limit(n) + .collect( + () -> new HashMap>() {{ + put(true, new ArrayList()); + put(false, new ArrayList()); + }}, + (acc, candidate) -> { + acc.get( isPrime(acc.get(true), candidate) ) + .add(candidate); + }, + (map1, map2) -> { + map1.get(true).addAll(map2.get(true)); + map1.get(false).addAll(map2.get(false)); + }); + } } diff --git a/src/main/java/lambdasinaction/chap6/ToListCollector.java b/src/main/java/lambdasinaction/chap6/ToListCollector.java index 0621d96a..f17251e5 100644 --- a/src/main/java/lambdasinaction/chap6/ToListCollector.java +++ b/src/main/java/lambdasinaction/chap6/ToListCollector.java @@ -3,35 +3,58 @@ import java.util.*; import java.util.function.*; import java.util.stream.Collector; + import static java.util.stream.Collector.Characteristics.*; public class ToListCollector implements Collector, List> { + /* + interface Collector +  T是流中要收集的项目的泛型。 +  A是累加器的类型,累加器是在收集过程中用于累积部分结果的对象。 +  R是收集操作得到的对象(通常但并不一定是集合)的类型。 + */ + + + // 建立新的结果容器:supplier方法 + @Override + public Supplier> supplier() { + // 下面两种写法都可以 + // return () -> new ArrayList(); + return ArrayList::new; + } + + // 将元素添加到结果容器:accumulator方法 + @Override + public BiConsumer, T> accumulator() { + // 下面两种写法都可以 + // return (list, item) -> list.add(item); + return List::add; + } + + // 对结果容器应用最终转换:finisher方法 + @Override + public Function, List> finisher() { + // 下面两种写法都可以 + // return i -> i; + return Function.identity(); + } + + // 合并两个结果容器:combiner方法 + @Override + public BinaryOperator> combiner() { + return (list1, list2) -> { + list1.addAll(list2); + return list1; + }; + } - @Override - public Supplier> supplier() { - return () -> new ArrayList(); - } - - @Override - public BiConsumer, T> accumulator() { - return (list, item) -> list.add(item); - } - - @Override - public Function, List> finisher() { - return i -> i; - } - - @Override - public BinaryOperator> combiner() { - return (list1, list2) -> { - list1.addAll(list2); - return list1; - }; - } - - @Override - public Set characteristics() { - return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT)); - } + // 返回一个不可变的Set + // 定义收集器的行为——————尤其是关于流是否可以并行归约,以及可以使用哪些优化的提示。 + // UNORDERED——归约结果不受流中项目的遍历和累积顺序的影响。 + // CONCURRENT——accumulator函数可以从多个线程同时调用,且该收集器可以并行归约流。如果收集器没有标为UNORDERED,此参数无效。 + // IDENTITY_FINISH——这表明完成器方法返回的函数是一个恒等函数,可以跳过。这种情况下,累加器对象将会直接用作归约过程的最终结果。这也意味着,将累加器A不加检查地转换为结果R是安全的。 + @Override + public Set characteristics() { + return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT)); + } }