Java8

作者: 巨子联盟 | 来源:发表于2018-03-15 09:02 被阅读0次
  • List类型抽象化

    public static <T> List<T> filter(List<T> list, Predicate<T> p){
        return list.stream().filter(p::test).collect(Collectors.toList());
    }

    public static <T> List<T> filter(List<T> list, Predicate<T> p){
        List<T> result = new ArrayList<>();
        for(T e: list){
            if(p.test(e)){
                result.add(e);
            }
        }
        return result;
    }

关键字: 谓词 行为参数化 匿名类 Lambda 策略模式

  • Lambda表达式

image.png

函数式接口就是只定义一个抽象方法的接口,如:Runnable,Callable,Comparator,ActionListener
@FunctionalInterface

  • Predicate,Consumer,Function
  • Predicate :boolean test(T t)

  • Consumer :void accept(T t)

  • Function : R apply(T t)
    环绕执行模式

  • 流的创建

        Stream<String> echos = Stream.generate(() -> "echos");
        //不停的打印echos
        echos.forEach(System.out::println); 
        Stream<Double> echos = Stream.generate(() -> Math.random());
        //不停的打印0到1的随机数
        echos.forEach(System.out::println);
       Stream<BigInteger> echos = Stream.iterate(BigInteger.ZERO,n -> n.add(BigInteger.ONE));
       //不停的打印0,1,2,3,4序列值
       echos.forEach(System.out::println);
  • 自动关闭流 try-with-resources写法

    @Test
    public void testTryWithResource() {
        Path path = Paths.get("E:\\apache-maven-3.5.3\\conf\\settings.xml");
        try (Stream<String> lines = Files.lines(path)) {
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

流只能遍历一次,集合可以循环遍历

  • Stream API

  • 筛选

filter

  • 查找文件中单词比较长的个数

    @Test
    public void testFindLongWords() throws IOException {

        String fileName = "D:\\1.txt";
        String content = new String(Files.readAllBytes(Paths.get(fileName)), StandardCharsets.UTF_8);
        List<String> contents = Arrays.asList(content.split("[\\P{L}]+"));
        for (int j = 0; j < 5; j++) {
            Instant startTime = Instant.now();
            int count = 0;
            for (String word : contents) {
                if (word.length() >= 12) count++;
            }
            System.out.println("count:" + count + " for:" + Duration.between(startTime, Instant.now()).toMillis());

            startTime = Instant.now();
            long c = contents.stream().filter(w -> w.length() >= 12).count();
            System.out.println("count:" + c + " stream:" + Duration.between(startTime, Instant.now()).toMillis());
            startTime = Instant.now();
            c = contents.parallelStream().filter(w -> w.length() >= 12).count();
            System.out.println("count:" + c + " parallelStream:" + Duration.between(startTime, Instant.now()).toMillis());

            System.out.println("============================");
        }
    }

distinct
count
max
min

  • 截断流

limit

  • 跳过

skip

  • 映射

flatmap(Arrays::stream) 将各个生成流扁平化为单个流
map(Arrays::stream) 每个数组生成一个单独的流

创建一个新版本而不是修改

  • 匹配 查找

allMatch anyMatch noneMatch findFirst findAny

        List<String> words = Arrays.asList("aaa", "bbb", "ccc","bcasd","ad","bc","bsd","cs");
        Optional<String> maxWords = words.stream().max(String::compareToIgnoreCase);
        maxWords.ifPresent(System.out::println);
        //找到第一个满足 条件的
        Optional<String> b = words.stream().filter(a -> a.startsWith("b")).findFirst();
        b.ifPresent(System.out::println);
        //findAny 在并行的时候 可以获得更好的性能
        Optional<String> b1 = words.stream().parallel().filter(a -> a.startsWith("b")).findAny();
        b1.ifPresent(System.out::println);
        boolean b2 = words.stream().anyMatch(a -> a.startsWith("b"));
        System.out.println(b2);

        
        List<String> newWords = new ArrayList<>();
        //不为空时干什么,用ifPresent代替if,map可以获取操作的返回值,但是也要注意为空的情况
        b1.ifPresent(bb -> Collections.addAll(newWords,bb));
        Optional<Boolean> aBoolean = b1.map(bb -> Collections.addAll(newWords, bb));
        aBoolean.ifPresent(System.out::println);
        System.out.println(newWords);
        //提供一个为空时的值
        String s = b1.orElse("");
        System.out.println(s);
        //提供一个计算为空的方法
        System.out.println(b1.orElseGet(() -> System.getProperty("user.dir")));

短路

  • 切片
  • 归约

reduce

    @Test
    public void testReduce() {
        Stream<Integer> values = Stream.of(1, 3, 4, 6, 234, 434, 5);
        values.reduce(Integer::sum).ifPresent(System.out::println);
        //java.lang.IllegalStateException: stream has already been operated upon or closed
        //values.reduce((x, y) -> x + y).ifPresent(System.out::println);

        //reduce(0,xxx),返回的时一个值,不是Optional
        Integer sum = Stream.of(1, 3, 4, 6, 234, 434, 5).reduce(0, Integer::sum);
        System.out.println(sum);
        
    }
//计算所有 单词的长度之和
 System.out.println(words.stream().mapToInt(String::length).sum()); 
等同于下面的表达式
        Integer reduce = words.stream().reduce(0, (total, word) -> total + word.length(), (total1, total2) -> total1 + total2);
        System.out.println(reduce);

reduce 操作应该是联合的,即 (x op y) op z = x op (y op z),比如减法就不是联合的,它和先后顺序是有关系的.比如 (6 -3) -2 ≠ 6 - (3 -2)

  • 转数组
        Long[] longs = Stream.of(1L, 3L, 4L, 6L).toArray(Long[]::new);
        for(int i = 0 ;i <longs.length ;i++) {
            System.out.println(longs[i]);
        }
  • 聚合操作
    @Test
    public void testReduceHashSet() {
        Stream<String> values = Stream.of("bb", "sss","aa",  "cksdl","aa");
//        HashSet<String> sets = values.collect(HashSet::new, HashSet::add, HashSet::addAll);

//        List<String> list = values.collect(Collectors.toList());
//        list.forEach(System.out::println);

//        Set<String> set = values.collect(Collectors.toSet());
//        set.forEach(System.out::println);

//        System.out.println(values.collect(Collectors.joining(",")));

//        TreeSet<String> treeSet = values.collect(Collectors.toCollection(TreeSet::new));
//        treeSet.forEach(System.out::println);

        //统计信息 LongSummaryStatistics{count=5, sum=14, min=2, average=2.800000, max=5}
//        LongSummaryStatistics summaryStatistics = values.collect(Collectors.summarizingLong(String::length));
//        System.out.println(summaryStatistics.toString());

//        values.forEachOrdered(System.out::println);

        //peek能继续用这个流,不是终止操作
        long count = values.peek(System.out::println).count();
        System.out.println(count);
    }
  • toMap

第1个参数,得出Key值的计算方法
第2个参数,得出Value 值的计算方法
第3个参数,如果合并也有的新值

    @Test
    public void testCollectMap() {
        Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());
        Map<String, String> languageNames = locales.collect(Collectors.toMap(Locale::getDisplayLanguage, l -> l.getDisplayLanguage(l), (existingValue, newValue) -> existingValue));
        languageNames.forEach((s, s2) -> {
            System.out.println(s + "-->" + s2);
        });
    }
  • toMap<String,HashSet>
    @Test
    public void testCollectMap1() {
        Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Set<String>> languageCountrys = locales.collect(Collectors.toMap(Locale::getDisplayCountry, l -> Collections.singleton(l.getDisplayLanguage()), (a, b) -> {
            Set<String> r = new HashSet<>(a);
            r.addAll(b);
            return r;
        }));
        languageCountrys.forEach((k, v) -> {
            System.out.println(k + "->" + v);
        });
    }
  • 分组和分片
    @Test
    public void testGroupingBy1() {
        Map<String, List<Locale>> localeCountries = Stream.of(Locale.getAvailableLocales()).collect(Collectors.groupingBy(Locale::getCountry));
        localeCountries.forEach((k, v) -> {
            System.out.println(k + "->" + v);
        });

        Map<Boolean, List<Locale>> cnCountries = Stream.of(Locale.getAvailableLocales()).collect(Collectors.partitioningBy(l -> l.getLanguage().equals("en")));
        cnCountries.forEach((k, v) -> {
            System.out.println(k + "->" + v);
        });
    }
        Map<String, Set<Locale>> localeCountriesSet = Stream.of(Locale.getAvailableLocales()).collect(Collectors.groupingBy(Locale::getCountry,Collectors.toSet()));
        localeCountries.forEach((k, v) -> {
            System.out.println(k + "->" + v);
        });
image.png
image.png
  • 数值流
  • 无限流

  • 什么时候用Lambda?Lambda的好处?

  1. 延迟调用,比如记录日志的logger.info ,参数传入一个Supplier<String>, 就会延迟调用.
  2. Lambda表达式的参数?
  3. 函数式接口
函数式接口 参数类型 返回类型 抽象方法名 描述 其他方法
Runnable run 执行一个没有参数 ,没有返回值的操作
Supplier<T> T get 提供一个T类型的值
Consumer<T> T accept 消费一个T类型的值 andThen
BiConsumer<T, U> T t, U u accept 消费两个参数的值 andThen
Function<T, R> T R apply 输入T转换成R identity,andThen,compose
BiFunction<T, U, R> T, U R apply 输入两个参数,返回一个值R andThen
UnaryOperator<T> T T apply 继承Function<T,T>,对类型T进行的一元操作 compose,andThen,identity
BinaryOperator<T> T,T T apply 继承BiFunction<T,T,T>,对类型T进行二元操作 maxBy,minBy,andThen
Predicate<T> T boolean test 一个计算Boolean值的函数 and,negate,or,isEqual
BiPredicate<T, U> T t, U u boolean test 一个计算Boolean值的函数,2个参数 and,negate,or
image.png
  1. 返回函数 UnaryOperator
  2. 组合 compose


    image.png
  3. 并行操作
  4. 处理异常


    image.png

  • Optional

  • lambda表达式内的闭包是不能被修改的.

    public static Optional<Double> inverse(Double x) {
        return x == 0 ? Optional.empty() :Optional.of(1/x) ;
//        return Optional.ofNullable(x);
    }

    public static Optional<Double> squareRoot(Double x) {
        return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
    }

    @Test
    public void testFlatMap() {
        Optional<Double> aDouble = inverse(4.0).flatMap(StringTest::squareRoot);
        aDouble.ifPresent(System.out::println);
        Optional<Double> aDouble1 = Optional.of(0.0).flatMap(StringTest::inverse).flatMap(StringTest::squareRoot);
        aDouble1.ifPresent(System.out::println);
    }

flatmap 将两个流展开.使得可以在Optional连着Optional运算下去

image.png
CompareDemo demo = null;
        CompareDemo demo1 = new CompareDemo("","");
        System.out.println(Objects.equals(demo,demo1));

Objects.toString() 会处理好Null值的情况,尽量用之,或者用String.valueOf()


  • 文件的操作

Path类
强大的Files工具类

image.png
        Path path = Paths.get("D:\\Reference");
        try (Stream<Path> entries = Files.list(path)){
            entries.forEach(System.out::println);
        }
        //walk 递归
        try (Stream<Path> entries = Files.walk(path)){
            entries.forEach(System.out::println);
        }
      // Files.find() 查找时用

  • 反射的一堆异常 可以用 ReflectiveOperationException代替了

  • 其他的改进

//用分隔符连接字符串
String.join(",", "a", "b", "c")
System.out.println(String.join("_",Arrays.asList("a", "b", "c")));
        System.out.println(Math.floorMod(-5,3)); // 1
        System.out.println(Math.floorMod(5,3)); //2
        System.out.println(-5 % 3);  //-2
  • Math,StrictMath 数学工具类

  • 注解

新增了两个特性

  1. 可以使用重复注解,但是要注意在处理注解时要处理两种注解,包括注解容器
@Repeatable(Authors.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {

    String name();

}
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {

    Author[] value();

}
  • 并发增强

  • LongAccumulator vs AtomicLong

LongAccumulator.accumulate(5) LongAdder.increment, 这两个的条件是:最终的结果必须与中间值的组合顺序 无关,LongAccumulator是在get时汇总,LongAdder方法是在sum时汇总

  • merge compute 更新 ConcurrentHashMap,search ,reduce , forEach
    public static AtomicLong largest = new AtomicLong();

    @Test
    public void testAtomicLong() {

        largest.set(Math.max(largest.get(),5)); //错误-竞争条件

        //如果另一个线程也在更新这个值,很有可能它已经捷足先登了
        // ,那么随后的compareAndSet会返回FALSE,这时程序要再次循环
        long oldValue;
        long newValue;
        do {
            oldValue = largest.get();
            newValue = Math.max(oldValue, 5);

        } while (!largest.compareAndSet(oldValue, newValue));

        //Java8方法,查看代码,是源码已经封装了上面的循环方法
        largest.updateAndGet(x -> Math.max(x, 5));
        largest.accumulateAndGet(5, Math::max);
    }
  • ConcurrentHashMap

    @Test
    public void testConcurrentHashMap() {
        //线程不安全,操作的顺序不是原子的,所以结果无法预测
        Map<String, Long> map = new ConcurrentHashMap<>();
        Long oldValue = map.get("word");
        Long newValue = oldValue == null ? 1 : oldValue + 1;
        map.put("word", newValue);

        //补救方法
        do {
            oldValue = map.get("word");
            newValue = oldValue == null ? 1 : oldValue + 1;
        } while (!map.replace("word", oldValue, newValue));

        //或者用ConcurrentHashMap<String,AtomicLong>
        Map<String, AtomicLong> map1 = new ConcurrentHashMap<>();
        map1.putIfAbsent("word", new AtomicLong());
        map1.get("word").incrementAndGet();

        //或者用ConcurrentHashMap<String,LongAdder>
        Map<String, LongAdder> map2 = new ConcurrentHashMap<>();
        map2.putIfAbsent("word",new LongAdder()).add(1);

    }
  • Set

        Set<String> words = ConcurrentHashMap.<String>newKeySet();
        words.add("Java");
        words.add("2");
        words.add("3");
        words.forEach(System.out::println);
  • Future

CompletableFuture 流水线

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> readPage(url));
        future.thenApply()

  • 日期的改进

  1. 所有的java.time的类都是不可变的,线程安全
  2. 一个瞬间 Instant 是时间线上的一个点
  3. 持续时间 Duration 是两个瞬间 Instant之间的时间
  4. Java里,每天都是86400 = 24 * 60 * 60秒,没有闰
  5. LocalDateTime没有时区信息
  6. Temporal Adjuster可以处理常用的日历运算
  7. ZonedDateTime 是指定时区的某个时间点
  8. 当处理带时区的时间时,请使用 时段 Period ,而不是 Duration,以便考虑夏令时的变化
  9. 使用 DateTimeFormatter 来格式化和解析时间
  • Instant
        Instant now = Instant.now();
        try {
            sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Instant end = Instant.now();
        Duration duration = Duration.between(now, end);
        System.out.println(duration.toMillis());//501
        //检查一个算法是否比另一个算法快十倍
        Duration time1 = Duration.between(Instant.now(), Instant.now().plusSeconds(21));
        Duration time2 = Duration.between(Instant.now(), Instant.now().plusSeconds(2));
        boolean isFaster = time2.multipliedBy(10).minus(time1).isNegative();
        System.out.println(isFaster);
  • LocalDate
        for(int i = 2000;i<2020;i++) {
            System.out.println(i + ": " + LocalDate.of(i,1,1).plusDays(255));
        }
        LocalDate birthday = LocalDate.of(2012,1,2);
        System.out.println(birthday.plusYears(1));
        System.out.println(birthday.plus(Period.ofYears(1)));
        System.out.println(birthday.plus(Duration.ofDays(365))); //报错 UnsupportedTemporalTypeException

        System.out.println(LocalDate.of(2016,1,31).plusMonths(1)); //2016-02-29
        System.out.println(LocalDate.of(2016,3,31).minusMonths(1)); //2016-02-29

//本周,从星期日开始算第一天
LocalDate localDate = LocalDate.of(2018, 3, 8).minusDays(LocalDate.of(2018, 3, 8).getDayOfWeek().getValue());
        System.out.println(localDate.getDayOfWeek() +" : " +localDate.toString());
        System.out.println(localDate.plusDays(6).getDayOfWeek()+" : " + localDate.plusDays(6).toString());

  • Date 转 LocalDateTime
        Date date = new Date();
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();

        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        System.out.println("Date = " + date);
        System.out.println("LocalDateTime = " + localDateTime);
  • LocalDateTime 转 Date
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.now();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);

        Date date = Date.from(zdt.toInstant());

        System.out.println("LocalDateTime = " + localDateTime);
        System.out.println("Date = " + date);
  • 每个月的第二个周二
    LocalDate firstTuesday = LocalDate.of(2018, 3, 1).with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY));
  • TemporalAdjusters用法
    public void testFirstDay() {
        LocalDate ld = LocalDate.now();
        System.out.println(String.join("firstDayOfMonth",ld.with(TemporalAdjusters.firstDayOfMonth()).toString()));
        System.out.println(String.join("firstDayOfMonth",ld.with(TemporalAdjusters.firstDayOfYear()).toString()));
        System.out.println(String.join("firstDayOfMonth",ld.with(TemporalAdjusters.firstDayOfNextMonth()).toString()));
        System.out.println(String.join("firstDayOfMonth",ld.with(TemporalAdjusters.firstDayOfNextYear()).toString()));
        System.out.println();
    }
  • 计算某一个月的最后一个工作日
    @Test
    public void testFirstWorkDay() {
        int year = 2018;
        int month = 3;
        LocalDate ld = LocalDate.of(year, month, 1);
        int daysOfMonth = ld.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        LocalDate lastWorkDay = null;
        for (int i = daysOfMonth; i > 0; i--) {
            DayOfWeek dayOfWeek = LocalDate.of(year, month, i).getDayOfWeek();
            if(dayOfWeek.getValue() >= 6){
                continue;
            }
            lastWorkDay = LocalDate.of(year, month, i);
            break;
        }
        System.out.println(lastWorkDay.toString());
    }
  • 某月的最后一个星期几
    @Test
    public void testLastInMonth() {
        //某月的最后一个星期几
        int year = 2018;
        int month = 3;
        DayOfWeek dayOfWeek = DayOfWeek.MONDAY;
        LocalDate ld = LocalDate.of(year, month, 1);
        System.out.println(ld.with(TemporalAdjusters.lastInMonth(dayOfWeek)).toString());
    }
  • 某一个指定日期的上一个(下一个)星期几
    @Test
    public void testNextOrSame() {
        int year = 2018;
        int month = 3;
        DayOfWeek dayOfWeek = DayOfWeek.SATURDAY;
        LocalDate ld = LocalDate.of(year, month, 31);
        System.out.println(ld.with(TemporalAdjusters.nextOrSame(dayOfWeek)).toString()); //2018-03-31本身就是星期六,所以就同一天了
        System.out.println(ld.with(TemporalAdjusters.next(dayOfWeek)).toString());//2018-04-07 本身是星期六就下个
        System.out.println(ld.with(TemporalAdjusters.previousOrSame(dayOfWeek)).toString());//2018-03-31
        System.out.println(ld.with(TemporalAdjusters.previous(dayOfWeek)).toString());//2018-03-24
        System.out.println(ld.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)).toString());
        System.out.println(ld.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)).toString());
    }
  • 计算下一个工作日
// TemporalAdjusters.ofDateAdjuster 转换类型
    @Test
    public void testNextWorkDay1() {
        TemporalAdjuster NEXT_WORKDAY = TemporalAdjusters.ofDateAdjuster(ld -> {
            LocalDate result = ld;
            do {
                result = result.plusDays(1);
            } while (result.getDayOfWeek().getValue() >= 6);
            return result;
        });
        LocalDate ld = LocalDate.now().with(NEXT_WORKDAY);
        System.out.println(ld.toString());
    }

    @Test
    public void testNextWorkDay() {
        TemporalAdjuster NEXT_WORKDAY = (ld) -> {
            LocalDate result = (LocalDate) ld;
            do {
                result = result.plusDays(1);
            } while (result.getDayOfWeek().getValue() >= 6);
            return result;
        };
        LocalDate ld = LocalDate.now().with(NEXT_WORKDAY);
        System.out.println(ld.toString());
    }
  • ZonedDateTime
    @Test
    public void testAvailableZone() {
        //获取所有可用的时区 (IANA)
        ZoneId.getAvailableZoneIds().stream().sorted().forEach(System.out::println);
        System.out.println(ZoneId.systemDefault()); //Asia/Shanghai
        ZonedDateTime zdt = ZonedDateTime.now();
        //获取与UTC(格林威治皇家天文台的时间)之间的时差
        System.out.println(zdt.getOffset().toString());
        //Europe/Berlin
        ZonedDateTime meeting = ZonedDateTime.of(LocalDate.of(2013, 10, 25), LocalTime.of(2, 30), ZoneId.of("Europe/Berlin"));
        ZonedDateTime nextMeeting = meeting.plusDays(7); 
        System.out.println(nextMeeting); //2013-11-01T02:30+01:00[Europe/Berlin]
        nextMeeting = meeting.plus(Duration.ofDays(7)); 
        System.out.println(nextMeeting); //2013-11-01T01:30+01:00[Europe/Berlin] 不会处理夏令时
        nextMeeting = meeting.plus(Period.ofDays(7)); 
        System.out.println(nextMeeting); //2013-11-01T02:30+01:00[Europe/Berlin]
    }
  • 格式化


    image.png
    image.png
  • 字符串转日期

    @Test
    public void testParse() {
        LocalDate ld = LocalDate.parse("2018-03-16");
        System.out.println(ld.toString());
        ZonedDateTime zdt = ZonedDateTime.parse("2018-03-16 03:31:00+0800",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxx"));
        System.out.println(zdt);
        zdt = ZonedDateTime.parse("2018-03-16 03:31:00+08:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxxx"));
        System.out.println(zdt);
    }
  • 与遗留的日期的转换


    image.png
image.png

相关文章

网友评论

      本文标题:Java8

      本文链接:https://www.haomeiwen.com/subject/jwsktftx.html