1.Lambd表达式
Lambda表达式是简洁化的语法定义代码块。目的是弥补Java无法函数式编程的缺点。用其可以的进行代码块的传递,使代码更加简洁。
注意:使用Lambd表达式实现的接口一定是函数式接口(@functional interface)。但这个函数式接口并不用记,应为它基本上也没有什么用,只需要记忆哪个方法需要传递一段怎样的代码实现功能,如下面这段代码是用了表达式n->n==1
。
ArrayList<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
list.removeIf(n->n==1);//简便运算,其实不需要知道函数式接口的概念,直接当成函数块使用就行
System.out.println(list);
前面的n是表示一个形参,后面的n==1
是一个条件,表示 如果集合中的元素满足这个条件就把元素从集合中删除。
他在Java中实际是一个匿名内部类的形式,只不过是代码看起来简洁了而已,如果把它还原了,它是:
list.removeIf(new Predicate<Integer>() {
@Override
public boolean test(Integer n) {
return n==1;
}
});
再从原本的匿名内部类的形式,通过简化的方式一步步简化。
- 先把它写成标准的Lambd表达式,由形参
Integer n
,箭头->
,和代码块{return false;}
三部分组成。
list.removeIf ((Integer n)->{return false;});
- 表达式中形参的类型是可以推断出来的(和集合的类型一致),可以省略
list.removeIf ((n)->{return false;});
- 形参只有一个,外面的括号可以省略(注意:没有形参的也要写
()
表示空参,只有刚好一个参数才可以省略)
list.removeIf (n->{return false;});
- 如果代码块内的代码只有一行,可以直接写这一行(
return
不用写)
list.removeIf (n->n==1);
这样就一步步简化成了这样了,其实写的时候只需要知道可以简化的地方,然后直接写最终结果就可以,这样可以使代码更加简洁,但他的本质还是匿名内部类。
如果传递的函数是想实现某个已经实现的功能,可以使用
::
(双冒号)引用对应的方法。
2.什么是多态
Java三大核心思想之一,就是指子类的对象可以赋值给父类的变量(向上转型,就是指子类可以使用父类的名字),但在使用的过程中有一些注意事项:
如果子类使用父类的名字
- 只能获取到父类的成员变量
- 只能使用父类的成员方法(但是实际执行的还是子类的方法,只是无法使用子类中新创建的方法)
如果要使用子类的特有变量和方法,就必须将子类的对象强制类型转换(也就是向下转型)回到子类。
3.黑窗口运行Hello world
public class Text {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
- 使用记事本写入上述代码
- 打开cmd,输入
javac Text.java
编译(注意此处一定要写.java后缀) - 输入
java Text
翻译运行程序 (注意此处不要写.class后缀)
4.引用数据类型
基本数据类型有(四类八种)
-
整型
-
byte
8 = 1*8(1字节8位) -
short
16 = 2*8(2字节16位,下面类似) -
int
32 = 4*8 -
long
64 = 8*8
-
-
浮点型
-
float
32 = 4*8 -
double
64 = 8*8
-
-
布尔型
boolean
布尔类型,只有两个值true
和false
-
字符型
char
用来存储单个字符,用单引号包围。
除了以上基本数据类型以外的所有类型都是引用数据类型,典型的有String字符串和enum枚举常量
5.关于foreach
也叫做增强For,格式如下:
for(内部变量类型 内部变量名 : 数组或者集合名)
{
//代码
}
如:
- 数组遍历
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i : arr) {
System.out.println(i);
}
- 集合遍历
//ArrayList<Integer> list
for (Integer integer : list) {
System.out.println(integer);
}
foreach是普通for的简化版,没有了索引与结束条件。使代码更加简化。但是要注意foreach遍历基本数据类型时,用的是临时变量存储其数据,不能修改基本数据类型的数据。如:
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i : arr) {
i = 0;
}
这个赋值是错误的,修改的仅仅是 i
这个临时变量,并没有修改arr
数组的内部,最后的数组仍然是arr = {1, 2, 3, 4, 5, 6, 7, 8, 9}
6.Scanner获取数据的方法
Scanner sc = new Scanner(System.in);
System.in 标准输入流,控制台的输入
sc.next数据类型()
读取对应数据类型,返回指定数据,以 '指定数据后的空白字符' 为终止,前面的空白字符自动过滤
sc.next()
读取数据,以 '数据后的空白字符' 为终止,前面的空白字符自动过滤,返回String
sc.nextLine()
读取一行,回车结束,返回String
为了确保输入正确,一般来说sc.nextLine()
与前面的方法不混合使用。
7.java可编译的两种程序类型
-
Applet(小程序):编译后通过Applet View或支持Java的WWW浏览器来运行的程序 ,自JDK11开始删除了Applet支持,已淘汰。
-
Application(应用程序):在操作系统环境下可以直接运行的程序。
public static void main(String[] args)
是Java应用程序的标志,同时也是应用程序的主入口。
8.排序对象
-
如果是数组排序
使用数组工具
Arrays.sort()
-
如果是集合排序
使用集合的处理工具
Collections.*sort*();
,也可以直接调用集合内的sort方法集合.sort()
一般排序方式是使用快速排序,默认为顺序排序,也可以自己实现比较器Comparator
接口,实现函数,提供比较方法,自定义排序
9.常用容器
-
ArrayList
最常用的容器,有索引,有序,可重复
-
HashSet
无索引,无序,不可重复
-
TreeSet
无索引,有序,不可重复,方便增删查改,但是添加时的效率不高,底层采用数组哈希表、链表以及红黑树。
-
HashMap
键值对,键是唯一的,键与值一一对应,值可以重复
-
TreeMap
键值对,键是唯一的,键与值一一对应,值可以重复,方便增删查改,但是添加时的效率不高
10.抽象类
-
抽象类的定义是为了声明类里面至少有一个抽象方法。
-
抽象方法是没有确定下来的方法,没有函数体,只有函数的名字参数以及返回值,需要子类继承后重写来进行实现。
-
不可直接调用抽象方法,不可直接创建抽象类的对象。抽象类的子类要么重写所有的抽象方法,要么也声明为抽象类。(如果希望子类可以不用实现某个方法,可以用default关键字修饰这个方法)
11.权限修饰符
(默认)
: 同一个包里的类可以访问
public
: 最大的权限修饰符,公共的,任何地方都可以访问
private
: 最小的权限修饰符,私有的,只有自己(本类)才能使用
protected
: 为了解决private 一个问题(如果被private修饰,任何其他的类都不能访问,包括自己的子类),但是有时候我们又希望自己的子类也能访问,所以就出现了protected 。适用于不想让外界访问,但是希望子类继承的类型。
12.this和super为什么不能连用
这个问题我感觉有点问题,更详细的的问法应该是this和super的构造方法为什么不能连用。
这样一想其实就简单了,因为他们本身就有一层关系,在使用this的构造方法一般会默认执行super(),执行父类的初始化。你要是在用一个super(),不就是重复初始化了嘛。
13.Scanner为什么要关闭
使用完输入流,及时关闭可以释放内存、节约内存占用.但是一般Scanner是使用System.in进行输入,使用scanner.close
方法相当于System.in.close()
。关闭系统输入流,一般是不建议关闭,除非是你从这行代码之后再也不用系统的输入,即控制台输入。
14.异常处理
异常处理的的一般方式:try...catch(异常)...finally
try包含着的代码如果抛出了异常,会被catch捕获,执行catch内部的代码(异常解决方案)
catch捕获的前提是:catch括号内的异常包含抛出的异常,即catch括号内的异常就是抛出异常或者是抛出异常的父类(上级)。
此外,不管try内的代码有没有抛出异常,都会执行finally的代码。(如果抛出了异常会在catch代码执行完成后执行finally)
注:1. 如果要把retuen语句写在try...catch(异常)...finally异常处理体系中,需要在try和catch区域中分别写出return,
- 并且如果程序执行到try或者catch中的return时,如果有finally,会先执行finally内的代码,再去执行return,如下面的代码:
public static int function() {
try{
if (false) throw new RuntimeException(); //此处代表代码没有抛出异常
return 1;
}catch (RuntimeException e){
System.out.print("catch,");
return -1;
}finally {
System.out.print("finally,");
}
}
这个函数的执行结果(print的输出的信息)是finally,
返回值为1。
public static int function() {
try{
if (true) throw new RuntimeException(); //此处代表一个一定会报错的代码
return 1;
}catch (RuntimeException e){
System.out.print("catch,");
return -1;
}finally {
System.out.print("finally,");
}
}
这个函数的执行结果是catch,finally,
返回值为-1。
那么如果finally
中也有return呢?(答:和前面的结论一样,他一定会从finally
中的return返回,因为在程序执行到try或者catch中的return语句时,就会跳转到finally
中,不管程序是否抛出异常,必然会先执行finally
中的return)
private static int function() {
try {
if (true) {
throw new RuntimeException();
}
return 1;
} catch (RuntimeException e) {
System.out.print("catch");
return -1;
} finally {
System.out.print("finally");
return 0;
}
}
这个函数的执行结果是catch,finally,
返回值为0。
private static int function() {
try {
if (false) {
throw new RuntimeException();
}
return 1;
} catch (RuntimeException e) {
System.out.print("catch");
return -1;
} finally {
System.out.print("finally");
return 0;
}
}
这个函数的执行结果是finally,
返回值为0。
网友评论