Java8新特性总结

一.接口内允许添加默认实现的方法

在原来的定义中接口中只能有方法声明,不能有方法体。在Java8中,接口也可以有自己带有实现的方法啦。具体来说是要用default来修饰的方法,其可以像类中的方法一样有执行语句。在实现接口时,可以不实现其default方法,并且实现类对象可以调用其接口的default方法。当然也可以在实现类中覆盖default方法。

public class InterfaceDemo {
    public static void main(String[] args) {
        Formula formula = new Formula() {
            @Override
            public double calculate(int a) {
                return a + 1;
            }

//           @Override
//            public double sqrt(int a) {
//              return a;
//            }
        };

        System.out.println(formula.calculate(100));
        System.out.println(formula.sqrt(100));
    }
}

interface Formula {
    //计算
    double calculate(int a);

    //求平方根
    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}

二.Lambda表达式

Lambda简化了匿名内部类的写法。Java8中可以通过类型推断来判断出用户的意图,不必将类型等信息写全。特别是方法实现体中只有一句语句的实现类,更能加大简化力度。

Lambda解决了将一个方法作为参数传值的问题。解决了一个函数是否可以独立存在的问题。是Java向函数式编程的一种靠拢。

一般在某个方法只使用一次的地方使用Lambda表达式;如果方法没有入参,则只写一个()->{语句};当只有一个参数,且类型可推断时,()可省略;如果方法体中只有一条语句花括号可以省略;


public class LambdaDemo {
    public static void func1() {
        System.out.println("not use Lambda");
        List<String> strs = Arrays.asList("hello","word","apple","people","sea","book","school","computer");

        //old way 
        Collections.sort(strs,new Comparator<String>() {
            @Override
            public int compare(String a,String b) {
                return b.compareTo(a);
            }
        });

        System.out.println(strs);
    }

    public static void func2() {
        System.out.println("use Lambda");
        List<String> strs = Arrays.asList("hello","word","apple","people","sea","book","school","computer");

        //way 1
        Collections.sort(strs,(String a,String b) -> {
            return a.compareTo(b);
        });

        //way 2 : only one statement 
        Collections.sort(strs,(String a,String b) -> a.compareTo(b));

        //way 3 : omit class
        Collections.sort(strs,(a,b) -> a.compareTo(b));

        System.out.println(strs);
    }
}

三.函数式接口Functional Interface

学习了上述Lambda的内容肯定会有一些疑问:如果接口有多个需要实现的方法 呢,还能使用Lambda?如果可以的话Lambda是如何做推断的。

答案是,使用Lambda时要求接口中只能有一个抽象方法(通过default修饰的带有方法体的接口中的方法不是抽象方法)。

如果一个接口被注解@FunctionalInterface修饰,则该接口只能有一个抽象方法,否则会报错。

四.引用类的构造器及方法

在Lambda中若是直接调用了一个方法,且调用方法的形参和要实现的接口抽象方法形参一致,则可以进一步简写。举例如下:
接口定义:

@FunctionalInterface
interface Converter<F,T> {
    T convert(F form);
}

Lambda表达式

//旧的写法
Converter<String,Integer> convert1 = (from) -> Integer.valueOf(from);
//新的写法
Converter<String,Integer> convert2 = Integer::valueOf;

System.out.println(convert1.convert("1234"));

引用其他类型的方法

  • 例子中的方法是Integer类的静态方法,如果是某个类的实例方法,则应该使用一个对象加::来引用。如,obj::func;
  • 如果要调用的一个构造方法(抽象方法返回的是一个对象),则应该这样使用:Integer::new。用new代替构造方法名字。

五.Lambda访问外部变量及接口默认方法

访问局部变量

  • 可以访问局部的final变量,但不能修改。
  • 与匿名内部类不同的是,外部变量不需要显示地声明为final,但却要有final的特点,不能被修改,在Lambda之后被修改也不行。

访问成员变量和静态变量
可以任意读写,举例如下:

public class FunctionInterface {
    String str = "init";
    static Integer num = 0;

    public void testScope() {
        Converter<String,Integer> convert = (from) -> {
            //在这里可访问成员变量和静态变量
            str = from;
            num = Integer.valueOf(from);
            return num;
        };

        System.out.println(convert.convert("3453"));
        System.out.println(convert.convert("5678"));
    }        
}

访问接口的默认方法
在匿名类中可以访问接口定义的默认方法,在Lambda中不可以访问。

六.内置函数式接口

Java8中内置了许多函数式接口,包括Comparator和Runnable等,它们被添加了@FunctionalInterface注解,以用来支持Lambda表达式。

6.1Predicate断言

查看源码,这个函数式接口中要实现的方法为:boolean test(T t); 即一个判断传入值真假的方法,当然判断的规则由你自己定义。
如定义一个判断字符串长度是否大于10的Predicate:

import java.util.function.Predicate;

public class PredicateDemo {
    public static void main(String[] args) {
        Predicate<String> predicate = s -> s.length() > 10;

        System.out.println(predicate.test("hello"));
        System.out.println(predicate.test("hello,world!"));
    }
}

6.2 Function

查其源码,需要实现一个R apply(T t)的方法。这个接口提供链式调用、组合的功能。

6.3 Supplier

Supplier<Person> personSupplier = Person::new;
personSupplier.get();

6.4 Consumer

??
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));

6.5 Optional

参考资料

七.Stream流

什么是Stream流?
参考资料
Stream流提供了一种对集合Collection的方便的操作。分为“中间操作”和“终端操作”两种。中间操作的结果还是返回一个Stream,可以继续操作;而终端操作会返回一个结构不能继续流操作了。

要使用Sream首先要通过Collection的Stream方法获取一个Stream对象。

7.1 Filter过滤 中间操作

筛选出集合中满足一定条件的元素。Stream有一个filter方法,入参是一个Predicate,筛选结果是Predicate.test为true的集合的Stream。下面来看一个筛选出String集合中以"s"开头的String的程序:

List<String> list = Arrays.asList("hello","world","apple","people","sea",
                                  "watch","table","book","school","help");
list
    .stream() //获取stream
    .filter(s -> s.startsWith("s"))  //设置filter。中间操作
    .forEach(System.out::println);   //打印出流中的元素。终端操作

7.2 Sorted排序 中间操作

可以给sorted()方法传入一个Comparator用来自定义排序,否则将使用默认排序规则。

list
    .stream()
    .sorted((a,b) -> b.compareTo(a))
    .forEach(System.out::println);

7.3 Map

map方法入参为一个Function函数式接口。调用map方法将对集合中的每一个元素执行一下Function中的apply方法,并返回由其返回值组成的集合的流。

举例:将表示数字的字符串集合全部转换为数字再加一后输出。

List<String> list = Arrays.asList("10","100","1000");

System.out.println("---- test map ----");
list
    .stream()
    .map(Integer::valueOf)  //转换为整数
    .map(a -> a + 1)        //执行加一操作
    .forEach(System.out::println);

7.4Match匹配

是种终端操作,结果不是stream对象,而是boolean值
根据Predicate指定的规则判断集合中是否有匹配的,有的话返回true。
有三种形式,anyMatch:有一个匹配就返回true。allMatch:全部匹配返回true。noneMatch:全部不匹配返回true。

boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);

7.5 Count计数

终端操作,统计stream中元素的个数。

long count = 
    list
        .stream() //获取stream
        .filter(s -> s.startsWith("s"))  //设置filter。中间操作
        .count();

7.6 Reduce

list[0]和list[1]执行操作,得到的结果为result。result再和list[2]执行操作,得到的结果result。依次进行,对所有元素执行一遍。

根据上述描述也可以看出,这里的“操作”必须满足两个入参、返回值是同一类型的。

reduce方法的入参是:BinaryOperator<T> 这里的T就是集合的元素类型。

举例:求Integer集合中所有元素的和。

List<Integer> list = Arrays.asList(1,2,3,4,5);

System.out.println("---- test reduce ----");
Optional<Integer> sum = 
    list
        .stream()
        .reduce((a,b) -> a + b);

sum.ifPresent(System.out::println);

注意:reduce的返回值为Optional<T>

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

推荐阅读更多精彩内容