1.lambda表达式
区别于js的箭头函数,python、cpp的lambda表达式,java8的lambda是一个匿名函数,java8运行把函数作为参数传递进方法中。
-
语法格式
(parameters) -> expression 或 (parameters...) ->{ statements; }
-
实战
-
替代匿名内部类:java8之前如果想把方法传给函数(动态传递参数),那么需要匿名内部类
-
Runnable
接口new Thread(new Runnable() { @Override public void run() { System.out.println("The runable now is using!"); } }).start(); //用lambda new Thread(() -> System.out.println("It's a lambda function!")).start();
特性 静态传参 动态传参 参数数量 固定:编译时确定 可变:调用时可以变化 方法定义 参数数量和类型明确指定 参数用 ...
形式声明,数量可变适用场景 当参数数量固定时 当参数数量不确定时 调用方式 需要按照方法定义传递确切的参数数量 可以传递任意数量的同类型参数 例子 void method(int a, int b)
void method(int... numbers)
-
Comparator
接口List<Integer> strings = Arrays.asList(1, 2, 3); Collections.sort(strings, new Comparator<Integer>) { @Override public int compare (Integer o1, Integer o2) { return o1 - o2; } } Collections.sort(strings, (Integer o1, Integer o2) -> o1 - o2);
-
Listener
接口JButton button = new JButton(); button.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { e.getItem(); } }); //lambda button.addItemListener(e -> e.getItem());
-
不难发现这些匿名内部类只重写了接口的一个方法,当然也只有一个方法要重写。这就是上文提到的函数式接口,也就是说只要方法的参数是函数式接口就可以用lambda表达式。
-
自定义一个,java中的lambda就是减少实例化类这一步
public class lambda { @FunctionalInterface public interface LambdaInterface { void f(); } //使用 public static class LambdaClass { public static void forEg() { lambdaInterfaceDemo(() -> System.out.println("自定义函数式接口")); } //函数式接口参数 static void lambdaInterfaceDemo(LambdaInterface i) { i.f(); } } public static void main(String[] args) { LambdaClass.forEg(); } }
-
-
集合迭代
void lamndaFor() { List<String> strings = Arrays.asList("1", "2", "3"); //传统foreach for (String s : strings) { System.out.println(s); } //Lambda foreach strings.forEach((s) -> System.out.println(s)); //or strings.forEach(System.out::println); //map Map<Integer, String> map = new HashMap<>(); map.forEach((k,v)->System.out.println(v)); }
-
方法的引用
-
静态方法的引用
类名::静态方法
package lambda; import java.util.Arrays; public class reference { public static void main(String[] args) { Student[] s = new Student[6]; s[0] = new Student("张三", 18, "男", "北京"); s[1] = new Student("李四", 19, "男", "上海"); s[2] = new Student("王五", 20, "男", "广州"); s[3] = new Student("赵六", 21, "男", "深圳"); s[4] = new Student("孙七", 22, "男", "武汉"); s[5] = new Student("周八", 23, "男", "西安"); // lambda表达式,传入函数作为参数, 如果参数和调用的函数参数是一样的,才可以使用静态函数引用 Arrays.sort(s, (o1, o2) -> o1.getAge() - o2.getAge()); // 将类的静态方法作为引用,传送给函数式接口 Arrays.sort(s, Student::compareByAge); } }
package lambda; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class Student { private String name; private int age; private String gender; private String address; public static int compareByAge(Student s1, Student s2) { return s1.getAge() - s2.getAge(); } }
实例方法
package lambda; import java.util.Arrays; public class reference { public static void main(String[] args) { Student[] s = new Student[6]; s[0] = new Student("张三", 18, "男", "北京"); s[1] = new Student("李四", 19, "男", "上海"); s[2] = new Student("王五", 20, "男", "广州"); s[3] = new Student("赵六", 21, "男", "深圳"); s[4] = new Student("孙七", 22, "男", "武汉"); s[5] = new Student("周八", 23, "男", "西安"); // lambda表达式,传入函数作为参数, 如果参数和调用的函数参数是一样的,才可以使用静态函数引用 Arrays.sort(s, (o1, o2) -> o1.getAge() - o2.getAge()); Student s1 = new Student(); // 将类的静态方法作为引用,传送给函数式接口 Arrays.sort(s, s1::compareByAge); } }
特定类的调用
public void Demo3 { public static void main(String[] args) { String[] names = {"Tom", "Cat", "Jerry"}; } // Arrays.sort(names); // 默认按照首字母的升序排序 // 忽略字母大小写升序 如果是特定类型的实例方法,以及是对应类方法 // Arrays.sort(names, (o1, o2) -> o1.compareToIgnore(o2)); Arrays.sort(names, String::compareToIgnore); System.out.println(Array.toString(names)); }
构造方法
class Car{ String name; String getName() { return this.name; } } interface CarFactory { Car getCar(String name); } // CarFactory cf = new CarFactory { // @override // public Car getCar(String name); // return new Car(name); //} // CarFactory cf = name -> new Car(name); CarFactory cf = Car::new; Car c1 = cd.getCar();
-
-
-
这些方法是可遇不可求的,一般都是重构写出来的代码。
2.Interface
背景:
-
传统接口的缺点:
-
一旦接口需要修改或增加方法,实现该接口的所有类都需要进行改动**。例如,假设
Animal
接口增加了一个新的方法eat()
,那么所有已经实现Animal
接口的类 (Dog
、Cat
等) 都必须去实现这个新增加的方法,否则代码会报错。 -
这给代码的维护和扩展带来了很大的问题,尤其当你有很多实现类时,修改接口将变得代价非常高昂。
-
-
default
修饰的方法,是普通的实例方法,可以用this
调用,也可以被子类继承、重写。 -
static
修饰的方法,使用上和一般的类静态方法一样。但它不能被子类继承、重写。 -
private
修饰的方法,接口内部类才可以使用
例子:
public interface InterfaceNew {
static void sm() {
System.out.println("interface提供的方式实现");
}
static void sm2() {
System.out.println("interface提供的方式实现");
}
default void def() {
System.out.println("interface default方法");
}
default void def2() {
System.out.println("interface default2方法");
}
//须要实现类重写
void f();
}
public interface InterfaceNew1 {
default void def() {
System.out.println("InterfaceNew1 default方法");
}
}
因为两个接口没有继承关系,如果不重写def函数会编译出错
public class InterfaceNewImpl implements InterfaceNew , InterfaceNew1{
public static void main(String[] args) {
InterfaceNewImpl interfaceNew = new InterfaceNewImpl();
interfaceNew.def();
}
@Override
public void def() {
InterfaceNew1.super.def();
}
@Override
public void f() {
}
}
- 抽象类和接口的区别
-
interface 和 class 的区别,好像是废话,主要有:
- 接口多实现,类单继承
- 接口的方法是 public abstract 修饰,变量是 public static final 修饰。 abstract class 可以用其他修饰符
-
interface 的方法是更像是一个扩展插件。而 abstract class 的方法是要继承的。
- functional interface接口
- 也称SAM接口,既只有一个抽象方法的接口,在java8中有一个专门存放函数式接口的包
java.util.function
,该包下的所有接口都有@FunctionalInterface
注解,提供函数式编程,提醒编译器,如果不是SAM接口解报错。
- 也称SAM接口,既只有一个抽象方法的接口,在java8中有一个专门存放函数式接口的包
3.stream流
-
实例
package stream; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class demo1 { public static void main(String[] args) { // 目标:认证stream流 List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("java"); list.add("hello"); list.add("hello"); // 1.常规方法 List<String> newList = new ArrayList<>(); for (String name : list) { if (name.startsWith("h") && name.length() != 1) { newList.add(name); } } System.out.println(newList); // 2.stream流 List<String> list2 = list.stream().filter(name -> name.startsWith("h")) .filter(name -> name.length() != 1) .collect(Collectors.toList()); System.out.println("------------------"); System.out.println(list2); } }
3.1获取Stream流
-
Stream流是一个接口
package stream; import java.util.*; import java.util.stream.Stream; public class demo2 { public static void main(String[] args) { // 1.获取stream流 // 获取集合里的stream流可以调用stream方法 List<String> list = new ArrayList<>(); Stream<String> s1 = list.stream(); // 2.map Map<String, Integer> map = new HashMap<>(); // 获取键流 Stream<String> s2 = map.keySet().stream(); // 获取值流 Stream<Integer> s3 = map.values().stream(); // 获取键值对流 entrySet把map转为set集合 Stream<Map.Entry<String, Integer>> s4 = map.entrySet().stream(); Set<Map.Entry<String, Integer>> test = new HashMap<String, Integer>().entrySet(); // 3.数组 两种方式 String[] arr = {"hello", "world", "java"}; Stream<String> s5 = Arrays.stream(arr); System.out.println(s5.count()); // 计数 System.out.println(s5.max(Comparator.comparingInt(String::length))); Stream<String> s6 = Stream.of("hello", "world", "java"); } }
3.2处理stream流
-
返回值是一个新流
package stream; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Stream; public class demo3 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("java"); list.add("hello"); // 1.过滤方法 foreach将每个遍历出的元素塞给方法内。 list.stream().filter(name -> name.startsWith("h") && name.length() != 1) .forEach(System.out::println); // 2.排序方法 List<Double> list1 = new ArrayList<>(); list1.add(1.2); list1.add(2.3); list1.add(3.4); list1.add(1.2); // double可以排是因为里面实现了compare方法 默认是升序 list1.stream().sorted().forEach(System.out::println); System.out.println("------------------"); list1.stream().sorted((s1, s2) -> Double.compare(s2, s1)).forEach(System.out::println); // 只要前两名 System.out.println("------------------"); list1.stream().sorted().limit(2).forEach(System.out::println); // 跳过前两名 System.out.println("------------------"); list1.stream().sorted().skip(2).forEach(System.out::println); // 去重 如果需要自定义对象能够去重要重写hashCode和equals方法 System.out.println("------------------"); list.stream().distinct().forEach(System.out::println); // 映射方法, 把原来的数据拿出来加工并返回新流 System.out.println("------------------"); list1.stream().map(s -> s * 2).forEach(System.out::println); // 合并 List<String> list2 = new ArrayList<>(); list2.add("hello"); list2.add("world"); list2.add("java"); Stream<String> list3 = list2.stream(); Stream<String> list4 = list2.stream(); Stream<String> s3 = Stream.concat(list4, list3); System.out.println(s3.count()); } }
-
如果需要自定义对象能够去重要重写hashCode和equals方法
-
映射方法, 把原来的数据拿出来加工并返回新流
-
都是一个个方法,记住就好,看源码收益低
3.3终结stream流
-
抽象方法就是没实现的方法
package stream; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class demo4 { public static void main(String[] args) { // 创建一个教师列表并添加教师对象 List<Teacher> teachers = new ArrayList<>(); teachers.add(new Teacher("张三", 18, 3000)); teachers.add(new Teacher("李四", 19, 4000)); teachers.add(new Teacher("王五", 20, 5000)); teachers.add(new Teacher("赵六", 21, 6000)); teachers.add(new Teacher("钱七", 22, 7000)); // 使用流的收集操作: // 过滤出工资大于4000的教师,并打印他们的信息 teachers.stream() .filter(teacher -> teacher.getSalary() > 4000) // 过滤条件 .forEach(System.out::println); // 打印符合条件的教师,自动调用toString方法 // count long count = teachers.stream().filter(teacher -> teacher.getSalary() > 4000).count(); System.out.println("~~~~~~~~~~~~~~"); // 放到Optional<T>中防止空指针异常 Optional<Teacher> max = teachers.stream().max(Teacher::compareTo); Teacher teacher = max.get(); System.out.println(teacher.getName() + " " + teacher.getAge() + " " + teacher.getSalary()); } }
-
添加到集合中
package stream; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; public class demo4 { public static void main(String[] args) { // 收集到数组或者集合上 List<String> test = new ArrayList<>(); test.add("hello"); test.add("world"); Stream<String> s1 = test.stream().filter(s -> s.length() > 1); // 收集到List集合 // Collectors.toList()返回一个ArrayList对象,明确调用了一个Collector的实现,明确使用ArrayList调用方法 List<String> list = s1.collect(Collectors.toList()); System.out.println(list); System.out.println("~~~~~~~~~~~~~~"); // 收集到Set集合,流终止后不能再使用 List<String> test2 = new ArrayList<>(); test2.add("hello"); test2.add("world"); Set<String> set = test2.stream().filter(s -> s.length() > 1).collect(Collectors.toSet()); System.out.println(set); // 收集到数组中 两个版本的toArray,参数是数组的构造器,默认返回的类型是Object[] Stream<String> s2 = test2.stream().filter(s -> s.length() > 1); String[] arr = s2.toArray(String[]::new); // Objects[] arr1 = s2.toArray(); System.out.println(Arrays.toString(arr)); // 收集到Map集合中,需要指定key和value的类型,否则会报错 List<Teacher> list2 = new ArrayList<>(); list2.add(new Teacher("张三", 18, 3000)); list2.add(new Teacher("李四", 19, 4000)); list2.add(new Teacher("王五", 20, 5000)); list2.add(new Teacher("赵六", 21, 6000)); list2.add(new Teacher("钱七", 22, 7000)); Map<String, Integer> map = list2.stream().collect(Collectors.toMap(Teacher::getName, Teacher::getAge)); System.out.println(map); } }
-
可以看到toList调用的是ArrayList
-
每个方法都有默认的构造方法,按需调用即可