Java8新特性(1).Lambda表达式介绍、函数式接口和接口默认方法和静态方法

一、Lambda表达式

1.什么是lambda表达式

lambda表达式是一种匿名函数表达式

2.lambda表达式语法
  • 无参 : ()-> expression
  • 有参 :(parameters)-> {statement;}
  1. /**
  2. * 定义一个标签tag类
  3. */
  4. class Tag {
  5. private int tagId;
  6. private String tagName;
  7. private int weight;
  8. public Tag(int tagId, String tagName, int weight) {
  9. this.tagId = tagId;
  10. this.tagName = tagName;
  11. this.weight = weight;
  12. }
  13. public int getTagId() {
  14. return tagId;
  15. }
  16. public void setTagId(int tagId) {
  17. this.tagId = tagId;
  18. }
  19. public String getTagName() {
  20. return tagName;
  21. }
  22. public void setTagName(String tagName) {
  23. this.tagName = tagName;
  24. }
  25. public int getWeight() {
  26. return weight;
  27. }
  28. public void setWeight(int weight) {
  29. this.weight = weight;
  30. }
  31. @Override
  32. public String toString() {
  33. return "Tag{" +
  34. "tagId=" + tagId +
  35. ", tagName='" + tagName + '\'' +
  36. ", weight=" + weight +
  37. '}';
  38. }
  39. }
  40. public class LambdaDemo {
  41. public static void main(String[] args) {
  42. List<Tag> tagList = new ArrayList<Tag>(10);
  43. tagList.add(new Tag(1001, "JAVA", 15));
  44. tagList.add(new Tag(1002, "Golang", 10));
  45. tagList.add(new Tag(1003, "Lua", 17));
  46. tagList.add(new Tag(1004, "PHP", 11));
  47. tagList.add(new Tag(1005, "Node.js", 13));
  48. /**
  49. * 1.通过匿名函数来排序
  50. */
  51. Collections.sort(tagList, new Comparator<Tag>() {
  52. @Override
  53. public int compare(Tag o1, Tag o2) {
  54. if (o1.getWeight() > o2.getWeight()) {
  55. return -1;
  56. } else if (o1.getWeight() == o2.getWeight()) {
  57. return 0;
  58. } else {
  59. return 1;
  60. }
  61. }
  62. });
  63. System.out.println(tagList); //[Tag{tagId=1003, tagName='Lua', weight=17}, Tag{tagId=1001, tagName='JAVA', weight=15}, Tag{tagId=1005, tagName='Node.js', weight=13}, Tag{tagId=1004, tagName='PHP', weight=11}, Tag{tagId=1002, tagName='Golang', weight=10}]
  64. /**
  65. * 2.通过lambda表达式来实现排序
  66. */
  67. Collections.sort(tagList, (t1, t2)-> t2.getWeight() - t1.getWeight());
  68. System.out.println(tagList);
  69. }
  70. }

二、函数式接口

1.什么是函数式接口

函数接口是一种特殊的接口,它有且仅有一个接象方法(因为java8及以后,接口可以有默认方法,因此它可以有其他的默认方法)

  1. @FunctionalInterface
  2. interface Sortable<T> {
  3. public T sort(T obj);
  4. }

如:上例中这个Sortable接口中只有一个sort抽象方法

2.函数式接口声明

通过注解 @FunctionInterface 来声明

  1. @FunctionalInterface
  2. interface Testable<T> {
  3. public boolean test(T obj);
  4. }
3.常用的函数式接口
(1) Predicate 接口
  • 主要作用:测试输入对象是否符合某个条件
  • 主要方法:
    • 抽象方法: test
    • 默认方法
      • negate : 不符合指定条件时为true
      • and : 多个条件都满足
      • or : 多个条件有一个满足
  1. /**
  2. * 1.使用传统的匿名函数
  3. */
  4. Predicate<String> isNumber = new Predicate<String>() {
  5. @Override
  6. public boolean test(String s) {
  7. if (s == null || s.length() < 1) {
  8. return false;
  9. }
  10. return s.matches("\\d+");
  11. }
  12. };
  13. /**
  14. * 2.使用lambda表达式(是否为中包含数字的字符串)
  15. */
  16. Predicate<String> isNumberString = x -> x.matches("\\d+");
  17. /**
  18. * 字符串是否为5位
  19. */
  20. Predicate<String> isFifth = x -> x.length() == 5;
  21. /**
  22. * 是否只包括英文字母
  23. */
  24. Predicate<String> isLetter = x -> x.matches("[A-Za-z]+");
  25. /**
  26. * 1.直接调用Predicate接口的test方法
  27. */
  28. System.out.println(isNumber.test("123456"));
  29. System.out.println(isNumberString.test("456"));
  30. /**
  31. * 2.使用and方法
  32. */
  33. System.out.println(isNumber.and(isFifth).test("12345")); //true (是5位的数字字符串)
  34. /**
  35. * 3.使用or方法
  36. */
  37. System.out.println(isNumber.or(isLetter).test("Abcd")); //true (数字或者英文字母)
  38. System.out.println(isNumber.or(isLetter).test("Abcd14")); //false
  39. /**
  40. * 4.使用negate方法
  41. */
  42. System.out.println(isNumber.negate().test("123456")); //false (不是数字)
  43. System.out.println(isNumber.negate().test("ABc")); //true
(2)Supplier接口
  • 主要作用:创建对象,类似于对象工厂
  • 主要方法:get
  1. Supplier<String> strSupplier = ()->"hello supplier";
  2. System.out.println(strSupplier.get()); //hello supplier
  3. Supplier<Record> recordSupplier = () -> new Record();
  4. System.out.println(recordSupplier.get());
(3)Consumer接口
  • 主要作用:接收一个参数,对参数进行处理,但不返回(类似于一个消费的接口,只不过不需要反馈消费结果)
  • 主要方法:
    • accept : 接收参数,并进行处理
    • andThen : 接收另外一个Consumer接口,先处理当前接口的accept方法,再处理接收的Consumer接口
  1. Consumer<String> stringConsumer = s -> System.out.println("accepted:"+s);
  2. stringConsumer.accept("开奖了"); //accepted:开奖了
  3. Consumer<String> afterConsumer = s -> System.out.println("after:"+s);
  4. stringConsumer.andThen(afterConsumer).accept("中奖了");
  5. /**
  6. * accepted:中奖了
  7. * after:中奖了
  8. */
(4)Function接口
  • 主要作用:定义函数对象,生成一个Function对象
  • 主要方法:
    • apply : 将Function对象应用到输入的参数上,然后返回计算结果
    • andThen : 两个函数对象进行组合操作
  1. /**
  2. * 游戏记录
  3. */
  4. class ActivityRecord {
  5. /**
  6. * 记录ID
  7. */
  8. private Long recordId;
  9. /**
  10. * 用户ID
  11. */
  12. private Long userId;
  13. /**
  14. * 结果
  15. */
  16. private Integer result;
  17. /**
  18. * 时长
  19. */
  20. private Integer period;
  21. /**
  22. * 得分
  23. */
  24. private Integer score;
  25. /**
  26. * 创建时间
  27. */
  28. private Long createTime;
  29. public ActivityRecord(Long recordId, Long userId, Integer result, Integer period, Integer score, Long createTime) {
  30. this.recordId = recordId;
  31. this.userId = userId;
  32. this.result = result;
  33. this.period = period;
  34. this.score = score;
  35. this.createTime = createTime;
  36. }
  37. public Long getRecordId() {
  38. return recordId;
  39. }
  40. public void setRecordId(Long recordId) {
  41. this.recordId = recordId;
  42. }
  43. public Long getUserId() {
  44. return userId;
  45. }
  46. public void setUserId(Long userId) {
  47. this.userId = userId;
  48. }
  49. public Integer getResult() {
  50. return result;
  51. }
  52. public void setResult(Integer result) {
  53. this.result = result;
  54. }
  55. public Integer getPeriod() {
  56. return period;
  57. }
  58. public void setPeriod(Integer period) {
  59. this.period = period;
  60. }
  61. public Integer getScore() {
  62. return score;
  63. }
  64. public void setScore(Integer score) {
  65. this.score = score;
  66. }
  67. public Long getCreateTime() {
  68. return createTime;
  69. }
  70. public void setCreateTime(Long createTime) {
  71. this.createTime = createTime;
  72. }
  73. @Override
  74. public String toString() {
  75. return "ActivityRecord{" +
  76. "recordId=" + recordId +
  77. ", userId=" + userId +
  78. ", result=" + result +
  79. ", period=" + period +
  80. ", score=" + score +
  81. ", createTime=" + createTime +
  82. '}';
  83. }
  84. }
  85. /**
  86. * 按创建时间由小到大排序
  87. */
  88. class SortByCreateTime implements Function<List<ActivityRecord>, List<ActivityRecord>> {
  89. @Override
  90. public List<ActivityRecord> apply(List<ActivityRecord> activityRecordList) {
  91. return activityRecordList.stream().sorted(Comparator.comparing(ActivityRecord::getCreateTime)).collect(Collectors.toList());
  92. }
  93. }
  94. /**
  95. * 按分数倒序排列
  96. */
  97. class SortByScore implements Function<List<ActivityRecord>, List<ActivityRecord>> {
  98. @Override
  99. public List<ActivityRecord> apply(List<ActivityRecord> activityRecordList) {
  100. return activityRecordList.stream().sorted(Comparator.comparing(ActivityRecord::getScore).reversed()).collect(Collectors.toList());
  101. }
  102. }
  103. public class FunctionDemo {
  104. public static void main(String[] args) {
  105. List<ActivityRecord> recordList = new ArrayList<ActivityRecord>(5);
  106. int now = LocalDateTime.now().getNano();
  107. recordList.add(new ActivityRecord(1001L, 3500452001L, 1, 30, 1558, Long.valueOf(now)));
  108. recordList.add(new ActivityRecord(1002L, 3500462001L, 0, 130, 3600, Long.valueOf(now - 1000)));
  109. recordList.add(new ActivityRecord(1003L, 3501452001L, 0, 350, 12, Long.valueOf(now + 2000)));
  110. recordList.add(new ActivityRecord(1004L, 3300452001L, 1, 10, 300, Long.valueOf(now - 5000)));
  111. SortByCreateTime sortByCreateTime = new SortByCreateTime();
  112. SortByScore sortByScore = new SortByScore();
  113. System.out.println(sortByCreateTime.apply(recordList));
  114. System.out.println(sortByScore.apply(recordList));
  115. System.out.println(sortByCreateTime.andThen(sortByScore).apply(recordList));
  116. }
  117. }
(5)Comparator接口
  • 主要作用:用于比较和排序等(后面和stream一起使用再详细说明)

三、接口默认方法

注:java8之前,接口只能包括抽象方法,不能包含实例方法或静态方法,如下

  1. interface TagService {
  2. /**
  3. * 查询标签列表
  4. * @return
  5. */
  6. public List queryList();
  7. /**
  8. * 获取某个标签
  9. * @param tagId
  10. * @return
  11. */
  12. public Tag get(int tagId);
  13. /**
  14. * 添加标签
  15. * @param tag
  16. * @return
  17. */
  18. public int add(Tag tag);
  19. /**
  20. * 修改标签
  21. * @param tag
  22. * @return
  23. */
  24. public int update(Tag tag);
  25. /**
  26. * 删除标签
  27. * @param tagId
  28. * @return
  29. */
  30. public int delete(int tagId);
  31. }

java8以后,接口不仅有抽象方法,也可以有默认方法(实例方法)和静态方法

1.接口默认方法
  • 使用关键词default来修饰,在方法返回类型之前
  1. public default returnType methodName() {
  2. }
  1. interface TagVService {
  2. public default void print() {
  3. System.out.println("hello default method");
  4. }
  5. }

作用:有一些默认实现的方法,不需要所有的实现都由实现类来完成

在java标准类库中有很多接口有默认方法,如比较器接口Comparator

  • thenComparing : 多个比较条件
  • reversed : 倒序
2.接口静态方法

接口可以像普通类一样有静态方法

  1. interface TagVService {
  2. public static String getDefault() {
  3. return "default";
  4. }
  5. }

在java标准类库中有很多接口有静态方法,如比较器接口Comparator

  • Comparator.comparing() : 比较
  • Comparator.comparingInt() : 比较整数
  • Comparator.comparingLong() : 比较长整数
  • Comparator.comparingDouble : 比较双精度浮点数
  • Comparator.naturalOrder() : 正序排列
  • Comparator.reverseOrder() : 倒序排列