Lambda是一个匿名函数,可以理解为一段可以(像数据一样)传递的代码。可以使代码更简介更灵活
使用lambda表达式有4个知识点
()->{}
,只有函数式接口才能使用这种格式函数式接口接口只能有一个抽象方法
、可以有多个default
和static
方法这样的接口才能算是函数式接口
接口中只有一个方法声明
,例如Runnable
接口,可以使用lambda表达式
使用方式 ()->{}
new Thread(()->{System.out.println("lambda表达式测试");},"lambda").start();
//Runable来自java.lang没有返回值
Runnable runnable=()->{ System.out.println("lambda测试"); };
//Callable来自java.util.concurrent 有返回值,需要有一个泛型,例如传入Integer作为泛型
Callable<Integer> callable=()->{return 1;};
java8中,接口如果只有一个方法声明,则会默认在编译的过程中会加上
@FunctionalInterface
注解,相当于隐式的声明
例如
@FunctionalInterface
interface demo{
int add(int x,int y);
}
java8中允许在接口内写实现好的方法,但需要加上default声明
,实现的方法允许多个,但只能有一个方法声明没有实现。
@FunctionalInterface
interface demo{
int add(int x,int y);
//允许多个default声明的方法实现
default int sub(int x,int y){
return x - y;
}
default int sub_reverse(int x,int y){
return y - x;
}
}
java8中还允许有多个static声明的方法
@FunctionalInterface
interface demo{
int add(int x,int y);
//多个static
static double div(int x,int y){
return x / y;
}
static int muti(int x,int y){
return x * y;
}
}
都在java.util.function
包下
函数式接口 | 参数列表 | 返回类型 | 用途 |
---|---|---|---|
Consumer |
T | void | 对类型T的对象应用和操作,包含方法void accept(T t) |
Supplier |
无 | void | 返回类型为T的对象,包含方法T get() |
Function |
T | R | 对类型T的对象应用和操作并返回结果R,包含方法R apply(T t) 以及default声明的实现方法 |
Predicate |
T | boolean | 确定类型T的对象是否满足约束,包含方法boolean test(T t) |
//Consumer 消费型接口 :
@Test
public void test1(){
happy(10000, (m) -> System.out.println("每次消费:" + m + "元"));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
//Supplier 供给型接口 :
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
for (Integer num : numList) {
System.out.println(num);
}
}
//需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
//Function 函数型接口:
@Test
public void test3(){
String newStr = strHandler("\t\t\t 尚硅谷威武 ", (str) -> str.trim());
System.out.println(newStr);
String subStr = strHandler("尚硅谷威武", (str) -> str.substring(2, 5));
System.out.println(subStr);
}
//需求:用于处理字符串
public String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}
//Predicate 断言型接口:
@Test
public void test4(){
List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
for (String str : strList) {
System.out.println(str);
}
}
//需求:将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if(pre.test(str)){
strList.add(str);
}
}
return strList;
}
同理java8中还内置了截图中的这些函数式接口
具体的内容查看java.util.function
包下面的接口内容
方式一、 集合类,实现了Collection类的子类都可以创建集合类,通过集合自带的stram方法获取
1、ArrayList
(初始容量10,达到扩容因子则会扩容至原先的1.5倍)
2、CopyOnWriteArrayList
(解决多线程写入同一个ArrayList异常的解决方案、上个线程还没写入成功就被另一个线程写入。抛出java.util.ConcurrentModificationException
异常)
为了让其出
java.util.ConcurrentModificationException
异常,则在线程类内部加个等待200毫秒,这样必出异常
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(200);//让其必出异常做的等待
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(UUID.randomUUID().toString().substring(0, 3));
System.out.println(list.size()+""+list);
}, String.valueOf(i)).start();
}
}
3、LinkedList
(链表初始容量0,没有最大容量)
4、Vector
(初始容量10、和ArrayList一样的最大值。区别是add方法加了synchronized
是线程安全的,但是这种方式对性能损耗太大!线程安全使用CopyOnWriteArrayList
解决问题最好,不使用Vector
,除非是个小程序不需要考虑性能问题)
5、HashSet
(底层是HashMap)
6、CopyOnWriteArraySet
与CopyOnWriteArrayList
一样的作用是为了解决多线程安全问题设置的
7、HashMap
(初始容量1左移4位就是 24=16
,最大容量230,超过了则设置为Integer.MAX_VALUE
也就是231。看后面截图,容量因子0.75达到了容量因子则会扩容,会扩容到原先的2倍)
Integer.MAX_VALUE=0x7fffffff
也就是2的31次方
8、ConcurrentHashMap
(和前面一样为了解决java.util.ConcurrentModificationException
异常)
9、TreeMap
(是一种红黑树,关于TreeMap看到一篇博客,里面有详细讲解https://www.jianshu.com/p/2dcff3634326)
Collections是集合的一个工具类
List排序
void reverse(List list): //反转
void shuffle(List list), //随机排序
void sort(List list), //按自然排序的升序排序
void sort(List list, Comparator c); //定制排序,由Comparator控制排序逻辑
void swap(List list, int i , int j) //交换两个索引位置的元素
void rotate(List list, int distance) /*旋转。当distance为正数时,
将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面。*/
List搜索和替换
//对List进行二分查找,返回索引,注意List必须是有序的
int binarySearch(List list, Object key)
//根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
int max(Collection coll),
//根据定制排序,返回最大元素,排序规则由Comparatator类控制。
//类比int min(Collection coll, Comparator c)
int max(Collection coll, Comparator c)
void fill(List list, Object obj) //用元素obj填充list中所有元素
int frequency(Collection c, Object o) //统计元素出现次数
/* 统计targe在list中第一次出现的索引,找不到则返回-1,
类比int lastIndexOfSubList(List source, list target).*/
int indexOfSubList(List list, List target)
boolean replaceAll(List list, Object oldVal, Object newVal)// 用新元素替换旧元素。
Collection是一个接口,定义了上面ArrayList这类集合类的接口。对于实现Collection接口,子类都可以使用Collections对集合进行一系列操作。
//方式一、通过集合的方式获取,也就是上面记录的
List<String> list=new ArrayList<>();
Stream<String> stream1 = list.stream();
//方式二、Arrays的静态方法stream()获取
Integer[] integers=new Integer[10];
Stream<Integer> stream2 = Arrays.stream(integers);
//方式三、Stream的静态方法of
Stream<Integer> stream3 = Stream.of(12, 13, 14);
//方式四、创建无限流
//1、迭代
Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);
stream4.limit(10).forEach(System.out::println);//流进行操作,限制流的数量
//2、生成
Stream.generate(()-> Math.random()).limit(5).forEach(System.out::println);
筛选和切片
filter
传入一个断言接口
例如获取奇数,过滤偶数,按照三步
创建流 操作流 终止流
//1、创建流
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);//可以将数字换成对象,然后泛型改成对应的对象即可
//2、操作流
/*可以换成对应的比较,比如 对象::getXXX==某个值 或者>,<这类比较,
使用的是Predicate断言接口,boolean test(T t);。*/
Stream<Integer> integerStream = integers.stream().filter((e) -> e % 2 == 1);
//3、终止流,进行输出
integerStream.forEach(System.out::println);//输出 1 3 5
截断流
limit
limit会造成短路现象,也就是当limit达到条件时之后的迭代操作就不会生效
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);//可以讲数字换成对象,然后泛型改成对应的对象即可
Stream<Integer> integerStream = integers.stream().filter((e) -> e % 2 == 1).limit(1);//可以换成对应的比较,比如对象.getXXX判断
integerStream.forEach(System.out::println);//只输出 1
跳过
skip
跳过,这个好理解,跳过前面的指定多少条记录
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);//可以讲数字换成对象,然后泛型改成对应的对象即可
Stream<Integer> integerStream = integers.stream().filter((e) -> e % 2 == 1).skip(1).limit(1);//可以换成对应的比较,比如对象.getXXX判断
integerStream.forEach(System.out::println);//只输出 3
去重
distinct
去重
List<Integer> integers = Arrays.asList(1, 1, 2, 3, 4, 5);//可以讲数字换成对象,然后泛型改成对应的对象即可
Stream<Integer> integerStream = integers.stream().filter((e) -> e % 2 == 1).distinct().skip(1).limit(1);//可以换成对应的比较,比如对象.getXXX判断
integerStream.forEach(System.out::println);//只输出 3
映射
map
需要传入一个Function接口,会将集合的每一个元素都应用到函数式接口的参数上
如果将下面的"aaa","bbb"换成对象,可以在map传入对象::getXXX来将指定的字段提取出来
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");//可以讲数字换成对象,然后泛型改成对应的对象即可
list.stream().map((str) -> {
return str.toUpperCase();}
).forEach(System.out::println);
两天内会将其补充完全。
flatMap
将多个流合并成一个大流