java8新特性学习

内容:

1. lambda表达式

2. streamAPI

3. 内置函数接口

4. 接口默认实现方法

5. android中使用lambda/streamAPI

=======

1.lambda表达式:

几种形式:

()->statement
()->(statement)
()->{statement}

以Thread为例:

new Thread(new Runnable(){
   public void run(){
    }
}).start();
new Thread(()->{
     System.out.println(Thread.currentThread().getName());
}).start();

再比如:

Collections.sort(list, (x, y) -> y - x);

lambda表达式简化了匿名内部类的写法.它要求匿名内部类中只有一个抽象方法,这其实也称为函数接口。如果该抽象方法有多个参数,可以这样写:

(arg1,arg2)->{
}
(int arg1,double arg2)->{
}

两种写法都是可以的。

lambda的范围与匿名内部类类似,可以访问外部区域的局部final变量,以及成员变量和静态变量。

@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
final int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
stringConverter.convert(2);     // 3
//但是与匿名对象不同的是,变量num并不需要一定是final。
int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
stringConverter.convert(2);     // 3
//num在编译的时候被隐式地当做final变量来处理,下面的写法是错误的
int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
num = 3;

2.函数接口:

函数式接口是只包含一个抽象方法的接口。对于函数式接口,除了可以使用Java中标准的方法来创建实现对象之外,还可以使用lambda表达式来创建实现对象。这可以在很大程度上简化代码的实现。在使用lambda表达式时,只需要提供形式参数和方法体。由于函数式接口只有一个抽象方法,所以通过lambda表达式声明的方法体就肯定是这个唯一的抽象方法的实现,而且形式参数的类型可以根据方法的类型声明进行自动推断。

3.内置函数接口:

Java 8 API 还提供了很多新的函数式接口,来降低程序员的工作负担。

Predicates

Predicate是一个布尔类型的函数,该函数只有一个输入参数。Predicate接口包含了多种默认方法,用于处理复杂的逻辑动词(and, or,negate)

private static void testPredicate(List<String> list,Predicate<String> p){
        list.stream().filter(p).forEach(arg->{
            System.out.println(arg);
        });
    }

//client调用
List<String> l = Arrays.asList("aaa","hhaha","hiahia","hehe");
testPredicate(l,(arg)->arg.length()==3);

testPredicate方法的功能是在list集合中通过predicate指定的规则过滤元素,最后把过滤通过的元素打印出来。过滤条件的实现当然可以通过lambda表达式:(arg)->arg.length==3,意为过滤条件是元素的size为3。当然,Predicate可以允许有多个条件:

Predicate<String> p1 = (arg)->arg.charAt(0)==‘h‘;
    Predicate<String> p2 = (arg)->arg.length()<6;
    testPredicate(l,p1.and(p2));

原理可以参考Predicate源码:

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
    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);
    }
    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);
    }
}

可见,Predicate其实是一个函数接口。negate/and/or都是它的默认方法。

Functions

Function接口接收一个参数,并返回单一的结果。默认方法可以将多个函数串在一起(compse, andThen)

String s = "abcdefg";
Function<String,String> f = arg->arg.substring(3);
System.out.println(f.apply(s));//defg

再比如:

String s = "abcdefg";
Function<String,String> f = arg->arg.substring(3);
Function<String,Integer> f2 = f.andThen(arg->(arg.length()));
System.out.println(f2.apply(s));//输出4

先计算f,返回arg.substring(3),然后对返回的String执行arg.length(),所以结果应该是4.

参考源码:

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    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;
    }
}

Supplier:

Supplier接口产生一个给定类型的结果。与Function不同的是,Supplier没有输入参数。

比如构造对象:

Supplier<Person> s = ()->new Person();
s.get().sayHello();
static class Person{
        public void sayHello(){
            System.out.println("hello");
        }

}

参考源码:

@FunctionalInterface
public interface Supplier<T> {
    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

Consumers:

Consumer代表了在一个输入参数上需要进行的操作。

比如:

private static void testConsumer(List<Integer> l,Consumer<Integer> consumer){
        l.stream().forEach(i->{
            consumer.accept(i);
        });
    }
testConsumer(Arrays.asList(1222,12,9),i->{System.out.println("hello:"+i);});

BiConsumer:

跟Consumer类似,不过接受两个参数,常见的场景是Map的遍历。

Map的foreach遍历:

Map<String,String> map = new HashMap<>();

map.put("aa", "value1");
map.put("bb", "value2");
map.put("cc", "value3");

map.forEach((arg1,arg2)->{
    System.out.println(arg1+","+arg2);
});

4.Stream API:

java.util.Stream表示了某一种元素的序列,在这些元素上可以进行各种操作。Stream操作可以是中间操作,也可以是完结操作。完结操作会返回一个某种类型的值,而中间操作会返回流对象本身,并且你可以通过多次调用同一个流操作方法来将操作结果串起来。Stream是在一个源的基础上创建出来的,例如java.util.Collection中的list或者set(map不能作为Stream的源)。Stream操作往往可以通过顺序或者并行两种方式来执行。

常见的操作filter/sorted/map/match/count/reduce/

比如现在创建一个集合:

List<String> l = Arrays.asList("aaa","hhaha","hiahia","hehe");

filter:过滤特定的元素(返回stream)

Object[] l1 = l.stream().filter(arg->{
    return arg.length()>3;
}).toArray();

for(int i = 0; i<l1.length; i++){
    System.out.println(l1[i]);
}

map:对每个元素执行某种操作:(返回stream)

Object[] l2 = l.stream().map(arg1->arg1.toUpperCase()).toArray();

for(int i = 0; i<l2.length; i++){
    System.out.println(l2[i]);
}

sorted:排序(返回stream)

l.stream().sorted().forEach(arg->System.out.println(arg));

Match:匹配某种条件,有anyMatch/allMatch/noneMatch ( 返回boolean)

boolean result = l.stream().anyMatch(arg->arg.startsWith("a"));
System.out.println(result);

Parallel Streams

像上面所说的,流操作可以是顺序的,也可以是并行的。顺序操作通过单线程执行,而并行操作则通过多线程执行。

l.parallelStream().filter(arg->arg.startsWith("h")).map(arg->arg.toUpperCase()).forEach(arg->{
            System.out.println(arg);
        });

使用上跟stream()一样,但是效率更高.

5.接口的默认实现:

java8允许接口中有默认的实现方法,方法需加default声明:

@FunctionalInterface
public interface FooInterface {

    public default void funcA(){
        System.out.println("hello java8");
    }

    public int evaluate();

}

@FunctionalInterface注解代表当前接口是一个函数接口,也就是说里面必须只有一个抽象方法,如果出现多个则会报错,当然,默认方法不算。

注:

java8的接口和抽象类的区别:

1.抽象类注重继承,是为了继承而生。

2.抽象类可以有构造器、成员属性,接口不能有构造器,成员都是静态变量,隶属于类。

3.java8接口的默认方法主要作用是兼容低版本。因为当一个接口定义后之后,如果后期想增加一个方法的话,会导致之前的实现类无法使用,必须也实现新方法。默认方法的出现可以解决这一问题,只需增加一个默认方法,之前的实现类不会报错,而且新实现的类可以复写默认方法也可以不复写。

参考:

http://stackoverflow.com/questions/19998454/interface-with-default-methods-vs-abstract-class-in-java-8

想在android里面使用?

方案:

retrolambda+Lightweight-Stream-API

地址:

https://github.com/evant/gradle-retrolambda

https://github.com/aNNiMON/Lightweight-Stream-API

根目录下gradle文件中增加:

 dependencies {
        classpath ‘com.android.tools.build:gradle:1.3.0‘
        classpath ‘me.tatarka:gradle-retrolambda:3.2.3‘

    }

module目录下gradle文件中增加:

apply plugin: ‘me.tatarka.retrolambda‘
dependencies {
  ...
  compile ‘com.annimon:stream:1.0.3‘
  ...
}

另需在gradle中增加编译选项:

android{
compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }
} 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-29 07:29:18

java8新特性学习的相关文章

Java8新特性学习笔记(一) Lambda表达式

没有用Lambda表达式的写法:  Comparator<Transaction> byYear = new Comparator<Transaction>() {             @Override            public int compare(Transaction o1, Transaction o2) {                return o1.getValue().compareTo(o2.getValue());             

Java精品高级课,架构课,java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,第三方支付,web安全,视频教程

36套精品Java架构师,高并发,高性能,高可用,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,P2P金融项目,大型分布式电商实战视频教程 视频课程包含: 高级Java架构师包含:Spring boot.Spring  cloud.Dubbo.Elasticsearch,Redis.ActiveMQ.Nginx.Mycat.Spring.MongoDB.ZeroMQ.Git.Nosql.Jvm.Mecached.Netty.Nio.Mina.java8新特性,P2P金融项目,程序设计,

Java8新特性浅析

欢迎阅读我编写的Java 8介绍.本教程将带领你一步一步地认识这门语言的新特性.通过简单明了的代码示例,你将会学习到如何使用默认接口方法,Lambda表达式,方法引用和重复注解.看完这篇教程后,你还将对最新推出的API有一定的了解,例如:流控制,函数式接口,map扩展和新的时间日期API等等. 允许在接口中有默认方法实现 Java 8 允许我们使用default关键字,为接口声明添加非抽象的方法实现.这个特性又被称为扩展方法.下面是我们的第一个例子: 1 2 3 4 5 6 7 interfac

36套精品Java高级课,架构课,java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,第三方支付,web安全,高并发,高性能,高可用,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,大型分布式电商项目实战视频教程

新年伊始,学习要趁早,点滴记录,学习就是进步! QQ:1225462853 视频课程包含: 36套Java精品高级课架构课包含:java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,架构设计,web安全,高并发,高性能,高可用,高可扩展,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,工作流,程序调优,负载均衡,Solr集群与应用,主从复制,中间件,全文检索,Spring boot,Spring cloud,Dubbo,Elasticsearch,Redis,ActiveMQ

java8新特性,P2P金融项目,程序设计,功能设计,架构师视频教程

36套精品Java精品高级课,架构课,java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,第三方支付,web安全,高并发,高性能,高可用,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,大型分布式电商项目实战视频教程 视频课程包含: 36套Java精品高级课架构课包含:java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,架构设计,web安全,高并发,高性能,高可用,高可扩展,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,工作流,程序调优,负载均衡,S

java8新特性——Lambda表达式

上文中简单介绍了一下java8得一些新特性,与优点,也是为本次学习java8新特性制定一个学习的方向,后面几篇会根据上文中得新特性一一展开学习.本文就从java8新特性中比较重要的Lambda表达式开始学学习. 一.为什么要使用Lambda表达式 Lambda是一个匿名函数,我们可以baLambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递).可以写出更简洁,更灵活的代码.作为一种更紧凑得代码风格,使得java得语言表达能力得到提升.Lambda表达式需要函数式接口的支持,接口中

java8 新特性精心整理

前言 越来越多的项目已经使用 Java 8 了,毫无疑问,Java 8 是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和 JVM 等方面的十多个新特性.在本文中我们将学习这些新特性,并用实际的例子说明在什么场景下适合使用. 引用:本文参考了这两篇文章,加以自己的理解,整理成一份最容易理解的 Java8 新特性文章,有少部分章节可能内容一致,但绝对不是抄袭,只是为了文章的完整性,大部分常用的地方加了我自己的理解和示例. https://blog.

java8 新特性精心整理(全)

前言 越来越多的项目已经使用 Java 8 了,毫无疑问,Java 8 是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和 JVM 等方面的十多个新特性.在本文中我们将学习这些新特性,并用实际的例子说明在什么场景下适合使用. 引用:本文参考了这两篇文章,加以自己的理解,整理成一份最容易理解的 Java8 新特性文章,有少部分章节可能内容一致,但绝对不是抄袭,只是为了文章的完整性,大部分常用的地方加了我自己的理解和示例. https://blog.

JAVA8新特性——Lamda表达式

JAVA9都要出来了,JAVA8新特性都没搞清楚,是不是有点掉队哦~ Lamda表达式,读作λ表达式,它实质属于函数式编程的概念,要理解函数式编程的产生目的,就要先理解匿名内部类. 先来看看传统的匿名内部类调用方式: interface MyInterface{ void lMethod(); } public class Main { public static void test(MyInterface myInterface){ myInterface.lMethod(); } publi