public static String simplifyPath(String pathname) {
    checkNotNull(pathname);
    if (pathname.length() == 0) {
      return ".";
    }

    // split the path apart
    Iterable<String> components = Splitter.on('/').omitEmptyStrings().split(pathname);
    List<String> path = new ArrayList<String>();

    // resolve ., .., and //
    for (String component : components) {
      if (component.equals(".")) {
        continue;
      } else if (component.equals("..")) {
        if (path.size() > 0 && !path.get(path.size() - 1).equals("..")) {
          path.remove(path.size() - 1);
        } else {
          path.add("..");
        }
      } else {
        path.add(component);
      }
    }

    // put it back together
    String result = Joiner.on('/').join(path);
    if (pathname.charAt(0) == '/') {
      result = "/" + result;
    }

    while (result.startsWith("/../")) {
      result = result.substring(3);
    }
    if (result.equals("/..")) {
      result = "/";
    } else if ("".equals(result)) {
      result = ".";
    }

    return result;
  }
public static String simplifyPath ( String pathname ) { checkNotNull ( pathname ) ; if ( pathname . length ( ) == 0 ) { return "." ; } Iterable < String > components = Splitter . on ( '/' ) . omitEmptyStrings ( ) . split ( pathname ) ; List < String > path = new ArrayList < String > ( ) ; for ( String component : components ) { if ( component . equals ( "." ) ) { continue ; } else if ( component . equals ( ".." ) ) { if ( path . size ( ) > 0 && ! path . get ( path . size ( ) - 1 ) . equals ( ".." ) ) { path . remove ( path . size ( ) - 1 ) ; } else { path . add ( ".." ) ; } } else { path . add ( component ) ; } } String result = Joiner . on ( '/' ) . join ( path ) ; if ( pathname . charAt ( 0 ) == '/' ) { result = "/" + result ; } while ( result . startsWith ( "/../" ) ) { result = result . substring ( 3 ) ; } if ( result . equals ( "/.." ) ) { result = "/" ; } else if ( "" . equals ( result ) ) { result = "." ; } return result ; }
Returns the lexically cleaned form of the path name, <i>usually</i> (but not always) equivalent
to the original. The following heuristics are used:

<ul>
<li>empty string becomes .
<li>. stays as .
<li>fold out ./
<li>fold out ../ when possible
<li>collapse multiple slashes
<li>delete trailing slashes (unless the path is just "/")
</ul>

<p>These heuristics do not always match the behavior of the filesystem. In particular, consider
the path {@code a/../b}, which {@code simplifyPath} will change to {@code b}. If {@code a} is a
symlink to {@code x}, {@code a/../b} may refer to a sibling of {@code x}, rather than the
sibling of {@code a} referred to by {@code b}.

@since 11.0