1、用函数对象表示策略
什么是函数对象?实际上这是在JDK8之前没有Java不支持lamda表达式,方法参数不能传递一个方法只能通过传递对象的方式“曲线救国”,例如Arrays.sort(T[] a, Comparator<? super T> c)方法,第一个参数传递数组,根据传入第二个自定义的比较类中的比较方法进行排序。如果能传入函数指针、Lambda表达式等,那就自然不用传递一个类。
从JDK8开始Java已经支持了lambda表达式,不妨简单了解下JDK8的lambda表达式。
广义上来讲JDK8中lambda表达式有两个部分组成:一是lambda表达式本身,二是函数式接口。函数式接口实际上就是指只包含一个抽象方法的接口,比如Runnable接口只包含run抽象方法。而lambda表达式本身实际上则是对抽象方法的实现。
首先lambda表达式的语法格式如下所示:
例如
(n)->System.out.println(n);
表示打印n。
上面提到lambda是对抽象方法的实现,那么实际上这条lambda表达式对应的就是:
public void demo(String n){
System.out.println(n);
}
lambda表达式不过是一个匿名方法实现而已,接下来我们看看到底是如何使用lambda表达式。
/**
* 函数式接口,只包含一个抽象方法
*/
public interface LambdaDemo {
void demo(String n);
}
/**
* lambda例子
*/
public class App {
public static void main( String[] args ) {
LambdaDemo lambdaDemo = (n) -> System.out.println(n); //实例化LambdaDemo类,同时也lambda表达式实现了demo方法
lambdaDemo.demo("hello lambda");
}
}
2、优先使用静态成员类
一般情况下我们可能提到最多的是“内部类”这个名词,实际上在类“内部”的类叫做“嵌套类”。嵌套类分为四种:静态成员类、非静态成员类、匿名类和局部类。除了静态成员类,其余三种才被称之为内部类。
匿名类提及的比较多:
public class App {
public static void main( String[] args ) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个内部类");
}
}); //回顾一下lambda表达式,可表示为Thread thread = new Thread(() -> System.out.println("这是一个内部类"));
thread.start();
}
}
静态成员类相比较于非静态成员类就是多了一个static关键字修饰类,另外一个更重要的区别在于非静态成员类的每个实例都包含一个额外的指向外围对象的引用,保存这份引用要耗费时间和空间。
举个例子,在JDK7中,HashMap内部使用Entry类表示每个键-值对,这个类是static静态的,如果将static去掉仍然可以工作,但每个entry中将会包含一个指向该Map的引用,这样就浪费了空间和时间。
那么什么时候使用静态什么时候使用非静态呢?
书中给出了比较明确的原则:如果声明成员类不要求访问外围实例,就要始终把static修饰符放在它的声明中。也就是说如果成员类和外围实例类有交互,那这个类就应该是非静态的,如果没有交互而是作为外围类的一个组件存在在应使用静态的。
最后一个是局部类,只要是在任何“可以声明局部变量的地方”,都可以声明局部类,用得最少,如果要使用那也必须非常简短。