java8简记

使用java8有一段时间了, 简单记录一下

Lambda

Lambda类似于匿名内部类,一个简单的小栗子:

new Thread(() -> {
            System.out.println("hello, Lambda");
        }).start();

可以看到使用Lambda更简洁

lambda表达式和内部类有点类似,可以访问类属性,final方法局部变量.
注意 :更改lambda表达式中的变量不是线程安全的.
对于只包含一个抽象方法的接口, 可以通过lambda表达式创建该接口对象.这种接口称为函数式接口.
(接口可以重新声明Object类的方法,如ToString, clone, equals, 这些不是抽象方法, java8的default方法也不是) :

Comparator<Integer> c = (final Integer t1, final Integer t2) -> {return Integer.compare(t1, t2);};

上面栗子中, final是为了演示添加的,可以省略, 参数类型Integer java可以推导出来.
方法体中, 因为只要一句代码,所以return和{}可以省略

Comparator<Integer> c = (t1, t2) ->  Integer.compare(t1, t2);

甚至是

Comparator<Integer> c = Integer::compare;

上面使用了方法引用, 使用::操作符引用一个方法,有三种方式

  • 类::静态方法, 调用参数作为静态方法的参数 Integer::parseInt 等价于 s -> Integer.parseInt(s) , 对象对象s作为parseInt参数
  • 类::实例方法, 第一个参数就是执行方法的对象 Object::toString 等价于 o -> o.toString(), 直接调用调用对象o的toString方法
  • 构造方法

java8提供了许多常用的函数式接口


这些函数式接口可以作为类属性,方法参数,甚至返回值
如, 提供一个解析xml的接口, 由用户判断一个节点是否要处理, 如果要处理, 就交由用户进行处理. 可以使用如下方法定义:

public void handle(Predicate<Node> p, Consumer<Node> c)

而不用只定义NodeCheck, NodeHanler等接口

Optional

使用Optional可以有效的减小null的判断,特别是map的取值,如从一个Map<String, Object> map获取"amount"的值并转化为int(假定map或map.get("amount")都可能为null),
以往的写法:

    Integer i = null;
    Object o = map.get("amount");
    if(o != null) {
        String s = o.toString();
        if(s != null) {
            i = Integer.parseInt(s);
        }
    }

而使用Optional则非常简洁

Integer i = optional.map(k -> k.get("amount")).map(o -> o.toString()).map(s -> Integer.parseInt(s)).orElse(null);

参考: 使用 Java8 Optional 的正确姿势

个人觉得:虽然Optional使用方便,但始终觉得方法定义Optional<User> getUser(String code)
没有User getUser(String code)直观

stream

对于stream, 先来看个小栗子, 对一个List<Integer> list, 过滤掉其中的奇数:

list  = list.stream().filter(i -> i % 2 == 0).collect(Collectors.toList());

上面栗子中,可以分为3步:

  1. list.stream()创建一个stream
  2. filter(Predicate<? super T> predicate)进行过滤操作, 仅保留predicate返回true的元素
  3. collect(Collector<? super T, A, R> collector)进行结果收集

除了filter, java8还提供了常用的元素处理方案:

  • map 对stream中元素的类型转换
  • limit 取前n个元素
  • skip 丢弃前n个元素
  • distinct 丢弃重复的方法
  • sort 排序

收集结果

  • toArray 到数组
  • collect(Collectors.toList()) 到List
  • collect(Collectors.toMap) 到Map

还有其他的聚合方案

  • count
  • max
  • min
  • findFirst
  • findAny
  • allMatch
  • noneMatch

还可以使用stream分组
对于上个栗子中的list, 现在按奇偶数分成两组:

Map<Boolean, List<Integer>> oddMap = list.stream().collect(Collectors.partitioningBy(i -> i % 2 == 0));

根据属性分组

Map<String, List<User>> cityGroup = list.stream().collect(Collectors.groupingBy(User::getCity));

这是个很有用的特性, 因为我们常常要进行分组操作, 如对于一组user, 可以按地区, 用户等级等属性进行分组.

注意
可以很方便将list转成map

Map<String, User> users = userList.stream().collect(Collectors.toMap(User::getCode, c -> c)); 

但如果userList中用两个User.getCode()返回结果相同, 则会抛出异常java.lang.IllegalStateException: Duplicate key 1
可以使用userList.stream().collect(Collectors.toMap(User::getCode, c -> c, (a, b) -> a))解决这个问题,它表示,当两个User.getCode()结果相同时,取第一个User。

时间api

java8还有个比较大的改动,就是时间API。
java8加入了LocalDate和LocalTime, 它们使用的是ISO8601标准时间格式,和时区无关,和unix时间戳类似.
unix时间戳表示从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数。 也是说, 一个unix时间戳n, 对于每个地区, 它都表示该地区从1970年1月1日(UTC/GMT的午夜)开始经过n秒后的时间。
如1507564800表示2017/10/10 00:00:00, 如果在北京, 则表示北京时间2017/10/10 00:00:00, 如果在伦敦, 则表示伦敦时间2017/10/10 00:00:00(北京时间和伦敦时间时差八小时, 此时北京时间是2017/10/10 08:00:00)
LocalDate和LocalTime同理。

// 当前时间
LocalDate now = LocalDate.now();
// 当前时间加一天, 并按常用格式yyyy-MM-dd格式化
now.plusDays(1).format(DateTimeFormatter.BASIC_ISO_DATE);
// 当前时间减一天, 并按指定格式格式化
now.minusMonths(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

// 字符串转时间
LocalDate date = LocalDate.parse("2019-01-26", DateTimeFormatter.ISO_DATE);
// 时间比较
now.isAfter(date);

LocalDate与Date转换

// 时区ZoneId LocalDate时区不相关, Date时区, 两者转化需使用ZoneId
ZoneId zoneId = ZoneId.systemDefault();

LocalDate localDate = LocalDate.now();
// localDate转ZonedDateTime
ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
// ZonedDateTime转Date
Date date = Date.from(zdt.toInstant());

Date nowDate = new Date();
// Instant:nanosecond表示的时间戳
Instant instant = nowDate.toInstant();
// instant转ZonedDateTime
ZonedDateTime nowZonedDate = instant.atZone(zoneId);
// ZonedDateTime转LocalDate
LocalDate nowLocalDate = nowZonedDate.toLocalDate();

java7的新特性

简单记录一下java7比较重要的新特性

Path

java7新增了Path类, 可以便捷的对目录进行操作
当前resources目录结构为

|-- resources
    |-- local.properties
    |-- xml
        |-- local.xml

看一个小栗子

@Test
public void testPath() throws URISyntaxException {
    // 获取local.properties文件
    URI localProUri = this.getClass().getClassLoader().getResource("local.properties").toURI();

    // 转换为Path对象, 指向 .../resources/test/local.properties
    Path localProPath = Paths.get(localProUri);

    // 解析localProPath兄弟目录, 指向 .../resources/test/xml
    Path xmlPath = localProPath.resolveSibling("xml");

    // 解析xmlPath目录目录, 指向 .../resources/test/xml/local.xml
    Path localXmlPath = xmlPath.resolve("local.xml");

    // 转换为绝对路径
    localXmlPath.toAbsolutePath();

    // 获取文件名
    localXmlPath.getFileName();
    
    // 获取根目录
    localXmlPath.getRoot();
    
    // 获取父目录
    localXmlPath.getParent();
}

Files

java7也新增了Files类, 可以对文件进行读取,写入, 复制,移动等操作


@Test
public void testFileRead() throws URISyntaxException, IOException {
    Path localProPath = Paths.get(this.getClass().getClassLoader().getResource("local.properties").toURI());
    // 读取文件中所以的字节
    byte[] localProBytes = Files.readAllBytes(localProPath);
}


@Test
public void testFileCopy() throws URISyntaxException, IOException {
    Path localProPath = Paths.get(this.getClass().getClassLoader().getResource("local.properties").toURI());
    // 复制文件, StandardCopyOption.REPLACE_EXISTING表示替换已存在的文件
    Path targetPath = Files.copy(localProPath, localProPath.getParent().resolve("dev.properties"), StandardCopyOption.REPLACE_EXISTING);
}

@Test
public void testAppend() throws URISyntaxException, IOException {
    Path localProPath = Paths.get(this.getClass().getClassLoader().getResource("local.properties").toURI());

    // 追加文件,StandardOpenOption.APPEND表示追加
    Files.write(localProPath, "group=local".getBytes(), StandardOpenOption.APPEND);
}

这个有点类似于org.apache.commons.io.FileUtils类了。

try-with-resources

AutoCloseable是java7添加的接口, 实现了该接口的资源类可以使用try-with-resources语法

try (InputStream inputStream = new FileInputStream("local.properties")) {
    ...
} catch (IOException e) {
    e.printStackTrace();
}

对比一下原来的写法

InputStream inputStream = null;
try {
     inputStream = new FileInputStream("local.properties");
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if(inputStream != null) {
        try {
            inputStream.close();
        } catch (IOException e) {
        }
    }
}

捕获多个异常

java7中可以在同一个catch分支中捕获多个异常类型。引用《写给大忙人看的JavaSE8》中的一个栗子:

try {
    ...
} catch(FileNotFoundException | UnknownHostException ex) {
    // 处理丢失文件和未知主机的异常
} catch() {
    // 处理所有的IO异常
}

Objects

java7新增了Objects类, 提供一些常用的Object操作, 如deepEquals,isNull,nonNull,requireNonNull等。

参考:
Java8学习笔记
《写给大忙人看的Java SE 8》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容

  • Java8 in action 没有共享的可变数据,将方法和函数即代码传递给其他方法的能力就是我们平常所说的函数式...
    铁牛很铁阅读 1,230评论 1 2
  • Java 8自Java 5(发行于2004)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发...
    谁在烽烟彼岸阅读 888评论 0 4
  • Java 8自Java 5(发行于2004)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发...
    huoyl0410阅读 629评论 1 2
  • 对于Java开发者来说,Java8的版本显然是一个具有里程碑意义的版本,蕴含了许多令人激动的新特性,如果能利用好这...
    jackcooper阅读 1,025评论 0 6
  • DOM 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。通过 HTM...
    MA木易YA阅读 228评论 0 0