精华内容
下载资源
问答
  • Java中的增强for循环的实现原理与坑

    千次阅读 2018-04-13 11:08:43
    JAVA中,遍历集合和数组一般有以下三种形式:for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i) + ",");}Iterator iterator = list.iterator();while (iterator....

    在JAVA中,遍历集合和数组一般有以下三种形式:


    for (int i = 0; i < list.size(); i++) {
       System.out.print(list.get(i) + ",");
    }

    Iterator iterator = list.iterator();
    while (iterator.hasNext()) {
       System.out.print(iterator.next() + ",");
    }

    for (Integer i : list) {
       System.out.print(i + ",");
    }


    第一种是普通的for循环遍历、第二种是使用迭代器进行遍历,第三种我们一般称之为增强for循环(for each)。

    实现原理


    可以看到,第三种形式是JAVA提供的语法糖,这里我们剖析一下,这种增强for循环底层是如何实现的。


    我们对以下代码进行反编译


    for (Integer i : list) {
       System.out.println(i);
    }


    反编译后:


    Integer i;
    for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
       i = (Integer)iterator.next();        
    }

    反编译后的代码其实比较复杂,我们按照执行顺序拆解一下:

    Integer i; 定义一个临时变量i

    Iterator iterator = list.iterator(); 获取List的迭代器

    iterator.hasNext(); 判断迭代器中是否有未遍历过的元素

    i = (Integer)iterator.next(); 获取第一个未遍历的元素,赋值给临时变量i

    System.out.println(i) 输出临时变量i的值

    如此循环往复,直到遍历完List中的所有元素。


    通过反编译,我们看到,其实JAVA中的增强for循环底层是通过迭代器模式来实现的。


    增强for循环的坑

    这里说是增强for循环的坑,其实主要是因为有些人不了解增强for循环的实现原理而可能踩入的坑。


    既然增强for循环通过迭代器实现,那么必然有迭代器的特性。


    Java中有fail-fast机制。在使用迭代器遍历元素的时候,在对集合进行删除的时候一定要注意,使用不当有可能发生ConcurrentModificationException,这是一种运行时异常,编译期并不会发生。只有在程序真正运行时才会爆发。


    如以下代码:


    for (Student stu : students) {    
       if (stu.getId() == 2)     
           students.remove(stu);    
    }


    会抛出ConcurrentModificationException异常。


    Iterator是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出

    java.util.ConcurrentModificationException异常。

    所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。


    但你可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。


    正确的在遍历的同时删除元素的姿势:


    Iterator<Student> stuIter = students.iterator();    
    while (stuIter.hasNext()) {    
       Student student = stuIter.next();    
       if (student.getId() == 2)    
           stuIter.remove();//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException    
    }


    好啦,这里给你介绍了增强for循环的实现原理,以及使用不当可能踩入的坑。所以,虽然是一个简单的for-each语法,但是也要了解其原理,不然可能导致一些莫名其妙的问题。


    转载自:http://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650121134&idx=1&sn=a34a1bd547f00e479e9f6dbde8848fe4&chksm=f36bbe8fc41c3799d1bb2c781f81f51e28651d2fb8eb5670a31caac5ba782b66416e5fdf1b1c&mpshare=1&scene=1&srcid=0413o4rBaecPGUVy6Bi9lzt7#rd

    展开全文
  • Java循环语句

    千次阅读 2014-04-21 21:01:21
    Java循环语句有for,while 和 do-while 。这些语句创造了我们通常所称的循环(loops)。你可能知道,一个循环重复执行同一套指令直到一个结束条件出现。你将看到,Java 有适合任何编程所需要的循环结构。 ...

    Java的循环语句

    Java 的循环语句有for,while 和 do-while 。这些语句创造了我们通常所称的循环(loops)。你可能知道,一个循环重复执行同一套指令直到一个结束条件出现。你将看到,Java 有适合任何编程所需要的循环结构。

    1、 while 语句

    while 语句是Java 最基本的循环语句。当它的控制表达式是真时,while 语句重复执行一个语句或语句块。它的通用格式如下:
    while(condition) {
    // body of loop 

    条件condition 可以是任何布尔表达式。只要条件表达式为真,循环体就被执行。当条件condition 为假时,程序控制就传递到循环后面紧跟的语句行。如果只有单个语句需要重复,大括号是不必要的。
    下面的while 循环从10开始进行减计数,打印出10行“tick”。
    // Demonstrate the while loop.
    class While {
    public static void main(String args[]) {
    int n = 10; 
    while(n > 0) {
    System.out.println("tick " + n);
    n--; 
    }
    }
    }

    当你运行这个程序,它将“tick”10次:
    tick 10 
    tick 9 
    tick 8 
    tick 7 
    tick 6 
    tick 5 
    tick 4 
    tick 3 
    tick 2 
    tick 1 
    因为while 语句在循环一开始就计算条件表达式,若开始时条件为假,则循环体一次也不会执行。例如,下面的程序中,对println( ) 的调用从未被执行过:
    int a = 10, b = 20;
    while(a > b)
    System.out.println("This will not be displayed");
    while 循环(或Java 的其他任何循环)的循环体可以为空。这是因为一个空语句(null statement) (仅由一个分号组成的语句)在Java 的语法上是合法的。例如,下面的程序:
    // The target of a loop can be empty.
    class NoBody {
    public static void main(String args[]) {
    int i, j;
    i = 100; 
    j = 200; 
    // find midpoint between i and j
    while(++i < --j) ; // no body in this loop 
    System.out.println("Midpoint is " + i);
    }
    }
    该程序找出变量i和变量j的中间点。它产生的输出如下:
    Midpoint is 150
    该程序中的while 循环是这样执行的。值i自增,而值j自减,然后比较这两个值。如果新的值i仍比新的值j小,则进行循环。如果i等于或大于j,则循环停止。在退出循环前,i 将保存原始i和j的中间值(当然,这个程序只有在开始时i比j小的情况下才执行)。正如你看到的,这里不需要循环体。所有的行为都出现在条件表达式自身内部。在专业化的Java 代码中,一些可以由控制表达式本身处理的短循环通常都没有循环体。

    2、 do-while 循环

    如你刚才所见,如果while 循环一开始条件表达式就是假的,那么循环体就根本不被执行。然而,有时需要在开始时条件表达式即使是假的情况下,while 循环至少也要执行一次。换句话说,有时你需要在一次循环结束后再测试中止表达式,而不是在循环开始时。幸运的是,Java 就提供了这样的循环:do-while 循环。do-while 循环总是执行它的循环体至少一次,因为它的条件表达式在循环的结尾。它的通用格式如下:
    do {
    // body of loop
    } while (condition); 
    do-while 循环总是先执行循环体,然后再计算条件表达式。如果表达式为真,则循环继续。否则,循环结束。对所有的Java 循环都一样,条件condition 必须是一个布尔表达式。下面是一个重写的“tick”程序,用来演示do-while 循环。它的输出与先前程序的输出相同。
    // Demonstrate the do-while loop.
    class DoWhile {
    public static void main(String args[]) {
    int n = 10; 
    do {
    System.out.println("tick " + n);
    n--; 
    } while(n > 0);
    }
    }
    该程序中的循环虽然在技术上是正确的,但可以像如下这样编写更为高效:
    do {
    System.out.println("tick " + n); 
    } while(--n > 0); 
    在本例中,表达式“-- n > 0 ”将n值的递减与测试n是否为0组合在一个表达式中。它的执行过程是这样的。首先,执行-- n 语句,将变量n递减,然后返回n的新值。这个值再与0比较,如果比0大,则循环继续。否则结束。
    do-while 循环在你编制菜单选择时尤为有用,因为通常都想让菜单循环体至少执行一次。下面的程序是一个实现Java 选择和重复语句的很简单的帮助系统:
    // Using a do-while to process a menu selection
    class Menu {
    public static void main(String args[])
    throws java.io.IOException {
    char choice; 
    do {
    System.out.println("Help on:");
    System.out.println(" 1. if");
    System.out.println(" 2. switch");
    System.out.println(" 3. while");
    System.out.println(" 4. do-while");
    System.out.println(" 5. for\n");
    System.out.println("Choose one:");
    choice = (char) System.in.read();
    } while( choice < '1' || choice > '5');
    System.out.println("\n");
    switch(choice) {
    case '1': 
    System.out.println("The if:\n");
    System.out.println("if(condition) statement;");
    System.out.println("else statement;");
    break;
    case '2': 
    System.out.println("The switch:\n");
    System.out.println("switch(expression) {");
    System.out.println(" case constant:");
    System.out.println(" statement sequence");
    System.out.println(" break;");
    System.out.println(" // ...");
    System.out.println("}");
    break;
    case '3': 
    System.out.println("The while:\n");
    System.out.println("while(condition) statement;");
    break; 
    case '4': 
    System.out.println("The do-while:\n");
    System.out.println("do {"); 
    System.out.println(" statement;");
    System.out.println("} while (condition);");
    break; 
    case '5': 
    System.out.println("The for:\n");
    System.out.print("for(init; condition; iteration)");
    System.out.println(" statement;");
    break; 
    }
    }
    }
    下面是这个程序执行的一个样本输出:
    Help on:
    1. if 
    2. switch 
    3. while 
    4. do-while 
    5. for 
    Choose one: 

    The do-while: 
    do {
    statement;
    } while (condition); 
    在程序中,do-while 循环用来验证用户是否输入了有效的选择。如果没有,则要求用户重新输入。因为菜单至少要显示一次,do-while 循环是完成此任务的合适语句。
    关于此例的其他几点:注意从键盘输入字符通过调用System.in.read( ) 来读入。这是一个Java 的控制台输入函数。尽管Java 的终端 I/O (输入/输出)方法将在第12章中详细讨论,在这里使用System.in.read ( ) 来读入用户的选择。它从标准的输入读取字符(返回整数,因此将返回值choice 定义为字符型)。默认地,标准输入是按行进入缓冲区的,因此在你输入的任何字符被送到你的程序以前,必须按回车键。
    Java 的终端输入功能相当有限且不好使用。进一步说,大多数现实的Java 程序和Applets (小应用程序)都具有图形界面并且是基于窗口的。因此,这本书使用终端的输入并不多。然而,它在本例中是有用的。另外一点:因为使用System.in.read ( ) ,程序必须指定throws java.io.IOException 子句。这行代码对于处理输入错误是必要的。这是Java 的异常处理的一部分,将在第10章讨论。

    3、 for 循环

    在第2章曾使用过一个for循环的简单格式。你将看到,for循环是一个功能强大且形式灵活的结构。下面是for 循环的通用格式:
    for(initialization; condition; iteration) {
    // body
    } 
    如只有一条语句需要重复,大括号就没有必要。
    for循环的执行过程如下。第一步,当循环启动时,先执行其初始化部分。通常,这是设置循环控制变量值的一个表达式,作为控制循环的计数器。重要的是你要理解初始化表达式仅被执行一次。下一步,计算条件condition 的值。条件condition 必须是布尔表达式。它通常将循环控制变量与目标值相比较。如果这个表达式为真,则执行循环体;如果为假,则循环终止。再下一步执行循环体的反复部分。这部分通常是增加或减少循环控制变量的一个表达式。接下来重复循环,首先计算条件表达式的值,然后执行循环体,接着执行反复表达式。这个过程不断重复直到控制表达式变为假。
    下面是使用for 循环的“tick”程序:
    // Demonstrate the for loop.
    class ForTick {
    public static void main(String args[]) {
    int n; 
    for(n=10; n>0; n--)
    System.out.println("tick " + n);
    }
    }
    在for 循环中声明循环控制变量
    控制for循环的变量经常只是用于该循环,而不用在程序的其他地方。在这种情况下,可以在循环的初始化部分中声明变量。例如,下面重写了前面的程序,使变量 n 在for循环中被声明为整型:
    // Declare a loop control variable inside the for.
    class ForTick {
    public static void main(String args[]) { 
    // here, n is declared inside of the for loop
    for(int n=10; n>0; n--)
    System.out.println("tick " + n);
    }
    }
    当你在for 循环内声明变量时,必须记住重要的一点:该变量的作用域在for语句执行后就结束了(因此,该变量的作用域就局限于for 循环内)。在for循环外,变量就不存在了。如果你在程序的其他地方需要使用循环控制变量,你就不能在for循环中声明它。
    由于循环控制变量不会在程序的其他地方使用,大多数程序员都在for循环中来声明它。例如,以下为测试素数的一个简单程序。注意由于其他地方不需要i,所以循环控制变量i在for循环中声明。
    // Test for primes.
    class FindPrime {
    public static void main(String args[]) {
    int num;
    boolean isPrime = true; 
    num = 14; 
    for(int i=2; i <= num/2; i++) {
    if((num % i) == 0) {
    isPrime = false; 
    break;
    }
    }
    if(isPrime) System.out.println("Prime");
    else System.out.println("Not Prime");
    }
    }
    使用逗号
    你可能经常需要在初始化和for循环的反复部分包括超过一个变量的声明。例如,考虑下面程序的循环部分:
    class Sample {
    public static void main(String args[]) {
    int a, b;
    b = 4; 
    for(a=1; a<b; a++) {
    System.out.println("a = " + a);
    System.out.println("b = " + b);
    b--; 
    }
    }
    }
    如你所看到的,循环被两个相互作用的变量控制。由于循环被两个变量控制,如果两个变量都能被定义在for 循环中,而变量b不需要通过人工处理将是很有用的。幸好,Java 提供了一个完成此任务的方法。为了允许两个或两个以上的变量控制循环,Java 允许你在for 循环的初始化部分和反复部分声明多个变量,每个变量之间用逗号分开。
    使用逗号,前面的for循环将更高效,改写后的程序如下:
    // Using the comma.
    class Comma {
    public static void main(String args[]) {
    int a, b; 
    for(a=1, b=4; a<b; a++, b--) {System.out.println("a = " + a);System.out.println("b = " + b);
    }
    }
    }
    在本例中,初始化部分把两个变量a和 b都定义了。在循环的反复部分,用两个逗号分开的语句在每次循环重复时都执行。程序输出如下:
    a = 1 
    b = 4 
    a = 2 
    b = 3
    注意:如果你对C/C++ 熟悉,你就会知道逗号是一个运算符,能在任何有效的表达
    式中使用。然而,在Java 中不是这样。在 Java 中,逗号仅仅是一个分隔符,只
    适用于for循环。

    4、 for 循环的一些变化

    for循环支持一些变化,这增加了它的功能和灵活性。for循环这样灵活是因为它的3部分(初始化部分,条件测试部分和反复部分)并不仅用于它们所限定的那些目的。事实上,for 循环的3部分能被用于你需要的任何目的。让我们看一些例子。
    最普通的变化之一包含在条件表达式中。具体地说,条件表达式可以不需要用循环变量和目标值的比较来测试循环条件。事实上,控制for 循环的条件可以是任何布尔表达式。例如,考虑下列程序片段:
    boolean done = false;
    for(int i=1; !done; i++) {
    // ...
    if(interrupted()) done = true;
    }
    在本例中,for循环将一直运行,直到布尔型变量done 被设置为真。for循环的条件部分不测试值i。
    下面是for循环的另外一个有趣的变化。在Java 中可以使for循环的初始化、条件或者反复部分中的任何或者全部都为空,如下面的程序:
    // Parts of the for loop can be empty.
    class ForVar {
    public static void main(String args[]) {
    int i;
    boolean done = false;
    i = 0;
    for( ; !done; ) {
    System.out.println("i is " + i);
    if(i == 10) done = true;
    i++;}}
    }
    本例中,初始化部分和反复部分被移到了for 循环以外。这样,for循环的初始化部分和反复部分是空的。当这个简单的例子中,for循环中没有值,确实,这种风格被认为是相当差的,有时这种风格也是有用的。例如,如果初始条件由程序中其他部分的复杂表达式来定义,或者循环控制变量的改变由发生在循环体内的行为决定,而且这种改变是一种非顺序的方式,这种情况下,可以使for 循环的这些部分为空。
    下面是for 循环变化的又一种方式。如果for循环的三个部分全为空,你就可以创建一个无限循环(从来不停止的循环)。例如:
    for( ; ; ) {
    // ... 

    这个循环将始终运行,因为没有使它终止的条件。尽管有一些程序,例如操作系统命令处理器,需要无限循环,但大多数“无限循环”实际上是具有特殊终止要求的循环。在不久你将看到如何不用正常的条件表达式来终止这种类型的循环。
    5、 循环嵌套
    和其他编程语言一样,Java 允许循环嵌套。也就是,一个循环在另一个循环之内。例如,下面的程序就是循环嵌套:
    // Loops may be nested.
    class Nested {
    public static void main(String args[]) {
    int i, j; 
    for(i=0; i<10; i++) {
    for(j=i; j<10; j++)
    System.out.print(".");
    System.out.println();
    }
    }
    }
    该程序产生的输出如下所示:
    . . . . . . . . . . 
    . . . . . . . . . 
    . . . . . . . . 
    . . . . . . . 
    . . . . . . 
    . . . . . 
    . . . . 
    . . . 
    . . 


    转载自:http://dev.21tx.com/2005/03/24/12536.shtml

    展开全文
  • JAVA中,遍历集合和数组一般有以下三种形式: for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i) + ","); } Iterator iterator = list.iterator(); while (iterator.hasNext()) { ...

    在JAVA中,遍历集合和数组一般有以下三种形式:

    for (int i = 0; i < list.size(); i++) {
       System.out.print(list.get(i) + ",");
    }
    
    Iterator iterator = list.iterator();
    while (iterator.hasNext()) {
       System.out.print(iterator.next() + ",");
    }
    
    for (Integer i : list) {
       System.out.print(i + ",");
    }
    

    第一种是普通的for循环遍历、第二种是使用迭代器进行遍历,第三种我们一般称之为增强for循环(for each)。

    (一)、实现原理

    可以看到,第三种形式是JAVA提供的语法糖,这里我们剖析一下,这种增强for循环底层是如何实现的。
    我们对以下代码进行反编译:

    for (Integer i : list) {
       System.out.println(i);
    }
    

    反编译后:

    Integer i;
    for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
       i = (Integer)iterator.next();        
    }
    

    反编译后的代码其实比较复杂,我们按照执行顺序拆解一下:

    Integer i; 定义一个临时变量i
    
    Iterator iterator = list.iterator(); 获取List的迭代器
    
    iterator.hasNext(); 判断迭代器中是否有未遍历过的元素
    
    i = (Integer)iterator.next(); 获取第一个未遍历的元素,赋值给临时变量i
    
    System.out.println(i) 输出临时变量i的值
    

    如此循环往复,直到遍历完List中的所有元素。

    通过反编译,我们看到,其实JAVA中的增强for循环底层是通过迭代器模式来实现的。

    (二)、增强for循环的坑

    这里说是增强for循环的坑,其实主要是因为有些人不了解增强for循环的实现原理而可能踩入的坑。

    既然增强for循环通过迭代器实现,那么必然有迭代器的特性。

    Java中有fail-fast机制。在使用迭代器遍历元素的时候,在对集合进行删除的时候一定要注意,使用不当有可能发生ConcurrentModificationException,这是一种运行时异常,编译期并不会发生。只有在程序真正运行时才会爆发。

    如以下代码:

    for (Student stu : students) {    
       if (stu.getId() == 2)     
           students.remove(stu);    
    }
    

    会抛出ConcurrentModificationException异常。
    Iterator是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出java.util.ConcurrentModificationException异常。

    所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。

    但你可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

    正确的在遍历的同时删除元素的姿势:

    Iterator<Student> stuIter = students.iterator();    
    while (stuIter.hasNext()) {    
       Student student = stuIter.next();    
       if (student.getId() == 2)    
           stuIter.remove();//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException    
    }
    

    好啦,这里给你介绍了增强for循环的实现原理,以及使用不当可能踩入的坑。所以,虽然是一个简单的for-each语法,但是也要了解其原理,不然可能导致一些莫名其妙的问题。

    展开全文
  • java递归和循环

    万次阅读 2018-12-21 12:56:44
    方案1:使用循环 方案2:使用递归 递归:递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。 StackOverflowError:当应用程序递归太深而发生堆栈溢出时,抛出该错误。 ...

    功能:求1-100的累加和

    • 方案1:使用循环
      • 方案2:使用递归
      • 递归:递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。
      • StackOverflowError:当应用程序递归太深而发生堆栈溢出时,抛出该错误。
      • 递归结构
      • 1:递归尽头:什么时候不调用自己,如果没有头,将陷入死循环
      • 常见的递归头:就是if判断
      • 2:递归体
      • 什么时候需要调用自身方法。
      • 注意:就算没有递归头,java中递归不会无限的递归下去,递归太深,堆栈内存会溢出
      • 递归次数和计算机本身的硬件有关系,以及程序本身,
      • 计算机越好,次数越多
      • 程序越简单,次数越多
      • 面试题:循环个递归区别?
      • 递归算法:
      • 优点:代码简洁、清晰,并且容易验证正确性。(如果你真的理解了算法的话,否则你更晕)
      • 缺点:它的运行需要较多次数的函数调用,如果调用层数比较深,需要增加额外的堆栈处理,比如参数传递需要压栈等操作,会对执行效率有一定影响。但是,对于某些问题,如果不使用递归,那将是极端难看的代码。
      • 循环算法:
      • 优点:速度快,结构简单。
      • 缺点:并不能解决所有的问题。有的问题适合使用递归而不是循环。如果使用循环并不困难的话,最好使用循环。
      • 递归算法 和循环算法总结
      • 一般递归调用可以处理的算法,也通过循环去解决常需要额外的低效处理 。
      • 现在的编译器在优化后,对于多次调用的函数处理会有非常好的效率优化,效率未必低于循环。
    
    public class Demo {
    
    	
    	
    	 static int i=1;
    	
    	public static void show(int sum){
    		sum=sum+i; //业务代码1
    		//递归头
    		if(i==100){
    			System.out.println(sum);
    			return;
    		}
    		i++;   //业务代码2
    		show(sum); //递归体
    	}
    	
    	
    	public static void main(String[] args) {
    		int sum = 0;
    		show(sum);
    	}
    
    }
    
    
    package Test;
    /*编写递归算法程序:一列数的规则如下
    : 1、1、2、3、5、8、13、21、34...... 求数列的第40位数是多少*/
    public class homeWork {
    	public static void main(String[] args) {
    		System.out.println("第40位是"+homeWork.show(40));
    		
    	}
    	public static int show(int i){
    		if(i<0){
    			return 0;
    		}
    		else if(i>0&&i<2){
    			return 1;
    		}
    			
    		return show(i-1)+show(i-2);
    	}
    }
    
    

    利用递归删除多级目录结构

     *  1:根目录结构是a
     *  2:判断节点是否是目录
     *  3:如果是文件,直接删除
     *  4:如果不是文件,遍历目录
     *  5:判断遍历后的每一个子节点是否为文件夹,如果不是文件夹,直接删除,如果是文件夹,继续
    
    
    import java.io.File;
    
    public class Demo {
    
    	public static void deleteFile(File file){
    		//1:判断目录是否存在
    		if(file.exists()){
    			//1:判断是否是文件夹
    			if(file.isDirectory()){
    				//2 获取文件数组
    				File[] file2 = file.listFiles();
    				//3 遍历文件夹
    				for (File file3 : file2) {
    					//4:将遍历出来的文件以及目录传入方法中
    					deleteFile(file3);
    				}
    			}
    			//直接删除文件
    			file.delete();
    			
    		}
    	}
    	public static void main(String[] args) {
    		//创建根目录结构的抽象路径
    		File file = new File("a1");
    		
    		deleteFile(file);
    		
    		
    		
    		
    	}
    }
    
    

    1,循环(loop,指的是在满足条件的情况下,重复执行同一段代码。比如,while语句。 循环则技能对应集合,列表,数组等,也能对执行代码进行操作。

    2,迭代(iterate),**指的是按照某种顺序逐个访问列表中的每一项。比如,for语句。   迭代只能对应集合,列表,数组等。不能对执行代码进行迭代。

    3,遍历(traversal),指的是按照一定的规则访问树形结构中的每个节点,而且每个节点都只访问一次。 遍历同迭代一样,也不能对执行代码进行遍历。

    4,递归(recursion),指的是一个函数不断调用自身的行为。

    (1),通俗的解释:递归就像往存钱罐里存钱,先往里边塞钱,2块,5块,10块这样的塞,叫入栈。取钱的时候,后塞进去的先取出来,这叫出栈。具体多少钱,要全部出栈才知道。

    (2),递归分类:线性递归和尾递归。

    递归与循环的区别

    1。递归算法与迭代算法的设计思路区别在于:函数或算法是否具备收敛性,当且仅当一个算法存在预期的收敛效果时,采用递归算法才是可行的,否则,就不能使用递归算法。

    当然,从理论上说,所有的递归函数都可以转换为迭代函数,反之亦然,然而代价通常都是比较高的。但从算法结构来说,递归声明的结构并不总能够转换为迭代结构,原因在于结构的引申本身属于递归的概念,用迭代的方法在设计初期根本无法实现,这就像动多态的东西并不总是可以用静多态的方法实现一样。这也是为什么在结构设计时,通常采用递归的方式而不是采用迭代的方式的原因,一个极典型的例子类似于链表,使用递归定义及其简单,但对于内存定义(数组方式)其定义及调用处理说明就变得很晦涩,尤其是在遇到环链、图、网格等问题时,使用迭代方式从描述到实现上都变得很不现实。

    2。递归其实是方便了程序员难为了机器。它只要得到数学公式就能很方便的写出程序。优点就是易理解,容易编程。但递归是用栈机制实现的(c++),每深入一层,都要占去一块栈数据区域,对嵌套层数深的一些算法,递归会力不从心,空间上会以内存崩溃而告终,而且递归也带来了大量的函数调用,这也有许多额外的时间开销。所以在深度大时,它的时空性就不好了。

    循环其缺点就是不容易理解,编写复杂问题时困难。优点是效率高。运行时间只因循环次数增加而增加,没什么额外开销。空间上没有什么增加。

    3。局部变量占用的内存是一次性的,也就是O(1)的空间复杂度,而对于递归(不考虑尾递归优化的情况),每次函数调用都要压栈,那么空间复杂度是O(n),和递归次数呈线性关系。

    4。递归程序改用循环实现的话,一般都是要自己维护一个栈的,以便状态的回溯。如果某个递归程序改用循环的时候根本就不需要维护栈,那其实这个递归程序这样写只是意义明显一些,不一定要写成递归形式。但很多递归程序就是为了利用函数自身在系统栈上的auto变量记录状态,以便回溯。

    原理上讲,所有递归都是可以消除的,代价就是可能自己要维护一个栈。而且我个人认为,很多情况下用递归还是必要的,它往往能把复杂问题分解成更为简单的步骤,而且很能反映问题的本质。

    首先,递归和递推又一定的相似性(当然了,不然怎么会提出这个问题?)

    这两个问题都可以描述为以下形式:

    f(n)=g(f(n-1),…,f(0))

    这是二者的共同特点。

    不同点:

    1,从程序上看,递归表现为自己调用自己,递推则没有这样的形式。
    2,递归是从问题的最终目标出发,逐渐将复杂问题化为简单问题,最终求得问题
    是逆向的。递推是从简单问题出发,一步步的向前发展,最终求得问题。是正向的。
    3,递归中,问题的n要求是计算之前就知道的,而递推可以在计算中确定,不要求计算前就知道n。
    4,一般来说,递推的效率高于递归(当然是递推可以计算的情况下)

    由于一切递归问题都可以转化为循环求解,因此我们可以定义广义递归:

    如果转化为循环后,需要自己维护堆栈,则仍称为是递归的。

    在这个定义下,有些问题适用于用递归求解,如梵塔问题有些问题适用于用递推来做,如求满足N!>M条件时最小的N。有些问题二者都可以,如给定N时的阶乘问题。至于可读性,与问题有关,不能一概而论。

    递归其实就是利用系统堆栈,实现函数自身调用,或者是相互调用的过程。在通往边界的过程中,都会把单步地址保存下来,知道等出边界,再按照先进后出的进行运算,这正如我们装木桶一样,每一次都只能把东西方在最上面,而取得时候,先放进取的反而最后取出。递归的数据传送也类似。但是递归不能无限的进行下去,必须在一定条件下停止自身调用,因此它的边界值应是明确的。就向我们装木桶一样,我们不能总是无限制的往里装,必须在一定的时候把东取出来。比较简单的递归过程是阶乘函数,你可以去看一下。但是递归的运算方法,往往决定了它的效率很低,因为数据要不断的进栈出栈。这时递推便表现出它的作用了,所谓递推,就是免除了数据进出栈的过程。也就是说,不需要函数不断的向边界值靠拢,而直接从边界出发,直到求出函数值。比如,阶乘函数中,递归的数据流动过程如下:

    f(3){f(i)=f(i-1)*i}–>f(2)–>f(1)–>f(0){f(0)=1}–>f(1)–>f(2)–f(3){f(3)=6}

    而递推如下:

    f(0)–>f(1)–>f(2)–>f(3)

    由此可见,递推的效率要高一些,在可能的情况下应尽量使用递推。但是递归作为比较基础的算法,它的作用不能忽视。所以,在把握这两种算法的时候应该特别注意。

    展开全文
  • 有了前面的数组讲解,我们可以在一个数组里面添加很多个元素,也...一般而言程序的结构可以大致分为以下三种:顺序结构、选择结构、循环结构。它们的实现就是靠判断语句来实现,我们只需要掌握以下四个知识点就可以很
  • 新手小白学JAVA 分支结构 switch结构 for循环

    万次阅读 多人点赞 2021-04-01 13:53:14
    它由循环的条件,判断继续执行某个功能还是退出循环。 根据判断条件,循环结构又可细分为先判断后执行的循环结构和先执行后判断的循环结构。 3.2 for形式 3.3 for循环执行顺序 我们明明只写了一句打印语句,为...
  • Java while,do while, for 循环浅析

    千次阅读 2017-02-12 12:24:11
    Java 循环结构 - for, while 及 do...while ...Java中有三种主要的循环结构: while 循环 do…while 循环 for 循环Java5引入了一种主要用于数组的增强型for循环。 while 循环 while是最基本的循环
  • Java面试题全集(

    万次阅读 多人点赞 2015-04-09 22:05:20
    2015年重新整理发布的Java面试题全集,这部分主要是与Java Web和Web Service相关的面试题。
  • java以字节流形式读写文件

    千次阅读 2017-08-21 22:15:13
    java中以字节流的形式读取文件采用的是FileInputStream,将指定路径的文件以字节数组的形式循环读取,代码如下:public void ReadFileByByte(String path){ try { int length = 0; byte[] Buff = new byte...
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的主类有何不同?Java应用程序与小程序之间有那些差别?Java和C++的区别Oracle JDK 和 OpenJDK 的...
  • Java中的锁机制及Lock类 锁的释放-获取建立的happens before 关系 锁是java并发编程最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。 下面是锁释放-获取的...
  • Java笔试面试-Java 的各种锁和 CAS

    万次阅读 多人点赞 2019-09-23 09:58:40
    因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观地认为,不加锁的并发操作一定会出问题。 乐观锁  乐观锁正好和悲观锁相反,它获取数据的时候,并不担心数据被修改,每次获取数据的时候也不会加锁,只是...
  • Java中数组的定义与使用(一)

    万次阅读 多人点赞 2018-09-01 00:05:13
    数组的静态初始化一共分为以下两种类型: Tables Are 简化格式: 数据类型 数组名称 = {值, 值,…} 完整格式: 数据类型 数组名称 = new 数据类型[] {值, 值,…} 范例: 采用...
  • //语句嵌套形式:其实就是语句还有语句。 //循环嵌套 1、打印 public class ForForDemo { public static void main(String[] args) { for (int x = 0; x < 3; x++) { for (int y = 0; y < 4; y++)...
  • JAVA小白编程题练习 可能有很多刚入门的小白不知道自己如何能快速提升编程技巧与熟练度 其实大佬进阶之路只有一个~ 那就是疯狂码代码!!!实践出真知!!! 所以为了大家能够想练习的时候有素材,泡泡给大家整理了一些练习...
  • Java大佬在地表最强Java企业(阿里)面试总结

    万次阅读 多人点赞 2020-08-23 19:48:06
    面试题真的是博大精深,也通过这个面试题学到了很多...Hashtable 的方法是Synchronize的,而HashMap的方法在缺省情况下是非Synchronize的。 HashMap把Hashtable的contains方法去掉了,改成containsValue和contains.
  • Java面试题大全(2020版)

    万次阅读 多人点赞 2019-11-26 11:59:06
    发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全,希望对大家有帮助哈~ 本套Java面试题大全,全的不能再全,哈哈~ 一、Java 基础 1. JDK 和 JRE 有什么区别? JDK:Java ...
  • Java8 Stream语法详解 不用循环

    万次阅读 2017-04-12 15:52:42
    我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel aggregate operations. 我们来解读一下上面的那句话: Stream是元素的集合,这点让Stream看起来用...
  • java中数组遍历的三种方式

    千次阅读 2020-11-08 02:36:36
    1.for循环遍历 通常遍历数组都是使用for循环来...java5之后,Java提供了一种更简洁的循环:foreach循环,这种循环遍历数组和集合更加简洁。使用foreach循环遍历数组时,无须获得数组和集合长度,无须根据索引来访问数组
  • Java Map那些巧妙的设计

    万次阅读 多人点赞 2021-03-26 13:35:12
    因此,本文基于个人理解,对所阅读的部分源码进行了分类与总结,归纳出Map的几个核心特性。 最近拜读了一些Java Map的相关源码,不得不惊叹于JDK开发者们的鬼斧神工。他山之石可以攻玉,这些巧妙的设计思想非常...
  • java中volatile、synchronized和lock解析

    千次阅读 多人点赞 2017-03-07 21:10:34
    1、概述在研究并发程序时,我们需要了解java中关键字volatile和synchronized关键字的使用以及lock类的用法。首先,了解下java的内存模型:(1)每个线程都有自己的本地内存空间(java的帧)。线程执行时,先把...
  • 重新认识java(十一)---- java中的数组

    千次阅读 多人点赞 2017-03-08 21:14:54
    面向对象的一些知识暂时告一段落,从本文开始,进入java语法的重学阶段~
  • Java中Lambda表达式的使用

    万次阅读 多人点赞 2019-03-26 17:39:22
    Lambda表达式是Java SE 8一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。...
  • java

    千次阅读 2020-07-17 16:35:33
    jdk:java开发工具包,包含jre,jre包含jvm jre:java运行环境 jvm:jre的一部分,他是整个java实现跨平台的最核心部分,负责解释执行Java字节码文件,是运行java字节码文件的虚拟计算机,java跨平台的原因:Java...
  • java的三种主要循环结构

    千次阅读 2018-08-25 23:03:08
    java循环结构 顺序结构的程序语句只能 被执行一次。如果你要同样的操作执行多次,就需要使用循环结构。 java有三种主要的循环结构: while 循环 do ... while 循环 for 循环 在java5引入一种主要用于...
  • java中queue的使用

    千次阅读 2017-03-31 16:59:52
    java中queue的使用 Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Queue接 口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法的参数类型如果是Queue时,就完全只能...
  • Java虚拟机(JVM)你只要看这一篇就够了!

    万次阅读 多人点赞 2018-08-14 12:55:02
    1. Java 内存区域与内存溢出异常 ...字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成 如果线程正...
  • Java中的算术运算符

    千次阅读 2018-09-13 22:31:58
    JAVA语言常用的运算符可以分为以下几种 算术运算符、赋值运算符、比较运算符、逻辑运算符、条件运算符   Java中的算术运算符 算术运算符主要用于进行基本的算术运算,如加法、减法、乘法、除法等。 Java ...
  • 以下demo进行了扩展,增了消息循环和等待。 Java中的DatagramPacket与DatagramSocket的初步扩展的代码如下:1.接收端工程代码:由于接收端的控制台log会被发送端的log冲掉,所以把log写到文件。package ...
  • Java集合容器面试题(2020最新版)

    万次阅读 多人点赞 2020-03-01 11:08:34
    文章目录集合容器概述什么是集合集合的特点集合和数组的区别使用集合框架的好处常用的集合类有哪些?List,Set,Map三者的区别?List、Set、Map 是否继承自 Collection 接口?List、Map、Set 三个接口存取元素时,各...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 112,496
精华内容 44,998
关键字:

以下哪些是java中的循环形式

java 订阅