009-jdk1.8版本新特性一-展方法,Lambda表达式,函数式接口、方法引用构造引用
一、JDK1.8
名称:Spider(蜘蛛)
发布日期:2014-03-18
新特性:
1.1、扩展方法【接口的默认方法】
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法.
在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现,在C++中支持多继承,允许一个子类同时具有多个父类的接口与功能,在其他语言中,让一个类同时具有其他的可复用代码的方法叫做mixin。新的Java 8 的这个特新在编译器实现的角度上来说更加接近Scala的trait。 在C#中也有名为扩展方法的概念,允许给已存在的类型扩展方法,和Java 8的这个在语义上有差别。
示例:
- interface Formula {
- double calculate(int a);
- default double sqrt(int a) {
- return Math.sqrt(a);
- }
- }
- public class ExtendMethod {
- public static void main(String[] args) {
- Formula formula = new Formula() {
- @Override
- public double calculate(int a) {
- return sqrt(a * 100);
- }
- };
- System.out.println(formula.calculate(100)); // 100.0
- System.out.println(formula.sqrt(16)); // 4.0
- }
- }
Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。
文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算 sqrt(a * 100)。
1.2、Lambda表达式
“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
在java中使用lambda表达式替换匿名类中的函数,使用“() -> {}”代码块替代了整个匿名类中的某个方法函数。
示例1,从匿名类到lambda表达式
1、匿名类排序
- List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
- Collections.sort(names, new Comparator<String>() {
- @Override
- public int compare(String a, String b) {
- return b.compareTo(a);
- }
- });
只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
2、java8后lambda表达式
- Collections.sort(names, (String a, String b) -> {
- return b.compareTo(a);
- });
3、继续优化,对于单行代码只有一个返回值,可以去掉大括号{}以及return关键字
- Collections.sort(names, (String a, String b) -> b.compareTo(a));
4、参数类型推断,Java编译器可以自动推导出参数类型。
- Collections.sort(names, (a, b) -> b.compareTo(a));
示例2、多线程的lambda表达式
- // Java 8 传统方式:
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("Java 8 传统方式");
- }
- }).start();
- // Java 8 lambda方式:
- new Thread(() -> System.out.println("Java 8 lambda方式!") ).start();
- // Java 8 lambda方式:
- Runnable runnable = () -> System.out.println("Java 8 lambda方式!多线程");
- new Thread(runnable).start();
示例3、遍历for forEach
- // Java 8之前:
- List<String> features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
- for (String feature : features) {
- System.out.println(feature);
- }
- // Java 8之后:
- List<String> features2 = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
- features2.forEach(n -> System.out.println(n));
- // 使用Java 8的方法引用更方便,方法引用由::双冒号操作符标示
- features2.forEach(System.out::println);
示例4、Lambda在Collections中的用法
- List<Integer> myList = new ArrayList<>();
- for(int i=0; i<100; i++) myList.add(i);
- //有序流
- Stream<Integer> sequentialStream = myList.stream();
- //并行流
- Stream<Integer> parallelStream = myList.parallelStream();
- //使用lambda表达式,过滤大于90的数字
- Stream<Integer> highNums = parallelStream.filter(p -> p > 90);
- //lambdag表达式 forEach循环
- highNums.forEach(p -> System.out.println("大于90的数 并行="+p));
- Stream<Integer> highNumsSeq = sequentialStream.filter(p -> p > 90);
- highNumsSeq.forEach(p -> System.out.println("大于90的数 有序="+p));
lambda作用域
1、访问外部局部变量【可以访问 后续不能修改,final型】
- int num = 1;//等价于 final int num = 1; 固可读,不可修改,即隐性的具有final的语义
- Converter<Integer, String> stringConverter =
- (from) -> String.valueOf(from + num);
- stringConverter.convert(2); //
2、访问对象内字段与静态变量
和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的:
- class Lambda4 {
- static int outerStaticNum;
- int outerNum;
- void testScopes() {
- Converter<Integer, String> stringConverter1 = (from) -> {
- outerNum = 23;
- return String.valueOf(from);
- };
- Converter<Integer, String> stringConverter2 = (from) -> {
- outerStaticNum = 72;
- return String.valueOf(from);
- };
- }
- }
3、Lambda表达式中是无法访问到默认方法的
- interface Formula {
- double calculate(int a);
- default double sqrt(int a) {
- return Math.sqrt(a);
- }
- }
- public class ExtendMethod {
- public static void main(String[] args) {
- Formula formula = new Formula() {
- @Override
- public double calculate(int a) {
- return sqrt(a * 100);
- }
- };
- //Formula formula2 = (a) -> calculate( a * 100); //报错
- //Formula formula2 = (a) -> sqrt( a * 100); //报错
- System.out.println(formula.calculate(100)); // 100.0
- System.out.println(formula.sqrt(16)); // 4.0
- }
- }
1.3、函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为lambda表达式。
函数式接口可以现有的函数友好地支持 lambda。
1、定义
包含函数式的设计,接口需带有@FunctionalInterface的注解。它注解在接口层面,且注解的接口要有且仅有一个抽象方法。具体就是说,注解在Inteface上,且interface里只能有一个抽象方法,可以有default方法。因为从语义上来讲,一个函数式接口需要通过一个***逻辑上的***方法表达一个单一函数。单一不是说限制你一个interface里只有一个抽象方法,单是多个方法的其他方法需要是继承自Object的public方法,或者你要想绕过,就自己实现default。函数式接口自己本身一定是只有一个抽象方法。同时,如果是Object类的public方法,也是不允许的。
示例查看定义:
- // 错误:no target method found
- @FunctionalInterface
- public interface Func{
- }
- // 正确
- @FunctionalInterface
- public interface Func1{
- void run();
- }
- // 错误:含有多个抽象方法
- @FunctionalInterface
- public interface Func2{
- void run();
- void foo();
- }
- // 错误:no target method found,equals 方法签名是Object类的public方法
- @FunctionalInterface
- public interface Func3{
- boolean equals(Object obj);
- }
- // 正确
- @FunctionalInterface
- public interface Func4{
- boolean equals(Object obj);
- void run();
- }
- // 错误:可以是Object的public方法,而clone是protected的,这里相当于有两个抽象方法
- @FunctionalInterface
- public interface Func5{
- Object clone();
- void run();
- }
2、系统函数式接口
JDK 1.8之前已有的函数式接口:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.security.PrivilegedAction
- java.util.Comparator
- java.io.FileFilter
- java.nio.file.PathMatcher
- java.lang.reflect.InvocationHandler
- java.beans.PropertyChangeListener
- java.awt.event.ActionListener
- javax.swing.event.ChangeListener
JDK 1.8 新增加的函数接口:
- java.util.function
java.util.function 它包含了很多类,用来支持 Java的 函数式编程,该包中的函数式接口有:
- 序号 接口 & 描述
- 1 BiConsumer<T,U>
- 代表了一个接受两个输入参数的操作,并且不返回任何结果
- 2 BiFunction<T,U,R>
- 代表了一个接受两个输入参数的方法,并且返回一个结果
- 3 BinaryOperator<T>
- 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
- 4 BiPredicate<T,U>
- 代表了一个两个参数的boolean值方法
- 5 BooleanSupplier
- 代表了boolean值结果的提供方
- 6 Consumer<T>
- 代表了接受一个输入参数并且无返回的操作
- 7 DoubleBinaryOperator
- 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。
- 8 DoubleConsumer
- 代表一个接受double值参数的操作,并且不返回结果。
- 9 DoubleFunction<R>
- 代表接受一个double值参数的方法,并且返回结果
- 10 DoublePredicate
- 代表一个拥有double值参数的boolean值方法
- 11 DoubleSupplier
- 代表一个double值结构的提供方
- 12 DoubleToIntFunction
- 接受一个double类型输入,返回一个int类型结果。
- 13 DoubleToLongFunction
- 接受一个double类型输入,返回一个long类型结果
- 14 DoubleUnaryOperator
- 接受一个参数同为类型double,返回值类型也为double 。
- 15 Function<T,R>
- 接受一个输入参数,返回一个结果。
- 16 IntBinaryOperator
- 接受两个参数同为类型int,返回值类型也为int 。
- 17 IntConsumer
- 接受一个int类型的输入参数,无返回值 。
- 18 IntFunction<R>
- 接受一个int类型输入参数,返回一个结果 。
- 19 IntPredicate
- :接受一个int输入参数,返回一个布尔值的结果。
- 20 IntSupplier
- 无参数,返回一个int类型结果。
- 21 IntToDoubleFunction
- 接受一个int类型输入,返回一个double类型结果 。
- 22 IntToLongFunction
- 接受一个int类型输入,返回一个long类型结果。
- 23 IntUnaryOperator
- 接受一个参数同为类型int,返回值类型也为int 。
- 24 LongBinaryOperator
- 接受两个参数同为类型long,返回值类型也为long。
- 25 LongConsumer
- 接受一个long类型的输入参数,无返回值。
- 26 LongFunction<R>
- 接受一个long类型输入参数,返回一个结果。
- 27 LongPredicate
- R接受一个long输入参数,返回一个布尔值类型结果。
- 28 LongSupplier
- 无参数,返回一个结果long类型的值。
- 29 LongToDoubleFunction
- 接受一个long类型输入,返回一个double类型结果。
- 30 LongToIntFunction
- 接受一个long类型输入,返回一个int类型结果。
- 31 LongUnaryOperator
- 接受一个参数同为类型long,返回值类型也为long。
- 32 ObjDoubleConsumer<T>
- 接受一个object类型和一个double类型的输入参数,无返回值。
- 33 ObjIntConsumer<T>
- 接受一个object类型和一个int类型的输入参数,无返回值。
- 34 ObjLongConsumer<T>
- 接受一个object类型和一个long类型的输入参数,无返回值。
- 35 Predicate<T>
- 接受一个输入参数,返回一个布尔值结果。
- 36 Supplier<T>
- 无参数,返回一个结果。
- 37 ToDoubleBiFunction<T,U>
- 接受两个输入参数,返回一个double类型结果
- 38 ToDoubleFunction<T>
- 接受一个输入参数,返回一个double类型结果
- 39 ToIntBiFunction<T,U>
- 接受两个输入参数,返回一个int类型结果。
- 40 ToIntFunction<T>
- 接受一个输入参数,返回一个int类型结果。
- 41 ToLongBiFunction<T,U>
- 接受两个输入参数,返回一个long类型结果。
- 42 ToLongFunction<T>
- 接受一个输入参数,返回一个long类型结果。
- 43 UnaryOperator<T>
- 接受一个参数为类型T,返回值类型也为T。
3、常用函数式接口使用
1️⃣、Function<T, R> 功能型函数式接口
T:入参类型,R:出参类型
调用方法:R apply(T t);
定义函数示例:Function<Integer, Integer> func = p -> p * 10; // 输出入参的10倍
调用函数示例:func.apply(10); // 结果100
接口定义说明:
- package java.util.function;
- import java.util.Objects;
- @FunctionalInterface
- public interface Function<T, R> {
- // 将参数赋予给相应方法
- R apply(T t);
- // 先执行参数(即也是一个Function)的,再执行调用者(同样是一个Function)
- default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
- Objects.requireNonNull(before);
- return (V v) -> apply(before.apply(v));
- }
- // 先执行调用者,再执行参数,和compose相反。
- default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
- Objects.requireNonNull(after);
- return (T t) -> after.apply(apply(t));
- }
- // 返回当前正在执行的方法
- static <T> Function<T, T> identity() {
- return t -> t;
- }
- }
示例
- Function<Integer, Integer> times2 = i -> i*2;
- Function<Integer, Integer> squared = i -> i*i;
- System.out.println(times2.apply(4));
- System.out.println(squared.apply(4));
- //先4×4然后16×2,先执行apply(4),在times2的apply(16),先执行参数,再执行调用者。
- System.out.println(times2.compose(squared).apply(4)); //32
- // 先4×2,然后8×8,先执行times2的函数,在执行squared的函数。
- System.out.println(times2.andThen(squared).apply(4)); //64
- // 取出 Function.identity().compose(squared) 的 squared执行,结果 4x4
- System.out.println(Function.identity().compose(squared).apply(4)); //16
- // 取出 Function.identity().apply(4) 的 4执行,结果 4
- System.out.println(Function.identity().apply(4)); //
理解:Function类,是一个方法,类似c++里面函数指针,一个变量可以指向一个方法,并且可以把两个方法组合起来使用(使用compose和andThen),而可以通过identity这个静态方法来获取当前执行的方法。
2️⃣、Predicate<T>断言型函数式接口
T:入参类型;出参类型是Boolean
调用方法:boolean test(T t);
定义函数示例:Predicate<Integer> predicate = p -> p % 2 == 0; // 判断是否、是不是偶数
调用函数示例:predicate.test(100); // 运行结果true
接口定义说明
- package java.util.function;
- import java.util.Objects;
- // 一个谓词,布尔类型函数
- @FunctionalInterface
- public interface Predicate<T> {
- // 根据给定参数 获取布尔值
- boolean test(T t);
- // and 与 &&
- default Predicate<T> and(Predicate<? super T> other) {
- Objects.requireNonNull(other);
- return (t) -> test(t) && other.test(t);
- }
- // 取反
- default Predicate<T> negate() {
- return (t) -> !test(t);
- }
- // or 或者
- default Predicate<T> or(Predicate<? super T> other) {
- Objects.requireNonNull(other);
- return (t) -> test(t) || other.test(t);
- }
- // 相等
- static <T> Predicate<T> isEqual(Object targetRef) {
- return (null == targetRef)
- ? Objects::isNull
- : object -> targetRef.equals(object);
- }
- }
示例
- String tempStr="Spring is A";
- Predicate<String> length5=p->p.length()>=5;
- Predicate<String> containA=p->p.contains("A");
- Predicate<String> containB=p->p.contains("B");
- // 长度大于5 true
- System.out.println(length5.test(tempStr));
- // 包含A true
- System.out.println(containA.test(tempStr));
- // 长度大于5 and 包含A true
- System.out.println(length5.and(containA).test(tempStr));
- // 长度大于5 and 包含B false
- System.out.println(length5.and(containB).test(tempStr));
- // 长度大于5 or 包含B false
- System.out.println(length5.or(containB).test(tempStr));
- // 长度大于5 取反 false
- System.out.println(length5.negate().test(tempStr));
- // 长度大于5 取反 false
- System.out.println(!length5.test(tempStr));
3️⃣、Supplier<T>供给型函数式接口
T:出参类型;没有入参
调用方法:T get();
定义函数示例:Supplier<Integer> supplier= () -> 100; // 常用于业务“有条件运行”时,符合条件再调用获取结果的应用场景;运行结果须提前定义,但不运行。
调用函数示例:supplier.get();
接口定义说明:
- package java.util.function;
- // 生产型
- @FunctionalInterface
- public interface Supplier<T> {
- //得到一个结果
- T get();
- }
示例
- public static String supplierTest(Supplier<String> supplier) {
- return supplier.get();
- }
- public static void main(String[] args) {
- String name = "测试";
- // () -> name.length() 无参数,返回一个结果(字符串长度)
- // 所以该lambda表达式可以实现Supplier接口
- System.out.println(supplierTest(() -> name.length() + ""));
- }
4️⃣、Consumer<T>消费型
T:入参类型;没有出参
调用方法:void accept(T t);
定义函数示例:Consumer<String> consumer= p -> System.out.println(p); // 因为没有出参,常用于打印、发送短信等消费动作
调用函数示例:consumer.accept("18800008888");
接口方法定义
- package java.util.function;
- import java.util.Objects;
- @FunctionalInterface
- public interface Consumer<T> {
- void accept(T t);
- default Consumer<T> andThen(Consumer<? super T> after) {
- Objects.requireNonNull(after);
- return (T t) -> { accept(t); after.accept(t); };
- }
- }
示例
- public static void modifyTheValue3(int value, Consumer<Integer> consumer) {
- consumer.accept(value);
- }
- public static void main(String[] args) {
- // (x) -> System.out.println(x * 2)接受一个输入参数x
- // 直接输出,并没有返回结果
- // 所以该lambda表达式可以实现Consumer接口
- modifyTheValue3(3, (x) -> System.out.println(x * 2));
- }
1.4、方法引用和构造引用
方法引用是对Lambda表达式符合某种情况下的一种缩写,使得我们的Lambda表达式更加的精简, 也可以理解为Lambda表达式的另一种表现形式(缩写)
使用 :: 关键字来传递方法或者构造函数引用
方法引用
1、静态引用【指向静态方法的方法引用】类名::静态方法名
- @FunctionalInterface
- interface Converter<F, T> {
- T convert(F from);
- }
- public class TestReference {
- public static void main(String[] args) {
- //静态引用
- Converter<String, Integer> converter = Integer::valueOf;
- Integer converted = converter.convert("123");
- System.out.println(converted); //
- }
- }
2、指向任意类型实例方法的方法引用(这个实例为方法的参数)【类名::实例方法名】
- //指向任意类型实例方法的方法引用(这个实例为方法的参数)
- List<String> list = Arrays.asList("av","asdf","sad","324","43");
- List<String> collect = list.stream().map(String::toUpperCase).collect(Collectors.toList());
- System.out.println(collect);
3、向现有对象的实例方法的方法引用(这个实例为外部对象)【实例对象名::实例方法名】
- //指向现有对象的实例方法的方法引用(这个实例为外部对象)
- List<String> list2 = Arrays.asList("av","asdf","sad","324","43");
- String a="avasdf";
- List<String> collect2 = list2.stream().filter(a::contains).collect(Collectors.toList());
- System.out.println(collect2);
典型示例
- //传统Lambda表达式
- Consumer<String> consumer = (x) -> System.out.println(x);
- consumer.accept("Hi: 我是Lambda表达式实现的!");
- //方法引用实现
- consumer = System.out::println;
- consumer.accept("Hello : 我是使用方法引用实现的 ");
4、构造引用【类名 :: new 】
与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法。
- //传统Lambda方式
- Supplier<Map> mapSupplier = ()-> new HashMap<String,String>();
- Map map = mapSupplier.get();
- System.out.println(map);
- //构造器引用
- mapSupplier = HashMap::new;
- map = mapSupplier.get();
- System.out.println(map);
009-jdk1.8版本新特性一-展方法,Lambda表达式,函数式接口、方法引用构造引用的更多相关文章
- Java8新特性学习笔记(一) Lambda表达式
没有用Lambda表达式的写法: Comparator<Transaction> byYear = new Comparator<Transaction>() { @Overr ...
- Java8新特性第1章(Lambda表达式)
在介绍Lambda表达式之前,我们先来看只有单个方法的Interface(通常我们称之为回调接口): public interface OnClickListener { void onClick(V ...
- Java8新特性(一)——Lambda表达式与函数式接口
一.Java8新特性概述 1.Lambda 表达式 2. 函数式接口 3. 方法引用与构造器引用 4. Stream API 5. 接口中的默认方法与静态方法 6. 新时间日期 API 7. 其他新特 ...
- 【Java8新特性】还没搞懂函数式接口?赶快过来看看吧!
写在前面 Java8中内置了一些在开发中常用的函数式接口,极大的提高了我们的开发效率.那么,问题来了,你知道都有哪些函数式接口吗? 函数式接口总览 这里,我使用表格的形式来简单说明下Java8中提供的 ...
- jdk8新特性-亮瞎眼的lambda表达式
jdk8之前,尤其是在写GUI程序的事件监听的时候,各种的匿名内部类,大把大把拖沓的代码,程序毫无美感可言!既然Java中一切皆为对象,那么,就类似于某些动态语言一样,函数也可以当成是对象啊!代码块也 ...
- Java 8 新特性-菜鸟教程 (3) -Java 8 函数式接口
Java 8 函数式接口 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口. 函数式接口可以被隐式转换为lambda表达式. 函数式接 ...
- Java8新特性(三)——Optional类、接口方法与新时间日期API
一.Optional容器类 这是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. 查看结构图可以看到有如下常用方法: of(T)—— ...
- Java8新特性 -- 四大内置的核心函数式接口
可以把这些函数式接口作为方法的参数. 1.0 核心内置函数式接口一: 消费型接口@FunctionalInterfacepublic interface Consumer<T> { voi ...
- Java8新特性 利用流和Lambda表达式对List集合进行处理
Lambda表达式处理List 最近在做项目的过程中经常会接触到 lambda 表达式,随后发现它基本上可以替代所有 for 循环,包括增强for循环.也就是我认为,绝大部分的for循环都可以用 la ...
随机推荐
- 设置ADB网络连接目标板
adb connect 网络连接目标板报错,原因参考[http://ytydyd.blog.sohu.com/146260552.html].而且指定 adb connect <IP>:5 ...
- hadoop完全分布式搭建HA(高可用)
2018年03月25日 16:25:26 D调的Stanley 阅读数:2725 标签: hadoop HAssh免密登录hdfs HA配置hadoop完全分布式搭建zookeeper 配置 更多 个 ...
- 【Python学习】记一次开源博客系统Blog_mini源码学习历程-Flask
今天准备看看Flask框架,找到一套博客系统源码,拿来学习学习 https://github.com/xpleaf/Blog_mini 演示地址 http://140.143.205.19 技术框架 ...
- pace.js简介
Pace.js – 超赞的页面加载进度自动指示和 Ajax 导航效果 在页面中引入 Pace.js 和您所选择主题的 CSS 文件,就可以让你的页面拥有漂亮的加载进度和 Ajax 导航效果.不需要挂接 ...
- Android studio快捷键设置
Android Studio格式化代码设置和代码风格设置.代码提示键 http://blog.csdn.net/u010156024/article/details/48207145 Android ...
- openvpn 负载均衡方案
这些方案的前提是,vpnserver的key都是一样的.方案1在openvpn客户端设两个配置文件,我们自己手动去连接去选择方案2在openvpn 的配置文件里面加个随机参数remote 8.8.8. ...
- php 加密压缩
php 把文件打成压缩包 ,可以去搜下 pclzip 搜很好多地方没有找到对压缩包进行加密操作的. 如果服务器是linux 那么见代码: $filename="test.csv"; ...
- FtpWebRequest UploadFile返回"The underlying connection was closed: The server committed a protocol violation."解决方法
将FtpWebRequest的KeepAlive设置为true. return Return<Boolean>( new Uri(ftpPath + fileName), request ...
- 使用Autolayout xib实现动态高度的TableViewCell
http://my.oschina.net/u/2360693/blog/481236?p={{totalPage}} 创建Xib文件 首先将Cell做好布局,调整到满意的位置和宽度,然后开始做Aut ...
- Windows Server 2008 R2之一活动目录服务部署
测试环境: 服务器:计算机名Win2008R2CNDC,已安装Windows Server 2008 R2.IPV4:192.168.1.13,255.255.255.0,网关地址192.168.1. ...