Java8新特性

1.Lamda表达式

Lambda表达式的作用主要是用来简化接口的创建,使用Lambda表达式接口必须是函数式接口

  • 语法格式一:无参,无返回值,Lambda体只需一条语句
  • 语法格式二:Lambda只需要一个参数时,参数的小括号可以省略
  • 语法格式三:当Lambda体只有一条语句时,return与大括号可以省略
  • 语法格式四:参数的数据类型可以省略
@Test
public void testLambda() {
    new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            log.info(" {} ", i);
        }
    }).start();
}

2.函数式接口

函数式接口只能有一个抽象方法,使用@FunctionalInterface注解可以检查是否是函数式接口

  • 自定义函数式接口
@FunctionalInterface
interface MyFunc<T> {
    T getValue(T t);
}
  • 四大内置核心函数式接口

Consumner<T> : 消费型接口

void accept(T t);

用途:对类型为T的对象应用操作,包含方法:void accept(T t);

@Test
public void testConsume() {
    pay(1000, money -> System.out.println("购物消费了" + money + "元"));
}

private void pay(int money, Consumer<Integer> consumer) {
    consumer.accept(money);
}

Supplier<T> :供给型接口

T get();

用途:返回类型为T的对象,包含方法:T get();

@Test
public void testSupplier() {
    List<Integer> list = getNumList(10, () -> (int)(Math.random() * 100));
    for (int num : list) {
        System.out.println("supplier" + num);
    }
}

private List<Integer> getNumList(int num, Supplier<Integer> supplier) {
    List<Integer> list = new ArrayList<>();

    for (int i = 0; i < num; i++) {
        list.add(supplier.get());
    }

    return list;
}

Function<T , R>:函数式接口

R apply(T t);

用途:对类型为T的对象应用操作,并返回结果,结果是R类型的对象,包含方法:R apply(T t);

@Test
public void testFunction() {
    String name = "Jack Yang";
    System.out.print(strHandler(name, String::toLowerCase));
}
private String strHandler(String str, Function<String, String> func) {
    return func.apply(str);
}

Predicate<T>:断言型接口

boolean test(T t);

用途:确定类型为T的对象是否满足某约束,并返回boolean值,包含方法:boolean test(T t);

@Test
public void testPredicate() {
    List<String> list = filterStr(
        Arrays.asList("jackyang", "jackie", "jordan", "ronaldo", "figo", "zidane"),
        s -> s.length() >= 6
    );
    for (String name : list) {
        System.out.println(name);
    }
}

private List<String> filterStr(List<String> list, Predicate<String> predicate) {
    List<String> handleList = new ArrayList<>();
    for(String str : list) {
        if(predicate.test(str)) {
            handleList.add(str);
        }
    }
    return handleList;
}

其他函数式接口(http://www.runoob.com/java/java8-functional-interfaces.html)

3.方法引用

方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致

若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName

构造器的参数列表,需要与函数式接口中参数列表保持一致

三种语法格式
  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法

4.Stream API

集合讲的是数据,流讲的是计算!
  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream流的操作三个步骤
  • 创建流(数据源:集合、数组)
  • 中间操作(操作链,对数据源数据进行计算)
  • 终止操作(产生结果)
创建Stream流
  • 集合创建流(Collection 接口扩展)

default Stream<E> stream() : 返回一个顺序流

default Stream<E> parallelStream() : 返回一个并行流

  • 数组创建流(Arrays 静态方法)

static <T> Stream<T> stream(T[] array): 返回一个流

  • 值创建流(静态方法 Stream.of())

public static<T> Stream<T> of(T... values) : 返回一个流

  • 创建无限流(函数创建 iterate和generate)

迭代 public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)

生成 public static<T> Stream<T> generate(Supplier<T> s)

@Slf4j
public class StreamTest extends AdminApiApplicationTests {
    @Data
    class Student {
        private String name;
        private Integer age;

        public Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    }

    @Test
    public void testStreamCreate() {
        System.out.println("-----------集合创建流-----------");
        Arrays.asList("jackyang", "", "jordan", "helloworld", "hellokitty").stream().filter(s -> s.length() > 8).forEach(System.out::println);

        System.out.println("-----------数据创建流-----------");
        Student[] students = new Student[]{
                new Student("jackyang", 30),
                new Student("jordan", 40),
                new Student("kitty", 18)
        };
        Arrays.stream(students).filter(student -> student.age > 20).forEach(System.out::println);

        System.out.println("-----------值创建流-----------");
        Stream.of(students).filter(student -> student.age < 20).forEach(System.out::println);

        System.out.println("-----------创建无限流-----------");
        Stream.iterate(5, s -> s + 2).limit(10).forEach(System.out::println);
        Stream.generate(() -> (int)(Math.random() * 100)).limit(10).forEach(System.out::println);
    }
}
中间操作

中间操作不会执行任何的操作,而是在终止操作时一次性全部处理,称为“惰性求值”

  • filter(Predicate p) 接收 Lambda 从流中排除某些元素
  • distinct() 通过流所生成元素的 hashCode() 和 equals() 去 除重复元素
  • limit(long maxSize) 截断流,使其元素不超过给定数量
  • skip(long n) 跳过元素,返回一个剔除了前 n 个元素的流,若流中元素不足n个,则返回一个空流
  • map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream
  • mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream
  • mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream
  • flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
  • sorted() 产生一个新流,其中按自然顺序排序
  • sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序
终止操作

终止操作会从流的流水线生成结果,其结果可以是任何不是流的值,例如:List、Integer,甚至是 void

匹配

  • allMatch(Predicate p) 检查是否匹配所有元素
  • anyMatch(Predicate p) 检查是否至少匹配一个元素
  • noneMatch(Predicate p) 检查是否没有匹配所有元素

查找

  • findFirst() 返回第一个元素
  • findAny() 返回当前流中的任意元素
  • count() 返回流中元素总数
  • max(Comparator c) 返回流中最大值
  • min(Comparator c) 返回流中最小值

遍历

  • forEach(Consumer c) 内部迭代

规约

  • reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回 T
  • reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回 Optional<T>

收集

  • collect(Collector c) 将流转换为其他形式,接收一个 Collector接口的实现

用于给Stream中元素做汇总的方法

toList
List<T>
把流中元素收集到List
List<Employee> emps = list.stream().collect(Collectors.toList());

Set<T>
把流中元素收集到Set
Set<Employee> emps = list.stream().collect(Collectors.toSet());
 
toCollection
Collection<T>
把流中元素收集到创建的集合
Collection<Employee>emps =list.stream().collect(Collectors.toCollection(ArrayList::new));
 
counting
Long
计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
 
summingInt
Integer
对流中元素的整数属性求和
int total = list.stream().collect(Collectors.summingInt(Employee::getSalary));
 
averagingInt
Double
计算流中元素Integer属性的平均 值
double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));
 
summarizingInt
IntSummaryStatistics
收集流中Integer属性的统计值。 如:平均值
IntSummaryStatistics iss = list.stream().collect(Collectors.summarizingInt(Employee::getSalary));

joining
String
连接流中每个字符串
String str = list.stream().map(Employee::getName).collect(Collectors.joining());
 
maxBy
Optional<T>
根据比较器选择最大值
Optional<Emp>max = list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
 
minBy
Optional<T>
根据比较器选择最小值
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));

reducing
归约产生的类型
从一个作为累加器的初始值开始,利用BinaryOperator与 流中元素逐个结合,从而归约成单个值
int total = list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));

collectingAndThen
转换函数返回的类型
包裹另一个收集器,对其结 果转换函数
int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
    
groupingBy
Map<K, List<T>>
根据某属性值对流分组,属 性为K,结果为V
Map<Emp.Status, List<Emp>> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus));

partitioningBy
Map<Boolean, List<T>>
根据true或false进行分区
Map<Boolean,List<Emp>> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));

5.并行流与串行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流

可以使用parallel() 与 sequential() 在并行流与串行流之间进行切换

Fork/Join框架: 就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join汇总.
采用 “工作窃取”模式(work-stealing): 当执行新的任务时它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中

6.新时间日期 API

  • LocalDate
  • LocalTime
  • LocalDateTime
now() 静态方法,根据当前时间创建对象
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now();

of() 静态方法,根据指定日期/时间创建 对象
LocalDate localDate = LocalDate.of(2016, 10, 26); 
LocalTime localTime = LocalTime.of(02, 22, 56); 
LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);

plusDays, plusWeeks, plusMonths, plusYears 向当前 LocalDate 对象添加几天、 几周、几个月、几年

minusDays, minusWeeks, minusMonths, minusYears 从当前 LocalDate 对象减去几天、 几周、几个月、几年

plus, minus 添加或减少一个 Duration 或 Period

withDayOfMonth, withDayOfYear, withMonth, withYear 将月份天数、年份天数、月份、年 份修改为指定的值并返回新的 LocalDate 对象

getDayOfMonth 获得月份天数(1-31)

getDayOfYear 获得年份天数(1-366)

getDayOfWeek 获得星期几(返回一个 DayOfWeek 枚举值)

getMonth 获得月份, 返回一个 Month 枚举值

getMonthValue 获得月份(1-12)

getYear 获得年份

until 获得两个日期之间的 Period 对象, 或者指定 ChronoUnits 的数字

isBefore, isAfter 比较两个 LocalDate

isLeapYear 判断是否是闰年
  • Instant 时间戳

Duration:用于计算两个时间间隔

Period:用于计算两个日期间隔

  • TemporalAdjuster: 时间校正器
  • 时间格式化
@Test
public void testDateFormat() {
    LocalDateTime local = LocalDateTime.now();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    System.out.println(formatter.format(local));
}

@Test
public void testDateFormat() {
    LocalDateTime local = LocalDateTime.now();
    String dateTime = local.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"));
    System.out.println(dateTime);
}

@Test
public void testDateFormat() {
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    String strDate = "2018年05月12日 14:31:33";
    LocalDateTime ldt = LocalDateTime.now();
    LocalDateTime newDate = ldt.parse(strDate, dateTimeFormatter);
    System.out.println(newDate);
}

7.接口中默认方法与静态方法

接口默认方法的类优先原则

若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时选择父类中的方法

如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略

接口冲突:

如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突

8.Optional类

常用方法:
Optional.of(T t) : 创建一个 Optional 实例

Optional.empty() : 创建一个空的 Optional 实例

Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例

isPresent() : 判断是否包含值

orElse(T t) : 如果调用对象包含值,返回该值,否则返回t

orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值

map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()

flatMap(Function mapper):与 map 类似,要求返回值必须是Optional

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

推荐阅读更多精彩内容

  • Java8新特性 Lambda表达式 概念 lambda表达式是一段可以传递的代码,它的核心思想是将面向对象中的传...
    好好秦先生阅读 821评论 0 1
  • 原创文章&经验总结&从校招到A厂一路阳光一路沧桑 详情请戳www.codercc.com 对于Java开发者来说,...
    你听___阅读 2,337评论 4 38
  • source Description You are to write a program that has to...
    Gitfan阅读 307评论 0 0
  • 切下一块根茎 丟进小小的水杯 不经意间 收获满满一杯的丰盛
    禾小he阅读 194评论 0 4