Java -- Lambda表达式;函数式接口
Posted MinggeQingchun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java -- Lambda表达式;函数式接口相关的知识,希望对你有一定的参考价值。
一、Lambda表达式
Lambda 表达式,也可称为闭包,它是Java 8 发布的最重要新特性
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)
lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包(Closure)
(一)语法
(parameters) -> expression
或
(parameters) -> statements;
Lambda表达式由三部分组成
1、paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明,也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号
2、->:可理解为“被用于”的意思
3、方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不返回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回
// 1、不需要参数,返回值为 2
() -> 2
// 2、接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3、接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4、接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5、接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
Lambda语法特点
- 类型声明可省略:参数的类型可省略,编译器可自动识别
- 参数圆括号可省略:一个参数可以省略圆括号,无参或多个参数需要圆括号
- 大括号可省略:如果主体部分只是一个语句,可以省略大括号
- 返回关键字可省略:如果主体只有一个表达式返回值,则可以省略返回关键字编译器会自动返回,如果多条语句则不能省略
(二)Lambda表达式使用
Lambda表达式中我们只需要关心:参数列表 方法体
Lambda从普通接口实现类至Lambda表达式生成过程
public class LambdaTest
public static void main(String[] args)
Like like = new LikeImpl();
like.like();
like = new LikeImpl2();
like.like();
//4、局部内部类
class LikeImpl3 implements Like
@Override
public void like()
System.out.println("I like3");
like = new LikeImpl3();
like.like();
//5、匿名内部类
like = new Like()
@Override
public void like()
System.out.println("I like4");
;
like.like();
//6、Lambda表达式
like = () ->
System.out.println("I like5");
;
like.like();
//3、静态内部类
static class LikeImpl2 implements Like
@Override
public void like()
System.out.println("I like2");
//1、定义一个接口(有且只有一个抽象方法;接口中抽象方法的public abstract可以省略)
interface Like
// 有且只有一个抽象方法(接口中抽象方法的public abstract可以省略)
void like();
//2、接口实现类
class LikeImpl implements Like
@Override
public void like()
System.out.println("I like");
Lambda简化过程
/**
* Lambda表达式只能有一行代码情况下才能简化为一行
* 多个参数也可去掉参数类型,但是要去都去,要加都加
*/
public class LambdaTest2
public static void main(String[] args)
Love like = null;
// Lambda表达式
like = (int a) ->
System.out.println("I like " + a);
;
like.like(520);
//1、去掉参数类型
like = (a) ->
System.out.println("I like " + a);
;
like.like(521);
//2、去掉参数类型括号
like = a ->
System.out.println("I like " + a);
;
like.like(522);
//3、去掉方法体花括号
like = a -> System.out.println("I like " + a);
like.like(522);
// 定义一个接口(有且只有一个抽象方法;接口中抽象方法的public abstract可以省略)
interface Love
// 有且只有一个抽象方法(接口中抽象方法的public abstract可以省略)
void like(int a);
Lambda表达式的语法还可以精简
1、参数类型可以省略,如果需要省略,每个参数的类型都要省略
2、参数的小括号里面只有一个参数,那么小括号可以省略
3、如果方法体当中只有一句代码,那么大括号可以省略
4、如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字
1、List和foreach、sort
public static void main(String[] args)
ArrayList<String> list = new ArrayList<>();
//List的foreach
list.add("hello");
list.add("lambda");
list.forEach(new Consumer<String>()
@Override
public void accept(String s)
System.out.println(s);
);
System.out.println("----------");
//Lambda方法
list.forEach(a-> System.out.println(a));
//List的sort 方法
list.sort(new Comparator<String>()
@Override
public int compare(String o1, String o2)
return o1.compareTo(o2);
);
System.out.println(list);
System.out.println("----------");
//Lambda方法
list.sort((o1,o2)->o2.compareTo(o1));
System.out.println(list);
源码如下:
@FunctionalInterface
public interface Consumer<T>
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
......
@Override
public void forEach(Consumer<? super E> action)
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++)
action.accept(elementData[i]);
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
2、HashMap和forEach
public static void main(String[] args)
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "hello");
map.put(2, "lambda");
map.forEach(new BiConsumer<Integer, String>()
@Override
public void accept(Integer k, String v)
System.out.println(k + "=" + v);
);
//Lambda方法
map.forEach((k,v)-> System.out.println("key = "+k+" ,value = "+v));
源码如下:
@FunctionalInterface
public interface BiConsumer<T, U>
/**
* Performs this operation on the given arguments.
*
* @param t the first input argument
* @param u the second input argument
*/
void accept(T t, U u);
......
@Override
public void forEach(BiConsumer<? super K, ? super V> action)
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null)
int mc = modCount;
for (int i = 0; i < tab.length; ++i)
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key, e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
二、函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口
使用 @FunctionalInterface 注解
函数式接口可以被隐式转换为 lambda 表达式,如创建线程 实现的 Runnable 接口
@FunctionalInterface
public interface Runnable
public abstract void run();
如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。因此,只要保证接口中只有一个抽象方法,可以不加这个注解。加上就会自动进行检测
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中主要有4个常用函数式接口,都在 java.util.function包下
Function,Predicate,Consumer,Supplier
1、Function
传入参数T,返回类型R
@FunctionalInterface
public interface Function<T, R>
R apply(T t);
/**
* Function 函数型接口, 有一个输入参数 T ,有一个输出 R
* 只要是 函数型接口 可以 用 lambda表达式简化
*/
public class FunctionTest
public static void main(String[] args)
Function<String ,String> function = new Function<String, String>()
@Override
public String apply(String s)
return s;
;
System.out.println(function.apply("abc"));
2、Predicate
@FunctionalInterface
public interface Predicate<T>
boolean test(T t);
/**
* 断定型接口:有一个输入参数,返回值只能是 布尔值!
*/
public class PredicateTest
public static void main(String[] args)
Predicate<String> predicate = new Predicate<String>()
@Override
public boolean test(String s)
System.out.println(s);
return true;
;
System.out.println(predicate.test("abc"));
3、Consumer
@FunctionalInterface
public interface Consumer<T>
void accept(T t);
/**
* Consumer 消费型接口: 只有输入,没有返回值
*/
public class ConsumerTest
public static void main(String[] args)
Consumer<String> consumer = new Consumer<String>()
@Override
public void accept(String s)
System.out.println(s);
;
consumer.accept("abc");
4、Supplier
@FunctionalInterface
public interface Supplier<T>
/**
* Gets a result.
*
* @return a result
*/
T get();
/**
* Supplier 供给型接口 没有参数,只有返回值
*/
public class SupplierTest
public static void main(String[] args)
Supplier<String> supplier = new Supplier<String>()
@Override
public String get()
return "abc";
;
System.out.println(supplier.get());
以上是关于Java -- Lambda表达式;函数式接口的主要内容,如果未能解决你的问题,请参考以下文章
Java学习笔记3.9.2 Lambda表达式 - 函数式接口
Java8学习笔记 - 在哪里可以使用Lambda表达式 + 什么是函数式接口