添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
不开心的椰子  ·  elastic-builder ...·  2 月前    · 
安静的手套  ·  NULL 排序問題 - ORACLE / ...·  3 月前    · 
Java用一种特殊( 仅有 一个方法)的接口变量,作为lambda表达式的赋值对象/数据容器。
interface IMove{
	double move(double speed, int seconds);
	这种接口被称之为函数()/功能(接口@试一试@:接口中添加一个方法声明? 
	演示:F3到Comparator,以下方法不算作接口方法: 
default void stop() {}
static void stop() {}
重写Object中已有的方法
String toString();
函数式接口也可以被当做普通接口使用。
PS:@FunctionalInterface注释
lambda表达式表示函数式接口的实例:
IMove m = (s, t) -> s * t;
Java中lambda使用的是单横线箭头(->)
System.out.println(m.move(2.5, 60));    //实例调用其接口方法
演示:其他规则和JavaScript箭头函数一样 一般情况下,lambda类型可以由编译器推断。@想一想@:为什么可以推断? 什么是特殊情况呢? Lambda表达式最重要的作用就是作为函数参数传递。假设有两个重载的方法,
static void goSchool(IMove move) {
static void goSchool(IWalk walk) {
使用了类似的函数式接口:
interface IWalk {    //和IMove类似
	double move(float speed, long seconds);
演示:编译时错误 
goSchool((s,t)->s*t);
解决方案: 显式声明参数类型
//要声明参数类型,所有参数的类型就都要声明
goSchool((double s,int t)->s*t);
先声明Lambda变量类型
IMove m = (s, t) -> s * t;
goSchool(m);
通过强制类型转换声明lambda表达式类型:
goSchool((IMove)(s, t) -> s * t);
作用域和闭包:移到函数式编程
final修饰 Java允许在lambda参数前加final,以禁止lambda表达式内部修改该参数。 但如果这样,需要显式的声明参数类型:
IMove m = (final double s, int t) -> {
    s *= 2;    //error
    return s * t;
函数式接口可以是泛型的:
interface IMove<T> {
	T move(T speed, int seconds);
	PS:以上对应C#中delegate 
	Lambda表达式可以视为一种匿名函数。
	那如果我们需要传递一个已有的命名函数呢?比如把这个方法(注意是方法本身是方法运行结果)传递给IMove,IMove move = ??
static double walk(double speed, int seconds) {
	return speed * seconds;
这时候就需要操作符为双冒号(::)的方法引用了:
IMove move = Main::walk;    //静态方法由类名调用
System.out.println(move.move(23.5, 2));
除了静态方法以外,还有: 实例方法和属性
class Person  {
	public double walk(double speed, int seconds) {
IMove m = new Person()::walk;
m.move();
class Person  {
	public Person() {
interface IMove {
	Person getPerson();
IMove m = Person::new;
Person fg =  m.getPerson();
interface IMove {
    int[] get(int length);    //注意这个length参数
IMove m = int[]::new;
int[] students = m.get(10); //得到一个长度为10的数组
类::实例方法
interface IMove{
	void move(Person person);    //第一个参数是Person
class Person{
	public void walk() {    //这是一个实例方法
IMove m = Person::walk;    //但仍然可以用类名调用
//等价于:IMove m = p->p.walk();
m.move(new Person());
(一定要注意这个当)接口方法有参数时,可以用它的第一个(且只能是第一个)参数类型,后加双冒号(::)指定它的某一个匹配实例方法。(我个人不喜欢这种写法,宁愿用箭头,避免和静态方法混淆
System.out.println(greaterThan0.test(100));
另外三个default方法,套路和Consumer的andThen()一样。为了演示,添加一个:
Predicate<Integer> lessThan100 = i -> i < 100;
@想一想@:搞这么一个方法干嘛?直接用 == 不香么?
Predicate.<Integer>isEqual(32).or(greaterThan0).test(new Integer(22))
演示说明:and(Predicate<? super T> other)
Predicate<Student> greaterThan0 = i -> i.Age > 0;
Predicate<Person> lessThan100 = i -> i.Age < 100;
//假如这样可以允许的话
//Predicate<OnlineStudent> lessThan100 = i -> i.Fee < 100;
Student fg = new Student();
 * 1. 在test的时候,greaterThan0和lessThan100都使用的fg 
 * 2. 我们只能控制and()中的lambda泛型参数, 
 * 3. 确保其至少是Student类,这样predict中使用的都是Student有的类成员
greaterThan0.and(lessThan100).test(fg);
Function “标配的”apply()方法 两个default方法,在当前function 之后被调用:andThen(),以当前function的返回值为输入 之前被调用:compose(),运行结果作为以当前function的输入
Function<Person, Integer> getAge = p -> p.age;	
System.out.println(getAge
//指定i 类型方案1:	.compose((Integer i) -> new Person(i))
//指定i 类型方案2:	.<Integer>compose(i -> new Person(i))
	//还可以使用构造函数方法引用
	.<Integer>compose(Person::new)
	.andThen(a-> a*0.9)
	.apply(40));
演示:执行顺序 apply() -> compose() -> getAge -> andThen() 注意练习阅读其源代码。 还有更多的function(函数接口名),可以适用于更多的情形: 参数或返回值为基本类型的:
添加输入参数类型前缀,比如:DoubleConsumer、IntConsumer、LongPredicate…… 添加输出参数和返回类型前缀,比如:IntToDoubleFunction、DoubleUnaryOperator
作用:减少装箱拆箱,可以些许的提高性能
输入参数为2个的:
引用类型(泛型)添加bi前缀,比如:BiConsumer<T, U>、BiFunction<T, U, R>、BiPredicate<T, U>…… 基本类型添加To前缀,比如:ToDoubleBiFunction、ToIntBiFunction<T, U>……