GVKun编程网logo

Java lambda 表达式(javalambda表达式实现原理)

1

在本文中,我们将为您详细介绍Javalambda表达式的相关知识,并且为您解答关于javalambda表达式实现原理的疑问,此外,我们还会提供一些关于-source1.5中不支持lambda表达式(请

在本文中,我们将为您详细介绍Java lambda 表达式的相关知识,并且为您解答关于javalambda表达式实现原理的疑问,此外,我们还会提供一些关于-source 1.5 中不支持 lambda 表达式 (请使用 -source 8 或更高版本以启用 lambda 表达式)、5.8 java 11 增强的 Lambda 表达式、AWS CLI 表达式:错误的 jmespath 表达式:未知令牌、AWS Lambda EFS | EACCES:权限被拒绝 访问点请注意/lambda Lambda注释/mnt/lambda的有用信息。

本文目录一览:

Java lambda 表达式(javalambda表达式实现原理)

Java lambda 表达式(javalambda表达式实现原理)

lambda 表达式是一个匿名函数,通俗解释是:可以传递的、在以后执行一次或多次的代码块。Java8 中引入的特性。

lambda 表达式的语法

形式:(参数)-> 表达式

0. 若表达式复杂,可以用大括号括起。{语句块}

1. 没有参数的情况:仍然需要提供空括号。

()->{for (int i = 100;i >= 0;i--) System.out.println(i);}

2. 如果可以推导出参数类型:可以忽略参数类型。

Compertor<String> comp = (first,second) ->first.length()-scond.length();//参数类型必为字符串

3. 如果只有一个参数,可以推导出参数类型:可以省略小括号。

4. 无需指定 lambda 表达式的返回类型,自动由上下文推导得出。

函数式接口

对于只有一个抽象方法的接口,需要这种接口的对象时,可以提供一个 lambda 表达式。只有一个抽象方法的接口被称为函数式接口。

如 Array.sort 方法需要提供一个数组和比较器 (comparator)。比较器是实现了 Comparator 接口的实例对象。该接口只有一个方法。如普通实现:

class LengthComparater implements Comparator<String>{
    public int compare(String first,String second){
        return first.length() - second.length();
    }
}

这样,就可以创建一个 LengthComparater 类传入 Array.sort 函数中。

Array.sort(words,new LengthComparator())

而用 lambda 表达式:

Array.sort(words,(first,second)->first.length()-secong.length())

这样做,对 compare 方法的调用会执行这个 lambda 表达式的体,它把 lambda 看做一个函数。这样做法效率要高;代码可读性也要好一些。

方法引用

使用双冒号(::)分隔方法和对象名来表示一个方法引用,与 lambda 表达式效果相同。有 3 种写法:

object::instanceMethod (x,x,x...)   等价于 (x,x,x...)->object.instanceMethod (x,x,x...)

Class::staticMethod (x,x,x,....)          等价于 (x,x,x...)->object.staticMethod (x,x,x...)

Class::instanceMethod (x,y,z...)      等价于 (x)->x.instanceMethod (y,z.....)  // 第一个参数会成为方法的目标

可以在方法引用中使用 this 和 super 参数

构造器引用

与方法引用类似,方法名为 new。例如 Person::new 是 Person 构造器的一个引用。

变量作用域

lambda 表达式可以捕获外围作用域中变量的值,但却有些限制。

规则:lambda 表达式中捕获的变量必须实际上是最终变量。

一个例子:

public static void repeat(String text, int count){
        for (int i = 1;i <= count; i++){
            ActionListener ls = event ->{
                System.out.println(i + " " + text);
            };
            new Timer(10000,ls).start();
        }
    }

如上,对于 text 的打印是合法的,对 i 的打印却是非法的。text 总是指向同一个对象;而 i 的值却会改变。

规则:lambda 表达式的体与嵌套块有相同的作用域。

一个例子:

Path first = Paths.get("usr/bin");
    Comparator<String> comb = (first,second) -> first.length()-second.length();

以上是非法的。方法中不能有两个同名的局部变量。所以以上 lambda 表达式不能使用 first 变量名作为参数。

处理 lambda 表达式

简单例子:重复一个动作 n 次,用到 repeat 方法。

repeat(10,()->(System.out.println("hello world"));

需要实现一个函数式接口,这里使用 Runnable 接口,调用 action.run () 时会执行这个函数主体:

public static void repeat(int n,Runnable action){
    for(int i;i<n;i++) action.run();
}

实际上 lambda 表达式能做的也就是转换成函数式接口。

一些常用的函数式接口:Runnable,Supplier,Consumer,BiConsumer,Function,BiFunction,UnaryOperator,BinaryOperator,Predicate,BiPredicate。

 

-source 1.5 中不支持 lambda 表达式   (请使用 -source 8 或更高版本以启用 lambda 表达式)

-source 1.5 中不支持 lambda 表达式 (请使用 -source 8 或更高版本以启用 lambda 表达式)

Warning:scala: skipping Scala files without a Scala SDK in module(s) JavaSparkTest

 

Error:(19, 23) java: -source 1.5 中不支持 lambda 表达式
  (请使用 -source 8 或更高版本以启用 lambda 表达式)

5.8 java 11 增强的 Lambda 表达式

5.8 java 11 增强的 Lambda 表达式

[TOC] Lambda 表达式支持将代码块作为方法的参数,Lambda 表达式允许使用更加简洁的代码来创建一个只有一个抽象方法的接口(这种接口被称为函数式接口)的实例。 #一、Lambda 表达式入门 —— 为了避免匿名内部类的繁琐 我们前面介绍了 Command 表达式的例子: 定义一个处理数组元素的接口

package one;
public interface Command
{
	//接口里定义的Process方法用于封装“处理行为”
	void process(int element);
}

定义一个处理数组的类

package two;
import one.Command;
public class ProcessArray
{
	public void process(int[] target,Command cmd)
	{
		for(var t:target)
		{
			cmd.process(t);
		}
	}
}

1、通过匿名类来调用 Commad 处理数组

import one.Command;
import two.ProcessArray;
class CommandTest1 
{
	public static void main(String[] args) 
	{
		var pa=new ProcessArray();
		int[] a={1,5,9,7};
		pa.process(a,new Command(){
			public void process(int element)
			{
				System.out.println("数组元素的平方:"+element*element);
			}
		});
	}
}
---------- 运行Java捕获输出窗 ----------
数组元素的平方:1
数组元素的平方:25
数组元素的平方:81
数组元素的平方:49

输出完成 (耗时 0 秒) - 正常终止

2、Lambda 表达式来简化匿名内部类对象

import one.Command;
import two.ProcessArray;
class CommandTest2 
{
	public static void main(String[] args) 
	{
		var pa=new ProcessArray();
		int[] a={1,5,9,7};
		pa.process(a,(int element)->
		System.out.println("数组元素的平方:"+element*element));
	}
}

这段代码代码与创建匿名内部类时实现的 process (int element) 方法完全相同,只是不需要 new Xxx (){} 的繁琐形式,不需要指出重写方法的名字,也不需要指出重写方法的返回值类型,只需要给出重写方法括号以及括号里的形参列表即可。 ##3、Lambda 语句的组成 Lambda 表达式主要用于代替匿名内部类的繁琐语法。它由三部分组成: 1、形参列表。形参列表允许是省略类型。如果形参列表只有一个参数,甚至连形参列表的圆括号也可以省略。 2、箭头 (->) 3、代码块。如果代码块只有一条语句允许省略代码块的花括号;如果只有一条 return 语句,甚至可以省略 return 关键字。Lambda 表达式需要返回值,而他的代码块仅有一条省略了 return 语句,Lambda 表达式会自动返回这条语句的值。 Lambda 表达式的集中简化形式:

interface Eatable
{
	void taste();//public abstract
}
interface Flyable
{
	void fly(String weather);
}
interface Addable
{
	int add(int a,int b);
}

public class LambdaQs
{
	//调用该方法需要Eatable对象
	public void eat(Eatable e)
	{
		System.out.println(e);
		e.taste();
	}
	//调用该方法需要Flyable对象
	public void drive(Flyable f)
	{
		System.out.println("我正在驾驶:"+f);
		f.fly("[碧空如洗的晴天]");
	}
	//调用该方法需要Addable对象
	public void test(Addable add)
	{
		System.out.println("3加5的和为:"+add.add(3,5));
	}
	public static void main(String[] args)
	{
		var lq=new LambdaQs();
		//Lambda语句只有一条语句,可以省略花括号
		lq.eat(()->System.out.println("苹果味道不错!"));

		//Lambda表达式形参列表只有一个形参,可以省略圆括号
		lq.drive(weather->{
			System.out.println("今天天气是"+weather);
			System.out.println("直升机平稳飞行");});
		
		//Lambda只有一条语句时,可以省略花括号
		//代码块只有一条语句,即使该表达式需要返回值,也可以省略return关键字
		lq.test((a,b)->{return (a+b);});
		lq.test((a,b)->a+b);
	}
}
---------- 运行Java捕获输出窗 ----------
LambdaQs$$Lambda$1/0x0000000801201040@72ea2f77
苹果味道不错!
我正在驾驶:LambdaQs$$Lambda$2/0x0000000801201840@eed1f14
今天天气是[碧空如洗的晴天]
直升机平稳飞行
35的和为:8
35的和为:8

输出完成 (耗时 0 秒) - 正常终止

lq.eat () 使用不带形参列表的匿名方法,由于该 Lambda 表达式只有一条代码,因此可以省略花括号; lq.drive () 的 Lambda 表达式的形参列表只有一个形参,因此省略了形参列表的圆括号; lq.test () 的 Lambda 表达式的代码块只有一行语句,这行语句的返回值作为该代码块的返回值。

二、lambda 表达式与函数式接口

Lambda 表达式的类型,也成为 “目标类型(target type)”,Lambda 表达式的目标类型必须是 “函数式接口(functional interface)”。<font color=red> 函数式接口代表只包含一个一个抽象方法的接口。函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法。</font>

2.1 匿名内部类和 Lambda 表达式的适用情况

如果采用匿名内部类语法来创建函数式接口,且只需要实现一个抽象方法,在这种情况下,即可采用 Lambda 表达式来创建对象,该表示创建出来的对象的目标类型就是函数式接口。 注: Java 8 专门为函数式接口提供了 @FunctionalInterface 注解,该注解用于方法在接口定义前面,该注解对程序功能没有任何影响,它用于告诉编译器执行更严格的检查 —— 检查该接口必须是函数式接口,否则编译就会出错。 下面程序使用匿名内部类:

/*@FunctionalInterface
 *A 不是函数接口
 * 在 接口 A 中找到多个非覆盖抽象方法
 */
interface A
{
	public void test1();
	public void test2();
	default void test3()//接口中的默认方法
	{
		System.out.println("接口A中的默认方法");
	}
} 
public class 适用匿名内部类
{
	public void test(A a)
	{
		System.out.println("接口A含有两个抽象方法和一个默认方法,此时适合用匿名内部类");
		a.test1();
		a.test2();
		a.test3();
	}
	public static void main(String[] args)
	{
		var p=new 适用匿名内部类();
		p.test(new A()
		{
			public void test1()
			{
				System.out.println("接口中的抽象方法1");
			}
			public void test2()
			{
				System.out.println("接口中的抽象方法2");
			}
		});
	}
}
接口A含有两个抽象方法和一个默认方法,此时适合用匿名内部类
接口中的抽象方法1
接口中的抽象方法2
接口A中的默认方法

下面定义的接口 B 只有一个抽象方法,是函数式接口,此时适合用 Lambda 表达式:

@FunctionalInterface
interface B
{
	void test1(String msg);//抽象方法,默认public abstract
	default void test2()//接口中的默认方法
	{
		System.out.println("接口A中的默认方法");
	}
} 
public class LambdaFor
{
	public void test(B b)
	{
		System.out.println("接口A含有1个抽象方法和一个默认方法,是函数式接口");
		b.test1("函数式接口A中的抽象方法");
		b.test2();
	}
	public static void main(String[] args)
	{
		var p=new LambdaFor();
		p.test((msg)->
			System.out.println(msg));
	}
}
---------- 运行Java捕获输出窗 ----------
接口A含有1个抽象方法和一个默认方法,是函数式接口
函数式接口A中的抽象方法
接口A中的默认方法

输出完成 (耗时 0 秒) - 正常终止

2.2 使用 Lambda 表达式赋值给对象

用于 Lambda 表达式的结果就是被当成对象,因此程序中完全可以使用 Lambda 表达式进行赋值。我们知道接口不能创建实例,接口中只能定义常量,因此接口不存在构造器和初始化块。接口不能创建实例,但是通过 Lambda 表达式我们可以创建一个 “目标类型” 并把它赋值给函数式接口的对象。 例如:

@FunctionalInterface
interface Runnable
{
	void printNum();
}
public class RunnableTest
{
	public static void main(String[] args)
	{
		//Runnable接口中只包含一个无参数的构造器方法
		//Lambda表达式代表的匿名方法实现了Runnable接口中唯一的无参数方法
		//因此下面的方法创建了一个Runnable的对象
		Runnable r=()->{
			for(int i=0;i<10;i++)
				System.out.print(" "+i);
		};
		r.printNum();
	}
}
---------- 运行Java捕获输出窗 ----------
 0 1 2 3 4 5 6 7 8 9
输出完成 (耗时 0 秒) - 正常终止

<font color=red>Lambda 表达式实现的匿名方法 —— 因此它只能实现特定函数式接口中唯一方法。这意味着 Lambda 表达式有两个限制: 1、Lambda 表达式的目标类型必须是明确的函数式接口。 2、Lambda 表达式只能为函数式接口创建对象。Lambda 表达式只能实现一个方法,因此他只能为只有一个抽象方法的接口(函数式接口)创建对象。</font> 关于第一点限制举例:

@FunctionalInterface
interface A
{
	void test();
}
class  LambdaLimit1
{
	public static void main(String[] args) 
	{
		//Object a=()->{System.out.println("This is a test!");};
		//上面代码将报错: 不兼容的类型: Object 不是函数接口
		
		//Lambda表达式的目标类型必须是明确的函数式接口
		A a=()->{System.out.println("This is a test!");};
		a.test();//This is a test!
	}
}

从错误信息可以看出,Lambda 表达式的目标类型必须是明确的函数式接口。上述表达式将 Lambda 表达式赋给 Object 变量,编译器只能确定该表达式的类型为 Object,而 Object 并不是函数式接口。 为了保证 Lambda 表达式的目标类型是一个明确的函数式接口,常见有三种方式: 1、将 Lambda 表达式赋值给函数式接口的变量;

    //参考上面的完整程序
    A a=()->{System.out.println("This is a test!");};

2、将 Lambda 表达式作为函数接口类型的参数传给某个方法。

interface A
{
	void test(String msg);
}
public class ATest
{
	public static void med(A a)
	{
		System.out.println("主类的非静态方法");
		a.test("我是传奇");
	}
	public static void main(String[] args)
	{
		ATest.med((msg)->System.out.println(msg));
	}
}
---------- 运行Java捕获输出窗 ----------
主类的非静态方法
我是传奇

输出完成 (耗时 0 秒) - 正常终止

3、使用函数式接口类型对 Lambda 表达式进行强制转换。

Object a=(A)()->{System.out.println("This is a test!");};

三、在 Lambda 表达式中使用 var

对与 var 声明变量,程序可以使用 Lambda 表达式进行赋值。但由于 var 代表需要由编译器推断的类型,因此使用 Lambda 表达式对 var 表达式定义的变量进行赋值时,必须指明 Lambda 表达式的目标类型。 例如:

var a=(A)()->{System.out.println("This is a test!");};

如果程序需要对 Lambda 表达式的形参列表添加注解,此时就不能省略 Lambda 表达式的形参类型 —— 因为注解只能放在形参类型之前。在 Java 11 之前,程序必须严格声明 Lambda 表达式中的每个形参类型,但实际上编译器完全可以推断出 lambda 表达式中每个形参的类型。

例如:下面程序定义了一个 Predator 接口,该接口中的 prey 方法的形参使用了 @NotNull 注解修饰:

@interface NotNull{}
interface Predator
{
	void prey(@NotNull String animal);
}

接下来程序打算使用 Lambda 表达式来实现一个 Predator 对象。如果 Lambda 表达式不需要对 animal 形参使用 @NotNull 注解,则完全可以省略 animal 形参注解;但如果希望为 animal 形参注解,则必须为形参声明类型,此时可直接使用 var 来声明形参类型。

@interface NotNull{}
interface Predator
{
	void prey(@NotNull String animal);
}
public class PredatorTest
{
	public static void main(String[] args)
	{
		//使用var声明lambda表达式的形参类型
		//这样即可为Lambda表达式的形参添加注解
		Predator p=(@NotNull var animal)->System.out.println("老鹰在抓"+animal);
		p.prey("小鸡");
	}
}
//老鹰在抓小鸡

#四、方法引用和构造器引用 Lambda 表达式的方法引用和构造器引用都需要两个英文冒号::。Lambda 表达式支持如下几种引用方式:

种类 示例 说明 对应的 Lambda 表达式
引用类方法 类名::类方法名 函数式接口中被实现的方法的参数全部传给该类方法作为参数 (a,b...)-> 类名。类方法(a,b...)
引用特定对象的实例方法 特定对象::示例方法名 函数式接口中被实现的方法的参数全部传给该实例方法作为参数 (a,b...)-> 特定对象。实例方法 (a,b...)
引用某类对象的实例方法 类名::实例方法名 函数式接口中被实现的方法的第一个参数作为调用者,后面的参数传给该方法作为参数 (a,b,c...)->a. 实例方法 (b,c...)
引用构造器 类名::new 函数式接口中被实现的方法的全部参数传给该构造器作为参数 (a,b...)->new 类名 (a,b...)
##4.1 引用类方法
@FunctionalInterface
interface Converter
{
	Integer convert(String form);
}

public class ConverterTest
{
	public static void main(String[] args)
	{
		//Lambda表达式只有一条语句,可以省略1花括号:Lambda表达式会把这条代码的值作为返回值
		Converter c=(form)->Integer.parseInt(form);
		System.out.println(c.convert("185"));

		//下面通过引用类方法来实现相同的功能
		Converter cPlus=Integer::valueOf;
		System.out.println(cPlus.convert("140"));
	}
}

##4.2 引用特定对象的实例方法

@FunctionalInterface
interface Converter
{
	Integer convert(String form);
}

public class ConverterTest1
{
	public static void main(String[] args)
	{
		//先使用Lambda表达式来创建一个Converter对象
		Converter c=form->"fkit.org".indexOf(form);//代码块只有一条语句,因此Lambda表达式会把这条代码的值作为返回值
		System.out.println(c.convert("it"));//输出2

		//引用特定对象的特定方法 "fkit.org"是一个String对象
		Converter c1="fkit.org"::indexOf;
		System.out.println(c1.convert("org"));//输出5
	}
}

对于上面的示例方法引用,也就是说,调用 "fkit.org" 对象的 indexOf () 实例方法来实现 Converter 函数式接口中唯一的抽象方法,当调用 Converter 接口中的唯一抽象的方法时,调用参数会传给 "fkit.org" 对象的 indexOf () 实例方法。 ##4.3 引用某类对象的实例方法 先介绍一个函数:public String substring (int beginIndex, int endIndex) 返回字符串索引范围 [beginIndex,endIndex) 的子字符串。

@FunctionalInterface
interface MyTest
{
	String test(String a,int b, int c);
}
class  substringTest
{
	public static void main(String[] args) 
	{
		MyTest m=(a,b,c)->a.substring(b,c);
		System.out.println(m.test("fkjava",1,5));

		//引用某类对象的实例方法
		MyTest mPlus=String::substring;
		System.out.println(mPlus.test("hello world",2,7));//相当于"hello world".substring(2,7)
	}
}
---------- 运行Java捕获输出窗 ----------
kjav
llo w

输出完成 (耗时 0 秒) - 正常终止

##4.4 引用构造器 JFrame 屏幕上 window 的对象,能够最大化、最小化、关闭

import java.awt.*;
import javax.swing.*;
@FunctionalInterface
interface YourTest
{
  JFrame win(String title);
}
public class MethodRefer
{
  public static void main(String[] args)
  {
   // 下面代码使用Lambda表达式创建YourTest对象
//  YourTest yt = (String a) -> new JFrame(a);
   // 构造器引用代替Lambda表达式。
   // 函数式接口中被实现方法的全部参数传给该构造器作为参数。
   YourTest yt = JFrame::new;
   JFrame jf = yt.win("我的窗口");
   System.out.println(jf);
  }
}

#五、Lambda 表达式和匿名内部类的联系和区别 Lambda 表达式与匿名内部类之间存在如下相同点: 1、Lambda 表达式与匿名内部类一样,都可以直接访问 "effectively final" 的局部变量,以及外部类的成员变量,包括实例变量和类变量。 2、Lambda 表达式创建的对象与匿名内部类生成的对象一样,都可以直接从接口中继承的默认方法。

@FunctionalInterface
interface Displayable
{
	void display();
	default int add(int a,int b)
	{
		return a+b;
	}
}

public class LambdaAndInner
{
	private int age=12;
	private static String name="fkit.org";
	public void test()
	{
		var book="疯狂Java讲义";
		Displayable dis=()->{
			//访问"effictively final"的局部变量
			System.out.println("book局部变量为:"+book);
			//访问外部类的实例变量和类变量
			System.out.println("外部类的age实例变量:"+age);
			System.out.println("外部类的name类变量:"+name);
			};
		dis.display();
		//调用方对从接口继承add()方法
		System.out.println(dis.add(3,5));
	}
	public static void main(String[] args)
	{
		var lambda=new LambdaAndInner();
		lambda.test();
	}
}
---------- 运行Java捕获输出窗 ----------
book局部变量为:疯狂Java讲义
外部类的age实例变量:12
外部类的name类变量:fkit.org
8

输出完成 (耗时 0 秒) - 正常终止

与匿名函数相似的是,由于 Lambda 表达式访问了 book 局部变量,因此该局部变量相当于有一个隐式的 final 修饰,因此同样不允许对 book 局部变量重新赋值。当程序使用了 Lambda 表达式创建了 Displayable 对象之后,该对象不仅可调用接口的抽象方法,也可以调用接口中的默认方法,因此同样不允许对 book 局部变量重新赋值。 </font color=red>Lambda 表达式与匿名内部类的区别: 1、匿名内部类可以为内部类可以为任意接口创建实例;但 Lambda 表达式只能为函数式创建实例。 2、匿名内部类可以为抽象类乃至普通类创建实例;但 Lambda 表达式只能为函数式接口创建实例。 3、匿名内部类是实现抽象方法的方法体允许调用接口中定义的默认方法;但 Lambda 表达式的代码块不允许不允许调用接口中的默认方法。</font>

#六、使用 Lambda 表达式调用 Arrays 的类方法 Arrays 类的有些方法需要 Comparator、XxxOperator、XxxFunction 等接口的实例,这些接口都是函数式编程,因此可以使用 Lambda 表达式来调用 Arrays 的方法。

import java.util.Arrays;
public class LambdaArrays
{
	public static void main(String[] args)
	{
		var arr1 = new String[] {"java", "fkava", "fkit", "ios", "android"};
		Arrays.parallelSort(arr1, (o1, o2) -> o1.length() - o2.length());
                //这行Lambda表达式的目标类型是Comparator,该Comparator指定判断字符串大小的标准:字符串越长,认为该字符串越大
		System.out.println(Arrays.toString(arr1));

		var arr2 = new int[] {3, -4, 25, 16, 30, 18};
		// left代表数组中前一个所索引处的元素,计算第一个元素时,left为1
		// right代表数组中当前索引处的元素
		Arrays.parallelPrefix(arr2, (left, right)-> left * right);
                 //这行Lambda表达式的目标类型是IntBinaryOperator,该对象将会根据前后两个元素来计算当前元素
		System.out.println(Arrays.toString(arr2));
                
		var arr3 = new long[5];
		// operand代表正在计算的元素索引
		Arrays.parallelSetAll(arr3, operand -> operand * 5);
                //这行Lambda表达式的目标类型是IntToLongFunction,该对象将会根据当前索引值计算当前元素的值。
		System.out.println(Arrays.toString(arr3));
	}
}
---------- 运行Java捕获输出窗 ----------
[ios, java, fkit, fkava, android]
[3, -12, -300, -4800, -144000, -2592000]
[0, 5, 10, 15, 20]

输出完成 (耗时 0 秒) - 正常终止

AWS CLI 表达式:错误的 jmespath 表达式:未知令牌

AWS CLI 表达式:错误的 jmespath 表达式:未知令牌

如何解决AWS CLI 表达式:错误的 jmespath 表达式:未知令牌

我运行下面的查询并且它有效。

aws ec2 describe-security-groups \\
          --filters Name=ip-permission.from-port,Values=21 Name=ip-permission.to-Port,Values=21  \\
          --query ''SecurityGroups[].[Tags[?Key==`Owner`] | [0].Value,GroupId]'' \\
          --output text

但是试图获取对所有人开放流量的安全组以及 Tag=Owner 的值,我运行它并得到 jmespath 错误。

aws ec2 describe-security-groups --filters Name=ip-permission.protocol,Values=-1 --query SecurityGroups[?IpPermissions[?IpProtocol == ''-1'' && contains(IpRanges[].CidrIp,''0.0.0.0/0'')]].[Tags[?Key==`Owner`] | [0].Value,GroupId]'' --output=text 

--query SecurityGroups[?IpPermissions[?IpProtocol == -1 && contains(IpRanges[].CidrIp,0.0.0.0/0)]]].[Tags[?Key==Owner 的错误值] | [0].Value,GroupId]: 错误的 jmespath 表达式:未知标记 /:""

解决方法

我个人更喜欢 Steampipe,一个可以使用 SQL 查询 AWS 资源的 CLI。它可能比 JMES 更冗长,但更易于阅读和更灵活的查询。

这是您使用 aws_vpc_security_group_rule 表作为 SQL 的第一个查询:

select
  sg.tags ->> ''Owner'' as owner,sg.group_id
from
  aws_vpc_security_group as sg
  join aws_vpc_security_group_rule as rule on sg.group_id = rule.group_id
where
  rule.type = ''ingress''
  and from_port = 22
  and to_port = 22;

这是一个查找开放端口的查询:

select
  sg.tags->>''Owner'',sg.group_id
from
  aws_vpc_security_group as sg
  join aws_vpc_security_group_rule as rule on sg.group_id = rule.group_id
where
  rule.type = ''ingress''
  and rule.ip_protocol = ''-1''
  and rule.cidr_ip = ''0.0.0.0/0''

AWS Lambda EFS | EACCES:权限被拒绝 访问点请注意/lambda Lambda注释/mnt/lambda

AWS Lambda EFS | EACCES:权限被拒绝 访问点请注意/lambda Lambda注释/mnt/lambda

如何解决AWS Lambda EFS | EACCES:权限被拒绝 访问点请注意/lambda Lambda注释/mnt/lambda

因此,我正在尝试将lambda函数与EFS集成。我可以访问根目录(从lambda只读),因为我在根目录中可以看到xyz目录。 /mnt/-> xyz

当我尝试访问/mnt/xyz/mnt/xyz/时,出现此错误:

{
  "errorType": "Error","errorMessage": "EACCES: permission denied,scandir ''/mnt/xyz/''","trace": [
    "Error: EACCES: permission denied,"    at Object.readdirsync (fs.js:948:3)","    at Runtime.exports.handler (/var/task/index.js:19:24)","    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
  ]
}

授予访问点的权限:777

解决方法

好的,所以我面临的问题与用户/组 ID(所有权)有关。该文件由运行在 AWS EC2 实例上的应用程序生成,并由 AWS Lambda 函数使用。

  • 要查找所有者/文件组,请使用 cmd ls -al

  • 要查找所有者/组ID,请使用 cmd ls -n

  • 作为根生成的文件(UID:0),我需要在 EFS 接入点 owner id 和 group id 设置为 0 /p>

此配置解决了我的问题。

,

我试图复制问题,并且可以验证我也遇到了同样的问题。帮助来自以下github问题:EFS permission denied。

被拒绝的权限是由于分别在访问点和lambda中错误地设置了root和本地安装点引起的。 担心的正确设置是:

访问点(请注意/lambda

Lambda(注释/mnt/lambda

通过这些设置,可以成功访问EFS。

我们今天的关于Java lambda 表达式javalambda表达式实现原理的分享就到这里,谢谢您的阅读,如果想了解更多关于-source 1.5 中不支持 lambda 表达式 (请使用 -source 8 或更高版本以启用 lambda 表达式)、5.8 java 11 增强的 Lambda 表达式、AWS CLI 表达式:错误的 jmespath 表达式:未知令牌、AWS Lambda EFS | EACCES:权限被拒绝 访问点请注意/lambda Lambda注释/mnt/lambda的相关信息,可以在本站进行搜索。

本文标签: