菜单

Java:lambda表达式

2018年11月15日 - jQuery

中心概念:

大概明了:lambda表达式相当给创造的一个匿名对象.
每个lambda表达式都同一个一定的Java接口相关联,同时这个函数式接口只能分包一个泛方法声明。可以在接口及补偿加@FunctionalInterface注解注明是接口也lambda表达式相关接口。
例如:
声明一个函数式接口Converter:

@FunctionalInterface
public interface Converter<F, T> {

    T convertor(F from);

//    T convertor2(F from);

}

通过lambda表达式生成一个Converter类型的对象:

        Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
        Integer converted = converter.convertor("8");
        System.out.println(converted);

本文内容:

 

首发日期:2018-07-27

 


Java8许通过 :: 关键字传递方式要构造函数的援。

lambda表达式的牵线

 


传送静态方法

例如:

        Converter<String, Integer> staticFunConverter = Integer::valueOf;
        Integer staticFunConverted = staticFunConverter.convertor("123");
        System.out.println(converted);   // 123

lambda表达式的语法:

 

传递对象方法

例如:
新建一个类Something

 static class Something {
        String startsWith(String s) {
            return String.valueOf(s.charAt(0));
        }
    }

由此:: 关键字引用Something类型对象的计:

    Something something = new Something();
        Converter<String, String> objFunConverter = something::startsWith;
        String objFunConverted = objFunConverter.convertor("Java");
        System.out.println(objFunConverted);//J

语法:

(形参列表)
->{代码块}图片 1

(形参列表) ->表达式   
图片 4

 

 

传递构造方法

事先定义一个几近构造函数的bean

    static class Person {
        String firstName;
        String lastName;

        Person() {
        }

        Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

下一场定义一个足以创造person 的personFacotory接口

public interface PersonFactory<P extends FuncTest.Person> {

    P create(String firstName, String lastName);

}

由此构造函数引用,实现工厂接口。

PersonFactory<Person> personFactory = Person::new;
        Person person = personFactory.create("pee", "hao");
        System.out.println(person.lastName);//hao

方的例子中经过Person::new创建一个Person类构造函数的援,Java编译器会冲PersonFactory.create方法的签字活动选择适当的构造函数。

lambda表达式与函数式接口:

lambda表达式的目标项目必须是函数式接口。lambda通常用来促成函数式接口。

啊是函数式接口?

1.凡一个接口

2.只来一个空洞函数

3.足以生默认函数(如toString等默认函数,大部分是Object中的同名函数)【这里叫一个为何接口会发生接近继承自Object的函数的原故:https://blog.csdn.net/xidiancoder/article/details/78011148】

图片 6

 

 

lambda表达式访问变量范围

lambda表达式访问变量范围与匿名内部类相同。

表达式的变量的作用域问题:

 

 


而看当地final局部变量。

final int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

lambda表达式实现函数式接口

 

深信不疑看了点的始末,你曾了解函数式接口了。下面介绍如果下lambda表达式实现函数式接口。

 

图片 10

一般说来的落实方式发生好多,可以创建一个实名类来促成接口,也可行使匿名类来实现:

1.创立一个实名类来贯彻接口

图片 11

2.运匿名类来落实

图片 12

 

脚用lambda来促成,你见面发现lambda确实能节省成千上万行代码。

图片 13

 

 

图片 14—lambda实现->图片 15

 

方已经演示了:有参数的,没参数的,表达式的,代码块的。下面介绍任何一个留心点。

 

lambda表达式可以说凡是“任意档次”的,转换成什么在“需要什么”。

若是上面的,左边是一个接口,那么右边需要一个接口的贯彻类似的靶子,于是lambda会见错过落实之接口的肤浅函数,并创一个目标回来。

而外,还足以放在函数中作形参,比如:

图片 16以此近乎的函数需要一个接口作为形参。当我们调用函数时,可以流传一个lambda表达式:

图片 17

 

 


而是看成员变量和静态变量。

lambda表达式与Java于带的函数式接口的相当下

 

Java有那么些自带的函数式接口,下面仅因一个吗例。

 

Comparator是Java中用来排序的一个接口,里面有一个compare函数。

很多能传入一个排序对象的函数,通常都是传入一个Comparator的实现类。

比如Arrays中的排序函数就可传一个Comparator的实现类。图片 18

 

 

 

在不用lambda时,可以有:

图片 19

 

使lambda表达式之后:

图片 20

 

假设你所表现,减少了累累代码。所以要是用传入的靶子是一个函数式接口时,不妨考虑采用lambd表达式,这会省掉成千上万代码。


lambda表达式不可知访问默认接口方法。

富含扩展方法的接口

public interface Formula {

    double calculate(int a);

    //JAVA8中可以通过default关键字在接口中添加一个非抽象方法(即:扩展方法)
    default double sqrt(int a) {
        return Math.sqrt(a);
    }

}

Formula formula = new Formula() {
    @Override
    public double calculate(int a) {
        return sqrt(a);
    }
};
System.out.println(formula.calculate(9));
System.out.println(formula.sqrt(9));

Formula formula1 = Math::sqrt;//此处无法通过直接调用扩展方法sqrt实现。

Java8置的函数式接口

早已是的Comparator接口和Runnable接口。

Predicates(断言)

Predicates是含有一个参数返回值为boolean型的函数,为了满足复杂的逻辑条件(or
and negate)Predicates接口包含各种默认方法。

 //Predicates(断言)
        Predicate<String> predicate = (s -> s.length() > 0);
        System.out.println(predicate.test("foo"));//true
        System.out.println(predicate.negate().test("foo"));//false

Functions

Functions接口接收一个参数并转一个结出,可以采取Functions接口的默认方法(compose,
andThen)将多单functions串联起来。
横流:compose,
andThen的分,compose方法本身先实行,再将实践结果传递给调用者执行。andThen先实行前同一步之调用者,获取前一样步执行结果后更实行。

//Functions
        Function<Integer, Integer> time2 = e -> e * 2;
        Function<Integer, Integer> squared = e -> e * e;

        System.out.println(time2.compose(squared).apply(4));//32
        System.out.println(time2.andThen(squared).apply(4));//64

Consumers

Consumers接口表示在么输入参数达到而履行的操作。

//Consumers
        Consumer<FuncTest.Person> greeter = person -> System.out.println("hello :" + person.firstName);
        greeter.accept(new FuncTest.Person("jiahong", "hao"));//hello:jiahong

Comparators

Optionals

Optionals不是一个函数式接口,而是一个之所以来防止出现NullPointerException异常的老好工具。

Streams

java.util.Stream代表可以实行一个要么多个操作的班元素,stream的操作可以分成两栽类型:中间操作还是最后操作。中间操作的返回值还是一个stream,最终操作的返回值是一个规定的型。可以由此链式调用可以用大半只中等操作串联起来。stream上的操作既可以串行执行也得是并行执行。

List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
Filter

Filter通过断言来针对stream中所有的要素进行判定,由于filter是一个中档操作,因此我们可以以filter后面再调用forEach操作,ForEach操作接收一个consumer接口作为参数,这个consumer会在有通过filter的元素上实施。ForEach是一个终极操作,返回值类型是void,因此我们不克于ForEach后面又调用其他操作。(最终操作是回去执行的操作。这里的forEach相当给for(…)循环了)

        stringCollection
                .stream()   
                .filter(s -> s.startsWith("a"))
                .forEach(System.out::println);
        //aaa2 aaa1
Sorted

Sorted是一个中等操作,sorted操作接收Comparator接口作为参数,返回一个不变的stream。如果传递一个空函数给sorted,会按部就班自顺序进行排序,如果元素不支持排序,会在最后操作时抛来十分。

stringCollection
    .stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);

// aaa1 aaa2
Map

map是一个中级操作,通过加的转换方法map能将stream中之每个元素映射为另外一栽对象,下面的例证中将每个string转换为upper-cased
string。map也支撑不同种类的炫耀,具体投的靶子项目取决于映射方法的归值类型。

stringCollection
    .stream()
    .map(String::toUpperCase)
    .sorted((a, b) -> b.compareTo(a))
    .forEach(System.out::println);

// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
Match

matching是一个最终操作,返回值类型为boolean型,可以就此来确定某种断言是否和stream匹配。

boolean anyStartsWithA =
    stringCollection
        .stream()
        .anyMatch((s) -> s.startsWith("a"));

System.out.println(anyStartsWithA);      // true

boolean allStartsWithA =
    stringCollection
        .stream()
        .allMatch((s) -> s.startsWith("a"));

System.out.println(allStartsWithA);      // false

boolean noneStartsWithZ =
    stringCollection
        .stream()
        .noneMatch((s) -> s.startsWith("z"));

System.out.println(noneStartsWithZ);      // true
Count

Count是一个末尾操作,返回stream中元素的个数,返回值类型为long。

long startsWithB =
    stringCollection
        .stream()
        .filter((s) -> s.startsWith("b"))
        .count();

System.out.println(startsWithB);    // 3
Reduce

Reduce是一个最后操作,通过加的方式在stream上执行reduce操作,返回值为使用Optional接口包装的reduce值。(Reduce含义:把…归纳为,减少)

Optional<String> reduced =
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);

reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"

Parallel Streams

Parallel
Streams能当差不多个线程上并发地执行,下面的例证中经简单的采取parallel
streams就能极大地提高系统特性。
先是我们创建一个死十分之要素唯一的list.

int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
    UUID uuid = UUID.randomUUID();
    values.add(uuid.toString());
}

咱初步测试在此stream上实施排序所用的辰
Sequential Sort

long t0 = System.nanoTime();

long count = values.stream().sorted().count();
System.out.println(count);

long t1 = System.nanoTime();

long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));

// sequential sort took: 899 ms

Parallel Sort

long t0 = System.nanoTime();

long count = values.parallelStream().sorted().count();
System.out.println(count);

long t1 = System.nanoTime();

long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("parallel sort took: %d ms", millis));

// parallel sort took: 472 ms

点的蝇头段代码几乎一样,但是parallel sort的速几乎比sequential
Sort速度快50%。

Map

Map<Integer, String> map = new HashMap<>();
        for (int i = 0; i < 10; i++) {
                //当键值在map中不存在时,才会执行put操作.
            map.putIfAbsent(i, "val" + i);
        }

        map.forEach((key, value) -> System.out.println(value));

        map.computeIfPresent(3, (num, val) -> val + num + 1);
        System.out.println(map.get(3)); // val331 函数式接口返回值与原来的value不同,则赋予新值.

        map.computeIfPresent(9, (num, val) -> null);
        System.out.println(map.containsKey(9));//false 函数式接口返回值为null,则相应的mapping会被删除


        //当键值在map中不存在时,才会计算函数式接口的值,并设值.
        map.computeIfAbsent(23, num -> "val" + num);
        System.out.println(map.containsKey(23));
        System.out.println(map.get(23));

        map.computeIfAbsent(3, num -> null);
        System.out.println(map.get(3));//val331

        map.computeIfAbsent(3, num -> "bam");
        System.out.println(map.get(3));//val331

脚的事例展示了map如何去value不为空的key的操作。

map.remove(3, "val3");
map.get(3);             // val33

map.remove(3, "val33");
map.get(3);             // null
Another helpful method:

System.out.println(map.getOrDefault(42, "not found"));  // not found
System.out.println(map.get(42));//null

//Merging entries of a map is quite easy:
map.merge(9, "val9", (value, newValue) -> value.concat(newValue));
map.get(9);             // val9

map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
map.get(9);             // val9concat

merge方法在key不有时时,可以望map中补充加key/value,当key存在时时,可以针对之key对应的value执行merge操作。

todo:stream()方法吃的collect()需要总结下,涉及到了常事要因此到的list装换map

JAVA8 教程
Java8
lambda表达式10个示例
【译】Java
8的新特性—终极版(杜琪)
Java8初体验(二)Stream语法详解
Java8
新特点的流式数据处理

相关文章

标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图