package com.dudu.java8.read;
import lombok.Data;
import java.io.BufferedReader;
import java.io.IOException;
import java.sql.SQLOutput;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
/**
* @create: 20190324
* @author: liu
**/
public class Read3 {
/**
* Lambda 没有名称,有参数列表、函数主题、返回类型,可能还有一个可以抛出异常列表
* 匿名:没有明确的名称
* 函数:不属于某个特定的类,但和方法一样,有参数列表、函数主体、返回类型
* 传递;可以作为参数传递给方法或者存储在变量中
* <p>
* 参数 -> 主体
* Lambda 表达式组成:参数列表 箭头 lambda主体
* <p>
* (parameters) -> expression
* (parameters) -> {statements;}
* <p>
* 函数式接口就是只定义了一个抽象方法的接口
* 只要接口只定义了一个抽象方法,它就仍然是一个函数式接口, Runnable
* Lambda表达式允许你直接以内联的形式为函数接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例
* 也就是说,是函数式接口一个具体实现的实例
* <p>
* 函数描述符
* <p>
* 函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。
* 这种抽象方法叫做函数描述符
* <p>
* 抽象方法签名可以描述Lambda表达式的签名
* <p>
* Lambda表达式的签名要和函数式接口的抽象方法一样
*
* @FunctionalInterface 标注用于表示该接口会设计成一个函数式接口
* <p>
* <p>
* 环绕执行模式,开始阶段和结束阶段的代码类似,并且围绕着执行处理的那些重要代码
* <p>
* 1、行为参数化
* 2、使用函数式接口来传递行为
* 3、执行一个行为,
* lambda表达式允许你直接内联,为函数式接口的抽象方法提供实现,并且将整个表达式作为函数式接口的一个实例
* 4、传递Lambda
* <p>
* <p>
* 函数式接口定义且只定义了一个抽象方法
* 函数式接口的抽象方法的签名称为函数描述符
* @create: 2019-03-24
* @author: liu
**/
public static void main(String[] args) {
Runnable r = () -> System.out.println("Hello!");
r.run();
Runnable runnable = () -> {
System.out.println("hello");
};
/**
* 1、行为参数化
* 2、使用函数式接口来传递行为
* 3、执行一个行为 , 将整个表达式作为函数式接口的一个实例
* 4、传递Lambda
* @create: 2019-04-13
* @author: liu
**/
/**
* 常见的函数式接口
*
* Predicate<T> test方法 表示一个涉及类型T的布尔表达式时,就可以使用
*
* Consumer<T> void accept抽象方法,没有返回 , 只能绑定到引用类型
* 访问类型T的对象,并且执行某些操作,就可以使用这个接口 例如: foreach sout
*
* Function<T,R> apply 接收一个泛型T ,并返回一个泛型R
*
* 装箱后的值本质上就是把原始类型包裹起来,并保存在堆里,装箱后的值需要更多的内存
*
* 函数式接口带来一个专门的版本,以便在输入和输出都式原始类型避免自动类装箱的操作
* 一般来说,针对专门的输入参数类型的函数式接口的名称都要加上对应的原始类型前缀
*
* 任何函数式接口都不允许抛出受检异常
* 1、定义一个自己的函数式接口,并声明受检异常
* 2、把lambda放在一个try/catch中
*
*
* @create: 2019-03-25
* @author: liu
**/
List<Integer> integers = Arrays.asList(1, 2, 3);
integers.forEach(
(i) -> {
System.out.println(i * 10);
}
);
/**
* 类型检查
* lambda的类型式是使用上下文推断出来的
* 上下文中lambda表达式需要的类型称为目标类型
*
* 类型推断
* java编译器会从上下文推断出用什么函数式接口来配合lambda表达式
*
* 使用局部变量
* lambda允许使用自由变量,但局部变量必须显示声明为final
* 实例变量都存储在堆中,局部变量则保存在栈上
* 使用线程访问时,可能分配给该变量的线程将这个变量收回,
* java在自由局部变量时,实际上访问它的副本,而不是访问原始变量
*
*
* 闭包 closure
* 闭包就是一个函数的实例,可以无限制的访问那个函数的非本地变量
* 不能修改定义lambda的方法的局部变量的内容
*
*
* 方法引用
* 方法引用,可以让你重复使用现有的方法定义,像lambda一样传递他们
* 如果一个lambda代表的只是直接调用这个方法,最好还是用名称来调用它,而不是去描述如何调用它
* 方法引用就是让你根据已有的方法实现来创建lamdba表达式
* 目标引用放在分隔符::前,方法名在后,不需要使用括号,因为没有实际调用这个方法
*
* 方法引用只要有三类
* 1、指向静态方法的方法引用
* 2、指向任意类型实例方法的方法引用
* 3、指向现有对象的实例方法的方法引用
*
*
*
* @create: 2019-03-25
* @author: liu
**/
// 方法引用 不需要括号
integers.forEach(System.out::println);
List<Integer> integers1 = Arrays.asList(1, 24, 2);
// Apple a1 = Apple::new;
/**
* lambda 表达式引用的局部变量必须是 final,否则会报错
* 实例变量都存储在堆中,堆中的变量是在线程之间共享的
* 局部变量保存在栈上
* java访问自由局部变量时,实际上是在访问它的副本,而不是访问原始变量
*
* 闭包就是一个函数的实例,可以无限制地访问那个函数的非本地变量
*
*
* @create: 2019-04-13
* @author: liu
**/
/**
* 构造函数引用
* @create: 2019-04-13
* @author: liu
**/
Supplier<Apple> a = Apple::new;
Supplier<Apple> a1 = () -> new Apple();
Function<String, Apple> a3 = (name) -> new Apple(name);
Apple liu = a3.apply("liu");
System.out.println("liu ===");
System.out.println(liu);
}
}
@Data
class Apple {
Apple() {
}
private String name;
private int weights;
public Apple(String name) {
this.name = name;
}
}
/**
* 函数式接口
*
* @create: 2019-03-25
* @author: liu
**/
@FunctionalInterface
interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
package lambdaj;
/*
* lambda 允许使用简洁的代码来创建只有一个抽象方法的接口 这种接口也被称为函数式接口
* lambda表达式 也支持将代码块作为方法参数
*
* 形参列表
* 箭头 ->
* 代码块
* */
abstract class cd {
abstract void ddd();
}
interface ia {
void aaa(); // 只包含一个抽象方法的 接口
}
interface ib {
void bbb(String bString);
}
interface ic {
int ccc(int c, int cc);
}
public class one {
public static void main(String[] args) {
one o = new one();
// rr r1 = ()->{ //接口类型 变量 直接使用函数式编程 不晓得怎么使用
Object r1 = (rr) () -> { // 接口类型 变量 直接使用函数式编程 不晓得怎么使用
for (int i = 0; i < 11; i++) {
System.out.println(i);
}
};
System.out.println();
/*
* 三种常见的方式
*
* 将lambda 表达式赋值给函数式接口类型的变量 将lambda 表达式作为函数式接口类型的参数传给某个方法 使用函数式接口对lambda
* 表达式进行强制类型转换
*/
// 同样的lambda 表达式的目标类型完全可能是变化的 --唯一的要求是,lambda
// 表达式实现的匿名方法与目标类型(函数式接口)中唯一的抽象方法有相同的形参列表
/*
* java.util.function 中典型的4类接口 xxxfunction 这类接口中通常包含一个apply()抽象方法
* ,该方法对参数进行处理转换(apply()方法的处理逻辑由lambda表达式实现),然后返回一个新的值
* 该函数接口通常用于对指定的数据进行转换处理
*
* xxxConsumer 这类接口中通常包含一个apply()抽象方法 方法与上面的类中的 基本相似 但是不会返回处理结果
*
* xxxPredicate 包
* 含一个抽象的Test 抽象方法 该方法通常用来对参数进行某种判断(test
* 方法的判断逻辑由lambda表达式实现)返回一个boolean 通常用于判断是否满足特定条件 经常用于进行筛选数据
*
* xxxSupplier
* 这类接口中通常包换一个getAsXXX()抽象方法,该方法不需要参数,该方法会按照某种逻辑算法(有lambda表达式实现)返回一个数据
*
* 这种语法的出现避免了匿名内部类的繁琐
*
*/
System.out.println();
o.oa(() -> // 对象名.方法名 (参数...) -> { 代码块 }
{
System.out.println("这个是oa");
});
/*
* 函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法
*
* 该表达式创建出来的对象的目标类型就是这个函数式接口
*
* @FunctionInterface 注解
*/
o.oa(() -> System.out.println("这个是oa")); // 只有一条语句可以省略 {}
// o.oa(ia1);
// 不带形参的匿名方法
/*
* lambda 只有一条代码,还可以在代码块中使用方法引用和构造器引用 方法引用和构造器引用 都需要使用两个英文冒号::
*
*
* 方法引用与构造器引用
*
* 引用类方法 类名::类方法 函数式接口中被实现的方法的全部参数传给该类方法作为参数 例子 (a,b...)->
* 类名.类方法(a,b...)
*
*
* 引用特定对象的实例方法 特定对象::实例方法 函数式接口中被实现方法的全部参数传给该方法作为参数 例子 (a,b...)->
* 特定对象.实例方法(a,b...)
*
*
* 引用某类对象的实例方法 类名::实例方法 函数式接口中被实现方法的第一个参数做为调用者,后面的参数全部传给该方法作为参数 例子
* (a,b...)-> a.实例方法(a,b...)
*
* 引用构造器 类名::new 函数式接口中被实现方法的全部参数传给该构造作为参数 例子 (a,b...)-> new 类名(a,b...)
*
*/
o.ob(weather -> { // 只有一个形参的匿名方法
System.out.println("今天的天气是+++");
System.out.println("这个是ob");
});
o.oc((a, b) -> a + b); // 只有一条语句可以省略花括号
// 只有一条语句,即该语句的返回值,也可以省略return关键字
/*
* 调用方法需要一个 类型的参数,实际上传入的是lambda表达式 表达式可以被当做任意类型的对象
*/
// o.od(()-> // 对象名.方法名 (参数...) -> { 代码块 } //错误 好像抽象类不能用,待验证
// {
// System.out.println("这个是oa");
// });
}
public void oa(ia ia1) { // 传入接口类型的对象
System.out.println("输出接口ia-" + ia1);
ia1.aaa(); // 调用接口中的方法
}
public void ob(ib ib1) {
System.out.println("输出接口ib--" + ib1);
ib1.bbb("这个是接口ib的bbb方法");
}
public void oc(ic ic1) {
System.out.println("输出接口ic---" + ic1);
System.out.println("ic1的方法抽象方法ccc " + ic1.ccc(1, 2));
}
public void od(cd cd1) { // 该参数类型 必须为 只有一个抽象方法的接口
System.out.println("抽象类cd----" + cd1);
cd1.ddd();
}
}
interface rr {
void run();
}
------------------------------------------------------------------------------
package lambdaj;
public class MethodRefer1 {
public static void main(String[] args) {
MethodRefer1 methodRefer1 = new MethodRefer1();
// Integer val = con1.con("11");
// 引用类方法
conn conn1 = Integer::valueOf;
Integer integer = methodRefer1.conn1.connf("11");
//引用类方法 类名::方法名
//函数式接口中被实现的方法的全部参数传给该类方法作为参数
// 对应的表达式 类名.方法名
System.out.println(integer);
System.out.println("--------------------------------------------");
}
conn conn1 = s ->Integer.valueOf(s); // 对应的表达式
//引用特定对象的实例方法
conn conn2 = s ->"asdf".indexOf(s); //创建一个 conn 对象 省略了花括号 此句代码作为返回值
void pri(conn c) {
c.connf("1");
}
}
@FunctionalInterface
interface conn { // 将string转换成int
Integer connf (String s);
}
//只有一条语句,因此程序省略该代码的花括号
//lambda需要返回值,且 将这条代码作为返回值1
------------------------------------------------
package lambdaj;
import java.util.Arrays;
//lamdba 与匿名内部类的区别与联系
public class end {
public static void main(String[] args) {
endc endc1 = new endc();
endc1.test();
}
}
interface play{
void display();
default int add(int a ,int b )
{
return a + b;
}
}
class endc{
private int age = 12 ;
private static String name = "不会啊";
void test() {
String nString = "还是不会啊";
play p = ()->{ // 创建一个play 接口的对象
System.out.println( "test方法中的变量" + nString);
System.out.println("外部的非静态age" + age);
System.out.println("外部的静态 name" + name); // 先访问静态的变量
};
p.display();
System.out.println(p.add(2, 3)); //1 不仅可以调用接口中唯一的抽象方法,也可以调用接口中的默认方法
System.out.println("-----------------------");
String[] strings = new String[] {"java","hadop","hdfs","eclipse","liu"};
Arrays.parallelSort(strings,(a1,a2) -> a1.length() - a2.length()); // 表达式的类型是comparator 判断两个字符串的长度
System.out.println(Arrays.toString(strings));
int[] ints = new int[] {1,22,3,12,};
Arrays.parallelPrefix(ints, (left,right)->left * right); // lambda的表达式类型是 intbinaryOperator 前后两个元素计算当前元素的值
System.out.println(Arrays.toString(ints));
}
}
/*
*lambda 表达式 与匿名内部类存在的
*匿名内部类可以为文艺接口创建实例----不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可
*lambda 只能为函数式接口创建实例
*
*匿名内部类可以为抽象类甚至普通类创建实例
*lambda 只能为函数式接口创建实例
*
*匿名内部类 是先的抽象方法允许调用接口中定义的默认方法
*lambda 的代码块不允许直接调用接口中定义的默认方法,可以通过匿名内部类的方法调用
* */