java 鍵盤輸入冒泡排序_j2se学习中的一些零碎知识点4之字符串,数组和异常(使用数组实现冒泡排序算法和选择排序以及二分法查...

1、什么是异常?在程序运行过程中出现的错误。异常模拟的是现实世界中“不正常”的事件。

java中采用“类”去模拟异常。类是可以创建对象的。

NullPointException e = 0x1234; e是引用类型,e是保存的内存地址指向堆中的“对象”。这个对象是一定是NullPointException类型,这个对象就表示真实存在的异常事件。NullPointException是一类异常。(比如,“抢劫”就是一类异常,“张三被抢劫”是一个异常事件。)

int a = 10; int b = 0; int c = a/b;以上程序编译通过了,但是运行时出现了异常,表示发生了某个异常事件。JVM虚拟机向控制台输出如下信息:

7fd82e7d91e9873c0f05bf737bd6035b.png

这表明程序执行过程中发生了算数异常这个事件,JVM虚拟机为我们创建了一个ArithmeticException类型的对象。并且这个对象中包含了详细的异常信息,JVM会将这个对象中的信息打印输出到控制台中。

异常处理机制的作用?

java语言为我们提供了一种完善的异常处理机制,即程序发生异常事件之后,为我们输出详细的信息,程序员通过这个信息,可以对程序进行一些处理,使程序更加健壮。

2、异常的继承结构图

cb3e91a09561da0ba15d0caba2e79cef.png

3、处理异常的第一种方式:声明抛出throws,以下程序演示声明抛出,在方法声明的位置上使用throws关键字向上抛出异常。

package com.geeklicreed.j2se;

import java.io.*;

public class ExceptionTest03{

public static void main(String[] args) {

//创建文件输入流,读取文件

FileInputStream fis = new FileInputStream("c:/abc.txt");

}

}

以上程序编译不通过,原因是java.io.FileInputStream类的构造方法抛出了FileNotFoundException异常:

public FileInputStream(String name) throws FileNotFoundException {

this(name != null ? new File(name) : null);

}

FileNotFoundException异常类继承自IOException异常类(IOException异常类属于编译时异常类,因为是Exception类的直接子类),属于编译时异常。

修改后的代码为:

package com.geeklicreed.j2se;

import java.io.*;

public class ExceptionTest03{

public static void main(String[] args) throws FileNotFoundException{ //或者是IOException

//创建文件输入流,读取文件

//思考:java编译器是如何知道以下的代码执行过程中可能会出现异常

//java编译器是如何知道这个异常发生的几率比较高呢?

//java编译器不是那么智能,因为FileInputStream这个构造方法在声明的位置上使用了throws FileNotFoundException;

FileInputStream fis = new FileInputStream("c:/abc.txt");

}

}

使用throws处理异常不是真正的处理异常而是推卸责任,谁调用的就会抛给谁。(上抛直到抛给了JVM虚拟机,JVM虚拟机遇到这个异常就会退出程序,之后的代码并不会执行。)

需要注意的是,重写的方法无法比被重写的方法抛出更宽泛的异常。

import java.io.*;

class A{

public void m1(){}

}

class B enteds A{

//子类永远无法抛出比父类更宽泛的异常,编译无法通过

public void m1() throws Exception{}

}

import java.io.*;

class A{

public void m1() throws FileNotFoundException{}

}

class B enteds A{

//子类永远无法抛出比父类更宽泛的异常,编译无法通过

public void m1() throws Exception{}

}

4、处理异常的第二种方式:捕捉异常。

语法:

try{可能出现异常的代码;

}catch{ 处理异常的代码;

}catch{ 处理异常的代码;}

需要注意,catch语句块可以指定多个,但是必须从上到下,从小到大进行捕捉。

catch语句块提供的异常参数需要对try块中可能出现异常的代码做对应的处理。(catch语句块中的异常参数可以是要处理异常类的父类)

try...catch...中最多执行1个catch语句块,执行结束之后try..catch...就结束。

public static void main(String[] args){

try {

//程序执行到此处发生FileNotFoundException类型的异常。

//JVM会自动创建一个FileNotFoundException类型的对象,将该对象的内存地址赋值给catch语句块中的e变量

FileInputStream fis = new FileInputStream("abc");

//上面的代码出现异常,try语句块中的代码将不再继续执行,直接进入catch语句块中执行

System.out.println("TTTTTTTTT");

fis.read();

} catch (FileNotFoundException e) { //e内存地址指向堆中的那个对象是“FileNotFoundException类型”的异常事件

System.out.println("读取的文件不存在");

//FileNotFoundException将Object中的toString方法重写

System.out.println(e); //java.io.FileNotFoundException:abc(系统找不到指定的文件)

} catch (Exception e) {

System.out.println("其他IO异常");

}

}

5、关于Throwable接口中的getMessage()和printStackTrace()方法的应用。

printStackTrace()方法打印异常堆栈信息,一般情况下都会使用这种方式去调试程序。

getMessage()方法只是printStackTrace()方法打印异常信息的一部分,并不详细,只是提醒出现的异常信息,不显示异常出错代码的位置。

6、关于finally语句块:finally语句块可以直接与try语句块连用,如try...finally...。也可以和try语句和catch语句块连用,如try...catch...finally...也可以。(在finally语句块中的代码一定会执行。)

System.exit(0); --> 这个语句表示退出JVM。(只要在执行finally语句块前退出JVM,则finally语句块不会执行。)

finally语句块中是一定会执行的,所以通常在程序中为了保证某资源一定会释放,所有一般在finally语句块中释放资源。

7、自定义异常:有两种方式,编译时异常(Exception)和运行时异常(RuntimeException)。

package com.geeklicreed.j2se;

public class IllegalNameException extends Exception{

//public class IllegalNameException extends RuntimeException{ //运行时异常

//定义异常一般提供两个构造方法

public IllegalNameException() {

}

public IllegalNameException(String msg) {

super(msg);

}

}

手动抛出异常,使用throw关键字,后面跟创建的异常类对象。

package com.geeklicreed.j2se;

public class CustomerService{

//对外提供一个注册的方法

public void register(String name) throws IllegalNameException {

//完成注册

if(name.length() < 6){

//手动抛出异常

throw new IllegalNameException("用户名长度不能少于6位");

}

//如果代码能够执行到此处,证明用户名是合法的

System.out.println("注册成功!");

}

}

测试程序:(如果用户提供的用户名字符串长度小于6个,则捕获异常信息)

package com.geeklicreed.j2se;

public class Test {

public static void main(String[] args) {

//假如用户提供的用户名如下:

String username = "geeklicreed";

//注册

CustomerService cs = new CustomerService();

try {

cs.register(username);

} catch (IllegalNameException e) {

System.out.println(e.getMessage());

}

}

}

8、数组是一种引用类型,数组是一种简单的数据类型,线性的结构,数组是一个容器(可以用来存储其他的元素,数组是可以存储任意数据类型的元素。)

数组可以分为:一维数组,二维数组和多维数组。(数组中存储的元素类型是统一的,每一个元素在内存中所占的空间大小是相同的。)

//声明一个一维数组,用来存储int类型

int[] a1 = {100, 200, 150, 300}; //这种方式称之为“静态初始化一维数组”

数组拿首元素的内存地址作为数组对象的内存地址,a1引用中保存的是一维数组的首元素的内存地址。

数组长度不可改变,数组一旦创建长度是不可变的,固定的。

数组中每一个元素都是有下标的(有索引),从0开始,任何一个数组都有一个length属性用来获取数组中元素的个数。(数组最后一个元素的下标是数组的长度减去1,即a1.length -1。)

取得第一个元素:a1[0];如何取得最后一个元素:a1[a1.length -1]。(数组中通过元素的下标获取元素。)

数组的优缺点:

数组优点是查找效率高。知道数组的首元素的内存地址,要查找的元素只要知道下标就可以快速的计算出偏移量,通过首元素内存地址加上偏移量快速地计算出要查找元素的内存地址,通过内存地址快速定位该元素,所以数组查找元素的效率比较高。

数组的缺点是随意的增删元素效率低。当增加元素的时候,为了保证数组中元素在空间存储上是有序的,所以被添加元素位置后面的所有元素都要向后移动。删除元素也是,后面所有的元素都要向前移动,所以数组的增删元素的效率较低。

初始化一维数组另一种方式:动态初始化。(动态初始化一维数组,会先在内存中分配这个数组,并且在数组中每一个元素都采用默认值。)

//引用类型的数组

Object[] objs = new Object[3];

for(int index = 0; index < objs.length; index++){

Object o = objs[index];

//o.toString(); //注意空指针异常,因为引用类型的数组默认值是null

System.out.println(o); // null null null

}

//动态声明一个int类型的数组,最多可以存储4个元素

int[] a1 = new int[4];

J2SE中的println源码:

public void println(Object x){

String s = String.valueOf(x);

synchronized(this){

print(s);

newLine();

}

}

public static String valueOf(Object obj){

return (obj == null) ? "null" : obj.toString();

}

什么时候使用动态初始化,什么时候使用静态初始化?

a、无论是动态初始化还是静态初始化,最终的内存分布都是一样的;b、如果在创建数组的时候,知道数组中应该存储什么数据,这个时候当然采用静态初始化方式;如果在创建数组的时候,无法预测到数组中存储什么数据,只是先开辟空间,则使用动态初始化方式。

方法调用的时候,可以这样传递一个数组:

package com.geeklicreed.j2se;

public class ArrayTest06{

public static void main(String[] args){

//第一种方式

int[] a = {12,3,4,5,6};

m1(a);

//第二种方式

m1(new int[]{34,5,6,7,8,10});

}

public static void m1(int[] a){

for(int i = 0; i < a.length; i++){

System.out.println(a[i]);

}

}

}

9、关于main方法中的参数列表String [] args:String[] args是专门用来接收命令行参数的。例如:java ArrayTest abc def ,JVM在调用ArrayTest类的main方法之前,先把“abc def”这个字符串以“空格”的方式分隔,然后存储在String数组中。(String类型的数组中元素的个数是args.length。)

关于数组的拷贝:System.arraycope(源数组, 源数组的开始下标, 目标数组, 目标数组的开始下标, 拷贝的长度);

b97ffd73284b279aa8c71565b6a383fb.png

二维数组的特点:二维数组是一个特殊的一维数组,特殊在于这个一维数组中每一个元素都是一维数组。

静态初始化二维数组:int [] [] a = {{1,2,3},{45,34},{0},{10,23,85,99}},获取第1个一维数组a[0],获取第1个一维数组中的第1个元素a[0][0],获取最后一个一维数组中的最后一个元素a[a.length-1][a[a.length -1].length-1]。

二维数组的动态初始化:

package com.geeklicreed.j2se;

public class ArrayTest06{

public static void main(String[] args){

m1(new int[][]{{1,23,4},{5,6,7,8},{10,9}});

}

public static void m1(int[][] a){

for(int i = 0; i < a.length; i++){

for(int j = 0; j < a[i].length; j++){

System.out.println(a[i][j] + " ");

}

System.out.println();

}

}

}

10、如何接收用户的键盘输入:(Scanner为扫描器类)

package com.geeklicreed.j2se;

import java.util.Scanner;

public class KeyInput {

public static void main(String[] args) {

Scanner s = new Scanner(System.in);

//程序执行到此处,停下来,等待用户的输入

String userInput = s.next();

System.out.println("您输入了:" + userInput);

}

}

11、使用一维数组模拟栈的数据结构:

自定义Stack类:

package com.geeklicreed.j2se;

//栈:后进先出

public class Stack {

//使用数组存储数据

//栈可以存储多个引用类型的元素

Object[] elements;

//指向栈顶元素上方的一个帧

int index;

//栈默认的初始化容量是5

Stack(){

this(5);

}

Stack(int max){

elements = new Object[max];

}

//栈应该对外提供一个压栈的方法

public void push(Object element) throws StackOperationException{

if(index == elements.length){

//异常

throw new StackOperationException("栈已满");

}

/*elements[index] = element;

index++;*/

elements[index++] = element;

}

//栈应该对外提供一个弹栈的方法

public Object pop()throws StackOperationException{ //从栈顶的元素往外弹

if(index == 0){

throw new StackOperationException("栈已空");

}

/*index--;

return elements[index];*/

return elements[--index];

}

}

栈出现异常StackOperationException类:

package com.geeklicreed.j2se;

public class StackOperationException extends Exception {

public StackOperationException() {

}

public StackOperationException(String msg) {

super(msg);

}

}

测试类Test的代码:

package com.geeklicreed.j2se;

public class Test {

public static void main(String[] args) {

Stack s = new Stack();

User user1 = new User("JACK",20);

User user2 = new User("SMITH",21);

User user3 = new User("FORD",22);

User user4 = new User("KING",23);

User user5 = new User("COOK",24);

try {

//压

s.push(user1);

s.push(user2);

s.push(user3);

s.push(user4);

s.push(user5);

} catch (StackOperationException e) {

e.printStackTrace();

}

try {

//弹

System.out.println(s.pop());

System.out.println(s.pop());

System.out.println(s.pop());

System.out.println(s.pop());

System.out.println(s.pop());

System.out.println(s.pop());

} catch (Exception e) {

e.printStackTrace();

}

}

}

需要用到的实体类:

package com.geeklicreed.j2se;

public class User {

String name;

int age;

public User(String name, int age) {

super();

this.name = name;

this.age = age;

}

public String toString() {

return "User [name=" + name + ", age=" + age + "]";

}

}

运行测试类Test的控制台打印结果:

e40125f35e9c2f0a1772885240637b52.png

12、使用数组实现冒泡排序算法:

e886c2532dd8fbe447059dd58b24a9b3.png

package com.geeklicreed.j2se;

public class BubbleSort {

public static void main(String[] args) {

int[] a = {3, 1, 6, 2, 5};

//开始排序

for(int i = a.length -1 ; i > 0; i--){

for(int j = 0; j < i; j++){

if(a[j] > a[j + 1]){

//交换位置

int temp;

temp = a[j];

a[j] = a[j + 1];

a[j + 1] = temp;

}

}

}

//遍历

for(int i = 0; i < a.length; i++){

System.out.println(a[i]);

}

}

}

13、使用数组实现选择排序算法:找出最小值,然后这个最小值和最前面的数据交换位置。

package com.geeklicreed.j2se;

public class SelectSort {

public static void main(String[] args) {

int[] a = {3, 1, 6, 2, 5};

//选择排序

for(int i = 0; i < a.length -1; i++){

//假设第一个数据是最小值

//记录最小值元素的下标

int min = i;

for(int j = i + 1; j < a.length; j++){

if(a[min] > a[j]){

//给min重新赋值

min = j;

}

}

//考虑交换位置

if(min != i){

int temp;

temp = a[i];

a[i] = a[min];

a[min] = temp;

}

}

//输出

for(int i = 0; i < a.length; i++){

System.out.println(a[i]);

}

}

}

14、二分法(折半法)查找:二分法查找是建立在已经排序的基础之上的,以下程序分析从小到大进行排序。(并且这个数组中没有重复的元素)

数组[1, 3, 5, 9. 11, 13, 56],以上是一个已经排好序的int类型的数组,要求快速找出13这个元素的下标。

0a42159cde78aa6bce8a8806c9637508.png

package com.geeklicreed.j2se;

public class MyArrays {

public static void main(String[] args) {

int[] a = {1, 3, 4, 5, 7, 8, 9, 10, 23, 25, 29};

int destElement = 10;

//要求从a数组中查找10这个元素的下标

int index = binarySearch(a, destElement); //如果找到则返回元素的下标,如果找不到则统一返回。

System.out.println((index == -1)? destElement + "元素不存在!" : destElement + "在数组中的下标是:" + index);

}

//折半查找的核心算法

private static int binarySearch(int[] a, int destElement) {

int begin = 0;

int end = a.length - 1;

while(begin <= end){

int mid = (begin + end) /2;

if(a[mid] == destElement){

return mid;

}else if(a[mid] > destElement){

end = mid - 1;

}else if(a[mid] < destElement){

begin = mid + 1;

}

}

return -1;

}

}

Arrays是SUM提供的一个工具类,(java.util.Arrays)该工具类主要针对的是数组的操作,包括排序、二分法查找等。

15、java.lang.String;是字符串类型,字符串一旦创建将不可再改变。“abc”字符串对象一旦创建,不可以再改变成“abcd”。

String s = "abc"; s = "def"; 创建一个“abc”字符串对象,该对象的内存地址,让s变量保存。s是一个引用,s指向"abc"对象。(s是局部变量,s前面没有final修饰,所以s可以重新指向。)

为了提升字符串的访问效率,在程序中使用“缓存”技术,所以在java中所有使用“双引号”括起来的字符串都会在“字符串缓存池”中创建一份。字符串常量池在方法区中被存储。

在程序执行过程中,如果程序用到某个字符串,例如"abc",那么程序会在字符串常量池中搜索该字符串,如果没有找到则在字符串常量池中新建一个"abc"字符串,如果找到就直接拿过来使用。(字符串常量池是一个缓存区,以此来提高访问字符串的效率。)

String s1 = "Hello";String s2 = "Hello";System.out.println(s1 == s2);(打印为“true”,首先在字符串常量池中新建一个“Hello”字符串对象,该对象不可变,然后在字符串常量池中直接拿过来使用)。

String s3 = new String("abc"); String s4 = new String("abc"); System.out.println(s3 == s4);(这两个对象使用new关键字创建,在堆中开辟空间,这两个对象的内存地址不相等。)

比较两个字符串是否一致,必须使用String类提供的equals方法。

以下程序在执行结束之后,会在字符串常量池中创建3个字符串对象。"aaa"、"bbb"、"aaabbb":

String s5 = "aaa"; String s6 = "bbb"; String s7 = "aaa" + "bbb";

String s1 = "abc";只会在字符串常量池中创建一个"abc"字符串对象。String s2 = new String("hello");会在字符串常量池中创建一个"hello"字符串对象,并且会在堆中在创建字符串对象(常用的是第一种方式,第二种方式比较耗费内存。)

16、使用String的时候我们应该注意的问题:尽量不要做字符串频繁的拼接操作。因为字符串一旦创建不可改变,只要频繁拼接,就会在字符串常量池中创建大量的字符串对象,给垃圾回收带来问题。

关于字符串常用的方法:

package com.geeklicreed.j2se;

public class StringTest {

public static void main(String[] args) {

// 1、char charAt(int index)

String s1 = "为什么遇到如此强大的敌人都不愿意逃跑--因为身后,有自己的至爱!";

char c1 = s1.charAt(2);

System.out.println(c1); // 么

// 2、boolean endsWith(String endStr);

System.out.println("HelloWorld.java".endsWith("java")); // true

System.out.println("HelloWorld.java".endsWith(".java")); // true

System.out.println("HelloWorld.java".endsWith("HelloWorld.java")); // true

System.out.println("HelloWorld.java".endsWith("txt")); // false

// 3、boolean equalsIgnoreCase(String anotherString)

System.out.println("abc".equalsIgnoreCase("ABc")); // true

// 4、byte[] getBytes();

byte[] bytes = "abc".getBytes();

for (int i = 0; i < bytes.length; i++) {

System.out.println(bytes[i]); // 97 98 99

}

// 5、int indexOf(String str);

System.out

.println("http://192.168.1.100:8080/oa/login.action?username=geeklicreed&pwd=123"

.indexOf("/oa")); // 25

// 6、int lastIndexOf(String str)

System.out.println("javaoraclec++javaweb".lastIndexOf("java")); // 13

// 7、int length();

System.out.println("abc".length()); // 3

// 8、String replaceAll(String s1, String s2);

System.out.println("javaoraclec++javaweb".replaceAll("java", "mysql")); // mysqloraclec++mysqlweb

// 9、String[] split(String s);

String myTime = "2008,08,08";

String[] ymd = myTime.split(",");

for (int i = 0; i < ymd.length; i++) {

System.out.println(ymd[i]); // 2008 08 08

}

// 10、boolean startsWith(String s);

System.out.println("/system/login.action".startsWith("/")); // true

// 11、String substring(int begin);

System.out.println("/oa/login.action".substring(3)); // /login.action

// 12、String substring(int begin, int endIndex);

System.out.println("/oa/login.action".substring(4, 9)); // login

// 13、char[] tocharArray();

char[] c2 = "我是邓金明".toCharArray();

for (int i = 0; i < c2.length; i++) {

System.out.println(c2[i]); // 我 是 邓 金 明

}

// 14、转换成大写

System.out.println("Abcdef".toUpperCase()); //ABCDEF

// 15、转换成小写

System.out.println("ABCDEF".toLowerCase()); //abcdef

// 16、String trim();

System.out.println(" abc def ".trim()); //abc def

// 17、String valueOf(Object obj);

Object o = null;

System.out.println(String.valueOf(o)); // null

}

}

17、正则表达式:1、正则表达式是一门独立的学科;2、正则表达式是一种字符模型,专门做字符串格式匹配的;3、正则表达式是通用的。(不详细介绍)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值