Java8特性-Lambda表达式

📕概述

        在Java 8中引入了Lambda表达式作为一项重要的语言特性,可以堪称是一种语法糖。Lambda表达式使得以函数式编程的方式解决问题变得更加简洁和便捷。

Lambda表达式的语法如下:

(parameters) -> expression
(参数) -> {代码}

        其中,parameters是Lambda表达式的参数列表,可以是零个或多个参数,如果有多个参数,用逗号分隔;expression是Lambda表达式的函数体,可以是一个表达式或一段语句块。

❗使用Lambda表达式的条件

  1. 函数式接口:Lambda表达式只能用于函数式接口(Functional Interface)的实现。函数式接口是指只包含一个抽象方法的接口。函数式接口可以使用@FunctionalInterface注解显式声明,但这并非必要,只要满足函数式接口的特征即可。

  2. 上下文匹配:Lambda表达式必须与上下文(Context)相匹配,即Lambda表达式的参数和返回类型必须与目标上下文的参数和返回类型相匹配。例如,Lambda表达式可以作为方法的参数或赋值给一个接口类型的变量。

📕Lambda表达式

以下是一个简单的Lambda表达式的示例:

//Lambda表达式作为匿名函数实现两个数相加
MathOperation addition = (int a,int b) -> a+b;
int result = addition.operation(2,3);//结果为5

        在这个示例中,我们定义了一个MathOperation接口,并使用Lambda表达式作为接口的实现。Lambda表达式接受两个整数参数ab,并返回它们的和。

🏷例1

public class LambdaTest {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程开始");                }}).start();}
}

使用Lambda表达式实现就是这样子的:

public class LambdaTest {public static void main(String[] args) {new Thread(() -> System.out.println("线程开始")).start();}
}

🏷例2

public class LambdaTest {public static void main(String[] args) {int b = calculateNum(new IntBinaryOperator() {@Overridepublic int applyAsInt(int left, int right) {return left + right;}});System.out.println(b);}public static int calculateNum(IntBinaryOperator operator){int a = 10;int b = 20;return operator.applyAsInt(a,b);}
}

使用Lambda表达式就是这个样子的:

public class LambdaTest {public static void main(String[] args) {int b = calculateNum((left, right) -> left + right);System.out.println(b);}public static int calculateNum(IntBinaryOperator operator){int a = 10;int b = 20;return operator.applyAsInt(a,b);}
}

        还差那么点意思是吧🤭,因为啥,因为return是吧,为啥掉了呢,其实没有掉,你把left+right改成{return left+right}试试,那肯定是不会报错的,left+right是表达式,加个return就是语句了,所以需要加上{}包裹着。你再看,和左边去掉之后有没有哪里不一样。 

        这里说明:注意使用Lambda表达式的前提吼,Lambda表达它不需要知道你接口名,也不需要知道你的接口内的方法名,但是哦,可得记住,这个接口内只能有一个抽象方法,那么我们就可以直接把不需要的东西去掉,简化后的代码就是Lambda表达式,但是这个时候你如果安装了idea的一些插件,他可能会提示你说还可以转换成Lambda更简化的表达式,不要着急,咱们慢慢来来!

🏷例3

public class LambdaTest {public static void main(String[] args) {printNum(new IntPredicate() {@Overridepublic boolean test(int value) {return value%2==0;}});}public static void printNum(IntPredicate intPredicate){int[] arr = {1,2,3,4,5,6,7,8,9};for (int i : arr) {if(intPredicate.test(i)){System.out.println(i);}}}
}

改为Lambda表达式:

public class LambdaTest2 {public static void main(String[] args) {printNum((int value) ->{return value%2==0;});}public static void printNum(IntPredicate intPredicate){int[] arr = {1,2,3,4,5,6,7,8,9};for (int i : arr) {if(intPredicate.test(i)){System.out.println(i);}}}
}

就这么简单,不用怀疑,就是这么简单,但是这还不是最简化的形式。

🏷例4

🆗,例子到此结束,这四个例子可以看出,转换Lambda表达式,接口名和方法名我们no care,我们只关注这个参数。咱们继续 👇

📕转换Lambda表达式简化规则

  1. 参数类型可以省略
  2. 方法体只有一句代码时,大括号return和唯一一句代码的分号可以省略
  3. 方法只有一个参数时小括号可以省略
  4. 以上这些规则都记不住也可以省略不记(因为IDEA有快捷键可以实现)Alt+Enter

 我们看上面说到的最后一个例子:简化的前提是,先转换成Lambda表达式再简化

这其实就和右边的一样了 。

当然还有更简化的方式啊,就是简化Integer.valueOf(str)为Integer::valueOf,这个是为什么呢?

        在Java中,Integer.valueof是调用静态方法的一种方式。它表示调用Integer类的valueof方法,将一个基本类型的整数值转换为对应的Integer对象。

        而Integer::valueof则是Java 8引入的方法引用(Method Reference)的语法。它也表示调用Integer类的valueof方法,并且可以作为Lambda表达式的替代形式使用。相当于把方法引用包装成一个函数接口。

        因此,Integer.valueofInteger::valueof的作用是完全相同的,只是语法上的不同而已。它们都用于将基本类型的整数值转换为对应的Integer对象。

那么类似这样的,都可以转换:

byte by = 10;
Byte byteObj = Byte.valueOf(by); // 将byte类型的值转换为Byte对象short sh = 100;
Short shortObj = Short.valueOf(sh); // 将short类型的值转换为Short对象int i = 1000;
Integer intObj = Integer.valueOf(i); // 将int类型的值转换为Integer对象long l = 1000000L;
Long longObj = Long.valueOf(l); // 将long类型的值转换为Long对象float f = 3.14f;
Float floatObj = Float.valueOf(f); // 将float类型的值转换为Float对象double d = 1.4142135;
Double doubleObj = Double.valueOf(d); // 将double类型的值转换为Double对象

 如果这种不会转换,那就用快捷键吧。

📕Stream流

 🏷准备工作

/*** @author 小白程序员* @Classname Author* @Description TODO干啥呢* @date 2023/9/3 17:39*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode //后期去重的使用
public class Author {private Long id;private String name;private Integer age;private String intro;private List<Book> books;
}/*** @author 小白程序员* @Classname Book* @Description TODO干啥呢* @date 2023/9/3 17:41*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Book {private Long id;private String name;private String category;private Integer score;private String intro;
}/*** @author 小白程序员* @Classname BookService* @Description TODO干啥呢* @date 2023/9/3 17:43*/
public class BookService {public static void main(String[] args) {//后面的代码都写在这一块的来测试}private static List<Author> getAuthors() {Author author = new Author(1L, "蒙多", 17, "一个祖安人", null);Author author2 = new Author(2L, "亚拉索", 18, "艾欧尼亚", null);Author author3 = new Author(3L, "易大师", 19, "黑色玫瑰", null);Author author4 = new Author(3L, "易大师", 19, "黑色玫瑰", null);List<Book> book1 = new ArrayList<>();List<Book> book2 = new ArrayList<>();List<Book> book3 = new ArrayList<>();List<Book> book4 = new ArrayList<>();book1.add(new Book(1L,"*","哲学,爱情", 80, "*"));book1.add(new Book(2L,"**","爱情,个人成长", 80, "**"));book2.add(new Book(3L,"***","爱情,传记", 70, "***"));book2.add(new Book(3L,"****","个人成长,传记", 70, "****"));book2.add(new Book(4L,"*****","哲学", 70, "*****"));book3.add(new Book(5L,"******","个人成长", 60, "******"));book3.add(new Book(6L,"*******","传记", 60, "*******"));book3.add(new Book(6L,"********","爱情", 60, "********"));book4.add(new Book(5L,"******","个人成长", 60, "******"));book4.add(new Book(6L,"*******","个人成长,传记,爱情", 60, "*******"));book4.add(new Book(6L,"********","哲学,爱情,个人成长", 60, "********"));author.setBooks(book1);author2.setBooks(book2);author3.setBooks(book3);author4.setBooks(book4);List<Author> authors = new ArrayList<>(Arrays.asList(author,author2,author3,author4));return authors;}
}

🏷案例分析

案例:获取年龄小于18的作家

public static void main(String[] args) {//查询出年龄小于18的作家的名字List<Author> authors = getAuthors();authors.stream().distinct().filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge() < 18;}}).forEach(new Consumer<Author>() {@Overridepublic void accept(Author author) {System.out.println(author.getName());}});
}//Lambda表达式优化
public static void main(String[] args) {//查询出年龄小于18的作家的名字List<Author> authors = getAuthors();authors.stream().distinct().filter(author -> author.getAge() < 18).forEach(author -> System.out.println(author.getName()));}

解释说明一下:authors.stream()是把集合转换成流形式,.distinct()是去重,.filter()是过滤,.forEach()是循环输出。

 🏷常用操作

🔖创建流

①单例集合:集合对象.stream()
List<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream();
②数组:Arrays.stream(数组)或Stream.of(数组)来创建
Integer[] arr = {1,2,3,4};
Stream<Integer> stream1 = Arrays.stream(arr);
Stream<Integer> stream2 = Stream.of(arr);
③双例集合:转换成单例集合再创建
Map<String, String> map = new HashMap<>();
Stream<Map.Entry<String, String>> stream3 = map.entrySet().stream();

🔖中间操作

①filter

对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。

public static void main(String[] args) {//查询出年龄小于18的作家的名字List<Author> authors = getAuthors();authors.stream().distinct().filter(author -> author.getAge() < 18)//中间操作.forEach(author -> System.out.println(author.getName()));//终结操作}
②map

可以把流中的元素进行计算或转换。

public static void main(String[] args) {List<Author> authors = getAuthors();authors.stream().map(new Function<Author, String>() {//泛型中,第一个参数为方法的参数类型(流中的类型),第二个参数为方法的返回值类型@Overridepublic String apply(Author author) {return author.getName();}}).forEach(new Consumer<String>() {@Overridepublic void accept(String name) {System.out.println(name);}});
}//Lambda表达式优化public static void main(String[] args) {List<Author> authors = getAuthors();//泛型中,第一个参数为方法的参数类型(流中的类型),第二个参数为方法的返回值类型authors.stream().map(author -> author.getName()).forEach(name -> System.out.println(name));}

由此可以看出,Lambda表达式是有多么简化代码。

计算使用

public static void test() {List<Author> authors = getAuthors();//泛型中,第一个参数为方法的参数类型,第二个参数为方法的返回值类型authors.stream().map(author -> author.getAge()).map(age -> age+10).forEach(age -> System.out.println(age));
}
③distinct

去除流中重复的元素。

❗distinct方法是依赖Object类中的equals方法来判断是否是相同对象,所以需要重写equals方法

④sorted

对流中的元素进行排序

👍调用sorted()空参方法

在比较的实体类上要实现Comparable接口,不然会报类型不匹配的异常。

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode //后期去重的使用
public class Author implements Comparable<Author>{private Long id;private String name;private Integer age;private String intro;private List<Book> books;@Overridepublic int compareTo(Author o) {return this.getAge()-o.getAge();}
}
public static void test2(){List<Author> authors = getAuthors();authors.stream().distinct().sorted().forEach(author -> System.out.println(author.getName()));}

这里sorted内没有参数是因为在实体类中定义了比较的方式,所以不用传递参数。

👍在sorted方法中实现Comparator接口

        首先把Author中实现的东西去掉,用Lambda表达式方式写比较条件。sorted()方法中的new Comparator<T>是一个函数式接口,内部只有一个和compare抽象方法。

public static void test3() {List<Author> authors = getAuthors();authors.stream().distinct().sorted(new Comparator<Author>() {@Overridepublic int compare(Author o1, Author o2) {return o1.getAge()-o2.getAge();}}).forEach(author -> System.out.println(author.getAge()));
}

优化 

public static void test3(){List<Author> authors = getAuthors();authors.stream().distinct().sorted(((o1, o2) -> o2.getAge()- o1.getAge())).forEach(author -> System.out.println(author.getAge()));}
⑤limit

可以设置流的最大长度,超出的部分将被抛弃。

public static void test4(){List<Author> authors = getAuthors();authors.stream().distinct().sorted(((o1, o2) -> o2.getAge()- o1.getAge())).limit(2).forEach(System.out::println);}
⑥skip

跳过流中的前N个元素,返回剩下的元素。

⑦flatMap

map方式:map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。

案例:打印所有书籍,要求对重复的元素进行去重。

map方式:Author对象的books属性是集合类型,使用原来map转换对象,要使用嵌套循环进行打印。

public static void test5() {List<Author> authors = getAuthors();authors.stream().map(Author::getBooks).forEach(books -> {books.forEach(System.out::println);});}

 flatMap方式:

public static void test6() {List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBooks().stream()).forEach(System.out::println);}
案例二:打印现有数据的所有分类,要求对分类进行去重。不能出现这种格式:哲学,爱情,要将它们拆开输出。
public static void test7(){List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBooks().stream()).distinct().flatMap(book -> Arrays.stream(book.getCategory().split(","))).distinct().forEach(System.out::println);}

🔖终结操作

①forEach

对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么具体的操作。

②count

获取当前流中的元素个数。

public static void test8(){List<Author> authors = getAuthors();Long count = authors.stream().flatMap(author -> author.getBooks().stream()).distinct().count();System.out.println(count);}
③max&min

获取流中的最值

public static void test9(){List<Author> authors = getAuthors();Optional<Integer> max = authors.stream().flatMap(author -> author.getBooks().stream()).map(Book::getScore).max(((o1, o2) -> o2-o1));Optional<Integer> min = authors.stream().flatMap(author -> author.getBooks().stream()).map(Book::getScore).max(((o1, o2) -> o1-o2));System.out.println(max);System.out.println(min);}
④collect

把当前流的元素转换成一个集合

//获取一个存放所有作者名字的list集合
public static void test5() {List<Author> authors = getAuthors();List<String> nameList = authors.stream().map(author -> author.getName()).collect(Collectors.toList());System.out.println(nameList);
}

list集合、set集合、map集合都是类似的

注意map的是两个参数哦:collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()))

⑤查找与匹配

(1)anyMatch:判断是否有任意符合匹配条件的元素,结果为Boolean类型。

public static void test9(){List<Author> authors = getAuthors();boolean flag = authors.stream().anyMatch(author -> author.getAge()>18);System.out.println(flag);}

(2)allMatch:判断是否都符合条件,如果都符合返回true,否则返回false

public static void test10(){List<Author> authors = getAuthors();boolean b = authors.stream().allMatch(author -> author.getAge() > 18);System.out.println(b);}

(3)noneMatch:判断流中的元素是否都不符合匹配条件,如果都不符合结果为true,否则为false

(4)findAny:获取流中的任意一个元素,该方法没有办法保证获取到的一定是流中的第一个元素。

public static void test11(){//获取任意一个年龄大于18的作家List<Author> authors = getAuthors();Optional<Author> any = authors.stream().filter(author -> author.getAge() > 50).findAny();//如果这个Optional中有元素,则执行方法,没有就不执行any.ifPresent(System.out::println);}

(5)findFirst:获取流中的第一个元素

public static void test12(){//获取一个年龄最小的作家List<Author> authors = getAuthors();Optional<Author> firstOne = authors.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).findFirst();firstOne.ifPresent(System.out::println);}

(6)reduce归并:对流中的数据按照指定的计算方式计算出一个结果

reduce的作用是把Stream中的元素给组合起来,我们可以传入一个初始值,它会按照我们的计算方式一次拿流中的元素和初始值进行计算,计算结果再和后面的元素计算。

它内部的计算方式如下:

T result = identity;
for (T element : this stream)result = accumulator.apply(result, element)
return result;

其中identity就是我们可以通过方法参数传入的初始值,accumulator的apply具体进行什么计算也是我们通过方法参数来确定的。

案例1:使用reduce求所有作者年龄的和

public static void test13(){List<Author> authors = getAuthors();Integer sum = authors.stream().distinct().map(Author::getAge).reduce(0,(result,element) -> result + element);System.out.println(sum);}

案例2:使用reduce求所有作者中年龄的最大值

public static void test14(){List<Author> authors = getAuthors();Integer max = authors.stream().map(Author::getAge).reduce(Integer.MIN_VALUE,(result,element) -> result > element ? result : element);System.out.println(max);}

reduce有个重载形式,内部代码如下:

boolean foundAny = false;
T result = null;
for (T element : this stream) {if(!foundAny) {foundAny = true;result = element;} else {result = accumulator.apply(result, element);}
}
return foundAny ? Optional.of(result) : Optional.empty();

利用这个重载形式,求作者年龄的最大值,不用传递初始值了。

public static void test8() {List<Author> authors = getAuthors();Optional<Integer> max = authors.stream().map(author -> author.getAge()).reduce((result, element) -> result > element ? result : element);System.out.println(max.get());
}

❗惰性求值:如果没有终结操作,中间操作是不会得到执行的。

❗流是一次性的:一旦一个流对象经过一个终结操作后,这个流就不能在被使用了,只能重新创建流对象再使用。

❗不会影响原数据:我们在流中可以对数据做很多处理,但正常情况下是不会影响原来集合中的元素的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/123824.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法笔记:堆

【如无特别说明&#xff0c;皆为最小二叉堆】 1 介绍 2 特性 结构性&#xff1a;符合完全二叉树的结构有序性&#xff1a;满足父节点小于子节点&#xff08;最小化堆&#xff09;或父节点大于子节点&#xff08;最大化堆&#xff09; 3 二叉堆的存储 顺序存储 二叉堆的有序…

c高级 day2

1.写一个1.sh脚本&#xff0c;将以下内容放到脚本中&#xff1a; 在家目录下创建目录文件&#xff0c;dir 在dir下创建dir1和dir2 把当前目录下的所有文件拷贝到dir1中&#xff0c; 把当前目录下的所有脚本文件拷贝到dir2中 把dir2打包并压缩为dir2.tar.xz 再把dir2.tar.…

TypeScript断言

什么是断言&#xff1f; 一个编译时语法&#xff0c;用于告诉编译器用户比编译器更加确定变量的类型&#xff0c;进而解除编译错误&#xff0c;类型断言有点类似于其他语言的类型转换&#xff0c;但它没有运行时的影响&#xff0c;只是在编译阶段起作用。所以&#xff0c;即使通…

028:vue上传解析excel文件,列表中输出内容

第028个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

机器学习笔记之最优化理论与方法(五)凸优化问题(上)

机器学习笔记之最优化理论与方法——凸优化问题[上] 引言凸优化问题的基本定义凸优化定义&#xff1a;示例 凸优化与非凸优化问题的区分局部最优解即全局最优解凸优化问题的最优性条件几种特殊凸问题的最优性条件无约束凸优化等式约束凸优化非负约束凸优化 引言 本节将介绍凸优…

windows打包uniapp应用p12证书和证书profile文件的制作方法

参考文章1&#xff1a; uniapp打包ios app所需的证书的制作流程-腾讯云开发者社区-腾讯云使用uniapp进行开发&#xff0c;既可以打包小程序&#xff0c;也可以打包app&#xff0c;假如需要打包app&#xff0c;需要p12格式的证书和一个证书profile文件&#xff0c;这个在uniapp…

php - fpm 请求达到max_children最大值后,新进入的请求工作流程

前言 偶然之间想了解下&#xff0c;php-fpm 请求达到max_children最大值后&#xff0c;新进入的请求怎么办&#xff1f;是抛出502还是等待前面的请求完成后&#xff0c;再将请求交给处理完毕的进程处理呢。 准备工作 运行环境&#xff1a;LNMP php 版本&#xff1a;php8.1 …

Elasticsearch:自动使用服务器时间设置日期字段并更新时区

在大多数情况下&#xff0c;你的数据包含一个以 create_date 命名的字段。 即使没有日期字段&#xff0c;处理各种格式和时区的日期对数据仓库来说也是一个重大挑战。 与此类似&#xff0c;如果要检测变化的数据&#xff0c;则必须准确设置日期字段。 在 Elasticsearch 中还有…

OJ练习第165题——修车的最少时间

修车的最少时间 力扣链接&#xff1a;2594. 修车的最少时间 题目描述 给你一个整数数组 ranks &#xff0c;表示一些机械工的 能力值 。ranksi 是第 i 位机械工的能力值。能力值为 r 的机械工可以在 r * n2 分钟内修好 n 辆车。 同时给你一个整数 cars &#xff0c;表示总…

《TCP/IP网络编程》阅读笔记--getsockopt和setsockopt的使用

目录 1--Socket的多种可选项 2--getsocketopt() 3--setsockopt() 4--代码实例 1--Socket的多种可选项 Socket 拥有多种可选项&#xff0c;其可分为 SOL_SOCKET 层&#xff0c;IPPROTO_IP 层和IPPROTO_TCP 层等&#xff0c;一般通过 getsocketopt() 和 setsockopt() 函数进行…

python趣味编程-太空入侵者游戏

在 Python 中使用 Turtle 的简单太空入侵者游戏免费源代码 使用 Turtle 的简单太空入侵者游戏是一个用Python编程语言编码的桌面游戏应用程序。该项目包含克隆实际太空入侵者游戏的多种功能。该项目可以使正在学习计算机相关课程的学生受益。该应用程序易于学习,可以帮助您发现…

入行测试一年半的心得体会

成为xx一员测试已经有1年半了&#xff0c;一直没有真正坐下来花些时间将自己的思路理清一下。刚好近期公司落地了OKR&#xff0c;给自己制定了OKR之后思路终于开始清晰起来&#xff0c;朦朦胧胧地开始看清了远方的路&#xff0c;麻着胆子分析一下自己&#xff0c;毕竟摸黑走路的…

程序分区:全局区、常量区、栈区、堆区、代码区

#include <iostream> using namespace std; //全局变量 int g_a 10; int g_b 10; //全局常量 const int c_g_a 10; const int c_g_b 10;int main() { //局部变量 int a 10; int b 10; //打印地址 cout << "局部变量a地址为&#xff1a; " <…

云原生架构如何助力大数据和AI技术在软件开发中的深度整合

文章目录 1. 云原生架构简介2. 大数据与云原生的融合a. 弹性计算和存储b. 容器化大数据应用c. 数据湖和数据仓库 3. AI与云原生的深度融合a. 弹性AI模型训练b. 容器化AI应用c. 自动化部署和监控 4. 对软件开发的影响a. 更快的开发周期b. 更低的成本c. 更高的灵活性和可伸缩性 5…

OpenCL编程指南-10.1C++包装器API

C包装器API概述 CAPI划分为多个类&#xff0c;分别映射到一个OpenCL C类型&#xff0c;例如&#xff0c;cl::Memory类就映射到OpenCL C中的cl_mem。不过&#xff0c;C API会尽可能使用继承提供额外的一层类型抽象&#xff1b;例如&#xff0c;类cl::Buffer派生自基类cl::Memor…

h5开发网站-使用jquery来实现二层嵌套的左侧列表,点击后显示右侧内容的效果

一、需求&#xff1a; 使用jquery来实现二层嵌套的左侧列表&#xff0c;点击后显示右侧内容的效果。 二、思路&#xff1a; 为一级列表项和二级子列表项分别添加了点击事件处理程序。当一级列表项被点击时&#xff0c;使用.slideToggle()方法展开或收起对应的二级子列表项。…

Unity项目包体优化经验方法论(Android平台)

前言 本篇文章主要讲解对于Unity Android平台也就是APK包体的优化经验&#xff0c;使用哪些工具能够更加便利的定位资源重灾区。本篇讲解的方法中对于Unity资源使用的AssetBundle的方式&#xff0c;如果使用addressable或其他资源管理方式&#xff0c;我还不是很清楚是否适用&…

Midjourney学习(四)光源类型prompt

序号类别光线名称英文名称描述用途示例1光线质地硬光Hard Light直接照射在主题上&#xff0c;产生明显的阴影和高对比度。强调轮廓&#xff0c;增加照片的戏剧性2光线质地软光/柔光Soft Light光线经过散射或扩散&#xff0c;产生柔和的阴影和低对比度。平滑细节&#xff0c;适合…

SQL注入案例

目录 一、简介 二、案例 1.发现注入点 2.寻找注入类型 3.寻找字段数 4.将传参值设为超出数据量的大值&#xff0c;联合查询找到回显位置 5.找到数据库 6.寻找库中的表 7.寻找表中列 8.查看表中数据 附&#xff1a;SQLMap注入 1.输入指令查数据库 2.输入指令查表 3…

物联网智慧种植农业大棚系统

一、项目背景 智慧农业是是将物联网技术和农业生产箱管理的新型农业&#xff0c;依托部署在农业生产现场的各种传感节点&#xff0c;以物联网网关为通道形成数据传输网络&#xff0c;可以实现控制柜、环境监测传感器、气象监测机器等设备的远程监控&#xff0c;达到及时高校的…