java8特性总结

  1. Lambda 表达式
    格式
(parameters) -> expression
(parameters) -> { statements; }

伪代码如下

public static void main(String[] args) {
        JFrame jFrame = new JFrame("My JFrame");
        JButton jButton = new JButton("My button");
        jButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                
            }
        });
    }

我们常常使用的匿名内部类如上

使用Lambda 表达式改写后如下

jButton.addActionListener(event -> System.out.println("button pressed"));

原理

@FunctionalInterface 函数式接口

如果接口只有一个抽象方法,那么它就是一个函数式接口
如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口

@FunctionalInterface
interface  MyInterface{
    void test();

    String toString();
}

public class Test {

    public  void myTest(MyInterface myInterface){
        System.out.println("进入myTest");
        myInterface.test();
        System.out.println("进入myTest执行完毕");
    }
    public static void main(String[] args) {
        Test test = new Test();

        test.myTest(()->{
            System.out.println("输出mytest");
        });
        System.out.println("------------");
       
        MyInterface myInterface =()->{
            System.out.println("hello");
        };
    }
}

小结

即Java的函数式编程,其实只是把方法看作了一个对象,传入的还是一个接口,最终还是通过函数式接口去调用对应的方法,这也是java8为什么会有Default方法的原因之一,一个是为了兼容,子类不用去实现,就可以拥有方法的功能。

jdk8里面的函数式接口
JDK 1.8 新增加函数接口
统一在java.util.function包下面

接口 说明
BiConsumer<T,U> 代表了一个接受两个输入参数的操作,并且不返回任何结果。
BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果。
BinaryOperator<T> 代表了一个作用于两个同类型操作符的操作,并且返回了操作符同类型的结果。
BiPredicate<T,U> 代表了一个两个参数的 boolean 值方法。
BooleanSupplier 代表了 boolean 值结果的提供方。
Consumer<T> 代表了接受一个输入参数并且无返回的操作。
DoubleBinaryOperator 代表了作用于两个 double 值操作符的操作,并且返回一个 double 值的结果。
DoubleConsumer 代表一个接受 double 值参数的操作,并且不返回结果。
DoubleFunction<R> 代表接受一个 double 值参数的方法,并且返回结果。
DoublePredicate<R> 代表一个拥有 double 值参数的 boolean 值方法。
DoubleSupplier 代表一个 double 值结构的提供方。
DoubleToIntFunction 接受一个 double 类型输入,返回一个 int 类型结果。
DoubleToLongFunction 接受一个 double 类型输入,返回一个 long 类型结果。
DoubleUnaryOperator 接受一个参数同为类型 double,返回值类型也为 double 。
Function<T,R> 接受一个输入参数,返回一个结果。
IntBinaryOperator 接受两个参数同为类型 int,返回值类型也为 int 。
IntConsumer 接受一个 int 类型的输入参数,无返回值 。
IntFunction<R> 接受一个 int 类型输入参数,返回一个结果 。
IntPredicate 接受一个 int 输入参数,返回一个 boolean 的结果。
IntSupplier 无参数,返回一个 int 类型结果。
IntToDoubleFunction 接受一个 int 类型输入,返回一个 double 类型结果 。
IntToLongFunction 接受一个 int 类型输入,返回一个 long 类型结果。
IntUnaryOperator 接受一个参数同为类型 int,返回值类型也为 int 。
LongBinaryOperator 接受两个参数同为类型 long,返回值类型也为 long。
LongConsumer 接受一个 long 类型的输入参数,无返回值。
LongFunction<R> 接受一个 long 类型输入参数,返回一个结果。
LongPredicate 接受一个 long 输入参数,返回一个 boolean 类型结果。
LongSupplier 无参数,返回一个结果 long 类型的值。
LongToDoubleFunction 接受一个 long 类型输入,返回一个 double 类型结果。
LongToIntFunction 接受一个 long 类型输入,返回一个int类型结果。
LongUnaryOperator 接受一个参数同为类型 long,返回值类型也为 long。
ObjDoubleConsumer<T> 接受一个 object 类型和一个 double 类型的输入参数,无返回值。
ObjIntConsumer<T> 接受一个 object 类型和一个 int 类型的输入参数,无返回值。
ObjLongConsumer<T> 接受一个 object 类型和一个 long 类型的输入参数,无返回值。
Predicate<T> 接受一个输入参数,返回一个 boolean 结果。
Supplier<T> 无参数,返回一个结果。
ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个 double 类型结果。
ToDoubleFunction<T> 接受一个输入参数,返回一个 double 类型结果。
ToIntBiFunction<T,U> 接受两个输入参数,返回一个 int 类型结果。
ToIntFunction<T> 接受一个输入参数,返回一个 int 类型结果。
ToLongBiFunction<T,U> 接受两个输入参数,返回一个 long 类型结果。
ToLongFunction<T> 接受一个输入参数,返回一个 long 类型结果。
UnaryOperator<T> 接受一个参数为类型 T,返回值类型也为 T。

方法引用

可以直接引用已有 Java 类或对象(实例)的方法或构造器。与 Lambda 联合使用,可以使语言的构造更紧凑简洁,减少冗余代码。
通过方法的名字来指向一个方法。
使用一对冒号 :: 。
只是一个语法糖,并不是所有方法都可以使用方法引用

有几种使用方式

构造器引用

语法为 Class::new,或者 Class< T >::new。

静态方法引用

语法为 Class::staticMethod。

特定类的任意对象的方法引用

语法为 Class::method。

特定对象的方法引用

语法为 instance::method。


默认方法

默认方法是接口可以有实现方法,而且不需要实现类去实现其方法。

public interface IOperation {
   default void print(){
      System.out.println("");
   }
}

静态默认方法

接口可以声明(并且可以提供实现)静态方法。

public interface Operation {
   default void printA(){
      System.out.println("A");
   }
    // 静态方法
   static void printB(){
      System.out.println("B");
   }
}

Stream

以一种声明的方式处理数据
语法类似于SQL,即描述式的
需要将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

List<Integer> transactionsIds = widgets.stream().filter(b -> b.getColor() == RED).sorted((x,y) -> x.getWeight() - y.getWeight()).mapToInt(Widget::getWeight).sum();

像 filter 这样只描述 Stream,最终不产生新集合的方法叫作惰性求值方法。而像 sum 这样最终会从 Stream 产生值的方法叫作及早求值方法。
在一个 Stream 操作中,可以有多次惰性求值,但有且仅有一次及早求值。

小结
Stream(流)是一个来自数据源的元素队列并支持聚合操作。

元素是特定类型的对象,形成一个队列。 Java 中的 Stream 并不会存储元素,而是按需计算。
数据源流的来源。 可以是集合,数组,I/O channel, 产生器 generator 等。
聚合操作类似 SQL 语句一样的操作, 如 filter,map,reduce,find,match,sorted 等。
中间操作(惰性求值)都会返回Stream,只有调用及早求值,才会返回最终结果

流的分类

有限长度,即有限流
无限长度,即无限流,一般结合limit进行配合使用


生成流的几种方式

of

其生成的 Stream 是有限长度的,Stream 的长度为其内的元素个数。

返回

Stream<Integer> integerStream = Stream.of(1, 2, 3);
Stream<String> stringStream = Stream.of("A");

generator

返回一个 无限 长度的 Stream,其元素由 Supplier 接口的提供。

1.在 Supplier 里是一个函数接口,只封装了一个 get() 方法,其用来返回任何泛型的值,该结果在不同的时间内,返回的可能相同也可能不相同,没有特殊的要求。
2.通常用于随机数、常量的 Stream,或者需要前后元素间维持着某种状态信息的 Stream。
3.把 Supplier 实例传递给 Stream.generate() 生成的 Stream,默认是串行(相对 parallel 而言)但无序的(相对 ordered 而言)。

Stream.generate(java.lang.Math::random);

iterate

iterate方法,其返回的也是一个无限长度的 Stream,与 generate 方法不同的是,其是通过函数 f 迭代对给指定的元素种子而产生无限连续有序 Stream。

Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);

empty

empty方法返回一个空的顺序 Stream,该 Stream 里面不包含元素项。

Stream.empty();

Collection 接口和数组的默认方法

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).collect(Collectors.toList());

在 Arrays 类,封装了一些列的 Stream 方法,不仅针对于任何类型的元素采用了泛型,更对于基本类型作了相应的封装,以便提升 Stream 的处理效率。

int id[] = new int[]{1, 2, 3, 4};
Arrays.stream(id).forEach(System.out::println);

流的常见中间操作(Intermediate)

concat

1.concat 方法将两个 Stream 连接在一起,合成一个 Stream。
2.若两个输入的 Stream 都是排序的,则新 Stream 也是排序的。
3.若输入的 Stream 中任何一个是并行的,则新的 Stream 也是并行的。
4.若关闭新的 Stream 时,原两个输入的 Stream 都将执行关闭处理

Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5)).forEach(System.out::println);

distinct

distinct 方法以达到去除掉原 Stream 中重复的元素,生成的新 Stream 中没有没有重复的元素。

Stream.of(1, 2, 3, 1, 2, 3).distinct().forEach(System.out::println);

filter

filter 方法用于通过设置的条件过滤出元素。

// 获取空字符串的数量
Stream.of("1", "2", "3", "4", "", "", "7", "", "").filter(string -> string.isEmpty()).count();

map

map 方法用于映射每个元素到对应的结果。

// 获取对应的平方数
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).map(i -> i * i).collect(Collectors.toList());

flatMap

flatMap 方法与 map 方法类似,都是将原 Stream 中的每一个元素通过转换函数转换,不同的是,该换转函数的对象是一个 Stream,也不会再创建一个新的 Stream,而是将原 Stream的元素取代为转换的 Stream。
原来是多个,会打平为一个,而map是原来是多和,返回的还是多个

Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).flatMap(i -> i * i).collect(Collectors.toList());

peek

peek 方法生成一个包含原 Stream 的所有元素的新 Stream,同时会提供一个消费函数(Consumer实例),新 Stream 每个元素被消费的时候都会执行给定的消费函数,并且消费函数优先执行。

Stream.of(1, 2, 3).peek(x -> System.out.print(x));

skip

skip 方法将过滤掉原 Stream 中的前 N 个元素,返回剩下的元素所组成的新 Stream。

Stream.of(1, 2, 3,4,5) .skip(2) .forEach(System.out::println); 

sorted

sorted 方法将对原 Stream 进行排序,返回一个有序列的新 Stream。

Stream.of(5, 4, 3, 2, 1).sorted().forEach(System.out::println);

流的常见最终操作

collect

通过 collect 收集器,应用 Collector 工具。

转换成其他集合
toList

List<Integer> collectList = Stream.of(1, 2, 3, 4).collect(Collectors.toList());

toSet

Set<Integer> collectSet = Stream.of(1, 2, 3, 4).collect(Collectors.toSet());

toCollection
其接受的函数参数必须继承于 Collection。

TreeSet<Integer> collectSet = Stream.of(1, 2, 3, 4).collect(Collectors.toCollection(TreeSet::new));

toMap
备注:若 Stream 中重复值,导致 Map 中 key 重复,在运行时会报异常
java.lang.IllegalStateException: Duplicate key

public Map<Long, String> getIdNameMap(List<Account> accounts) {
    return accounts.stream().collect(Collectors.toMap(Account::getId, Account::getUsername));
}

其它

方法 说明
averagingDouble 求平均值,Stream 的元素类型为 double
averagingInt 求平均值,Stream 的元素类型为 int
averagingLong 求平均值,Stream 的元素类型为 long
counting Stream 的元素个数
maxBy 在指定条件下的,Stream 的最大元素。
minBy 在指定条件下的,Stream 的最小元素。
reducing reduce 操作,操作可以实现从 Stream 中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。
summarizingDouble 统计 Stream 的数据(double)状态,其中包括 count,min,max,sum 和平均。
summarizingInt 统计 Stream 的数据(int)状态,其中包括 count,min,max,sum 和平均。、
summarizingLong 统计 Stream 的数据(long)状态,其中包括 count,min,max,sum 和平均。、
summingDouble 求和,Stream 的元素类型为 double
summingInt 求和,Stream 的元素类型为 int
summingLong 求和,Stream 的元素类型为 long
max 最大值
min 最小值

对结果的分组与限制

groupingBy

Map<Boolean, List<Integer>> collectGroup= Stream.of(1, 2, 3, 4).collect(Collectors.groupingBy(it -> it > 3));

limit

Stream.of(1, 2, 3,4,5).limit(2).forEach(System.out::println);

Optional

Optional 类的引入很好的解决空指针异常。

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

推荐阅读更多精彩内容