Skip to content

Instantly share code, notes, and snippets.

@VenkataRaju
Last active April 6, 2019 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VenkataRaju/18500aba90bdb62a02fda352986adfc6 to your computer and use it in GitHub Desktop.
Save VenkataRaju/18500aba90bdb62a02fda352986adfc6 to your computer and use it in GitHub Desktop.
Java File Related Statistics
public final Stats
{
public static void topJavaFilesByLoc() throws Exception
{
try (ZipFile zipFile = new ZipFile("/usr/lib/jvm/java-11.0.1-openjdk-amd64/lib/src.zip"))
{
Map<Long, Set<String>> fileNamesByNumberOfLines = zipFile.stream()
.map(zipEntry ->
{
if (zipEntry.isDirectory())
return null;
var name = zipEntry.getName();
int slashIndex = name.indexOf('/');
if (!name.regionMatches(slashIndex + 1, "java", 0, 4))
return null;
var fileNameWithPkg = name.substring(slashIndex + 1, name.length() - 5).replace('/', '.');
try (var br = new BufferedReader(new InputStreamReader(zipFile.getInputStream(zipEntry), StandardCharsets.UTF_8)))
{
return Map.entry(br.lines().count(), fileNameWithPkg);
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
})
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Entry::getKey,
() -> new TreeMap<Long, Set<String>>(Comparator.reverseOrder()),
Collectors.mapping(Entry::getValue, Collectors.toCollection(TreeSet::new))));
System.out.println("----------------");
System.out.println(" LOC | Class");
System.out.println("----------------");
fileNamesByNumberOfLines.entrySet().stream()
.limit(10)
.forEach(e -> System.out.printf("%,6d | %s%n", e.getKey(), String.join(", ", e.getValue())));
/**
* <pre>
----------------
LOC | Class
----------------
10,683 | java.lang.Character
10,515 | java.awt.Component
9,730 | javax.swing.JTable
8,906 | java.util.Arrays
6,382 | java.util.concurrent.ConcurrentHashMap
5,974 | java.lang.invoke.MethodHandles
5,961 | java.util.regex.Pattern
5,669 | javax.swing.JTree
5,638 | javax.swing.JComponent
5,616 | java.util.Collections
* </pre>
*/
}
}
static void publicOverloadedMethodStats()
{
Map<Long, Set<String>> map = Stream.of(Arrays.class.getDeclaredMethods())
.filter(m -> Modifier.isPublic(m.getModifiers()))
.collect(Collectors.groupingBy(Method::getName, Collectors.counting()))
.entrySet()
.stream()
.collect(Collectors.groupingBy(
Entry::getValue,
TreeMap::new,
Collectors.mapping(Entry::getKey, Collectors.toCollection(TreeSet::new))));
System.out.println("Overloaded | No. of Methods");
System.out.println("-----------------------------");
long noOfPublicMethods = 0;
for (Entry<Long, Set<String>> e : map.entrySet())
{
long key = e.getKey();
Set<String> val = e.getValue();
noOfPublicMethods += key * val.size();
System.out.printf("%2d %-5s | %2d methods (%s)%n", key, (key == 1 ? "time" : "times"), val.size(), String.join(", ", val));
}
System.out.println("Total No. of public methods: " + noOfPublicMethods);
// Overloaded | No. of Methods
// -----------------------------
// 1 time | 4 methods (asList, deepEquals, deepHashCode, deepToString)
// 4 times | 2 methods (parallelSetAll, setAll)
// 8 times | 4 methods (compareUnsigned, parallelPrefix, spliterator, stream)
// 9 times | 2 methods (hashCode, toString)
// 10 times | 2 methods (copyOf, copyOfRange)
// 18 times | 4 methods (binarySearch, fill, parallelSort, sort)
// 20 times | 3 methods (compare, equals, mismatch)
// Total No. of public methods: 214
}
static void publicOverloadedMethodStatsWithInPackage() throws Exception
{
try (ZipFile zipFile = new ZipFile("/usr/lib/jvm/java-9-oracle/lib/src.zip"))
{
Map<Entry<String, String>, Long> noOfMethodOccurancesByClassAndMethodName = zipFile.stream()
.map(ZipEntry::getName)
.filter(zen -> zen.startsWith("java.base/java/") && !zen.endsWith("package-info.java"))
.map(zen ->
{
StringBuilder sb = new StringBuilder(zen.length() + 1);
for (int i = 10, len = zen.length() - 5; i < len; i++)
{
char c = zen.charAt(i);
sb.append(c == '/' ? '.' : c);
}
return sb.toString();
})
.map(className ->
{
try
{
return Class.forName(className);
}
catch (ClassNotFoundException e)
{
System.out.println("Could not load class: " + className);
return null;
}
})
.filter(Objects::nonNull)
.flatMap(c -> Stream.of(c.getDeclaredMethods()))
.filter(m -> Modifier.isPublic(m.getModifiers()))
.collect(Collectors.groupingBy(m -> Map.entry(m.getDeclaringClass().getTypeName(), m.getName()), Collectors.counting()));
// Eclipse fails to compile all the expression at once
Comparator<Entry<String, String>> entryComparator = Comparator.comparing(Entry::getKey);
Map<Long, Set<Entry<String, String>>> classAndMethodsByNoOfMethodOccurances = noOfMethodOccurancesByClassAndMethodName
.entrySet()
.stream()
.collect(Collectors.groupingBy(
Entry::getValue,
TreeMap::new,
Collectors.mapping(Entry::getKey,
Collectors.toCollection(() -> new TreeSet<>(entryComparator.thenComparing(Entry::getValue))))));
System.out.println("Overloaded | No. of Methods");
System.out.println("-----------------------------");
long noOfPublicMethods = 0;
for (Entry<Long, Set<Entry<String, String>>> e : classAndMethodsByNoOfMethodOccurances.entrySet())
{
long noOfOccurances = e.getKey();
Set<Entry<String, String>> classAndMethodNames = e.getValue();
int noOfMethods = classAndMethodNames.size();
noOfPublicMethods += noOfOccurances * classAndMethodNames.size();
String methodNames;
if (noOfMethods > 10)
methodNames = ("(" + noOfMethods + ") methods");
else
{
methodNames = classAndMethodNames
.stream()
.collect(Collectors.groupingBy(Entry::getKey, Collectors.mapping(Entry::getValue, Collectors.toList())))
.toString();
methodNames = methodNames.substring(1, methodNames.length());
}
System.out.printf(" %2d %-5s | %4d %-7s %s%n", noOfOccurances,
(noOfOccurances == 1 ? "time" : "times"), noOfMethods, (noOfMethods == 1 ? "method" : "methods"),
methodNames);
}
System.out.println("\nTotal number of methods: " + noOfPublicMethods);
}
/**
* <pre>
Overloaded | No. of Methods
-----------------------------
1 time | 7899 methods (7899) methods
2 times | 1169 methods (1169) methods
3 times | 198 methods (198) methods
4 times | 155 methods (155) methods
5 times | 10 methods java.io.PrintWriter=[write], java.nio.IntBuffer=[put], java.nio.FloatBuffer=[put], java.nio.DoubleBuffer=[put], java.io.Writer=[write], java.nio.ShortBuffer=[put], java.security.KeyStore=[getInstance], java.nio.LongBuffer=[put], java.text.NumberFormat=[format], java.nio.ByteBuffer=[put]}
6 times | 42 methods (42) methods
7 times | 3 methods java.nio.CharBuffer=[put], java.util.concurrent.ForkJoinPool=[submit], java.time.LocalDateTime=[of]}
8 times | 5 methods java.util.Arrays=[compareUnsigned, parallelPrefix, spliterator, stream], java.util.ResourceBundle=[getBundle]}
9 times | 8 methods java.io.PrintWriter=[append, print], java.io.PrintStream=[print], java.util.Arrays=[hashCode, toString], java.io.StringWriter=[append], java.lang.String=[valueOf], java.io.CharArrayWriter=[append]}
10 times | 4 methods java.io.PrintWriter=[println], java.io.PrintStream=[println], java.util.Arrays=[copyOf, copyOfRange]}
11 times | 1 method java.util.Map=[of]}
12 times | 3 methods java.util.List=[of], java.lang.AbstractStringBuilder=[insert], java.util.Set=[of]}
13 times | 1 method java.util.Spliterators=[spliterator]}
16 times | 1 method java.lang.AbstractStringBuilder=[append]}
18 times | 4 methods java.util.Arrays=[binarySearch, fill, parallelSort, sort]}
20 times | 3 methods java.util.Arrays=[compare, equals, mismatch]}
24 times | 2 methods java.lang.StringBuffer=[insert], java.lang.StringBuilder=[insert]}
29 times | 2 methods java.lang.StringBuffer=[append], java.lang.StringBuilder=[append]}
Total number of methods: 12240
* </pre>
*/
}
static void topWordsInJavaSourceFiles() throws IOException
{
var pattern = Pattern.compile("[A-Z][A-Za-z]{3,}");
long topN = 100;
try (var zipFile = new ZipFile("/usr/lib/jvm/java-11.0.1-openjdk-amd64/lib/src.zip"))
{
var ai = new AtomicInteger();
String[] fullPathArr = { null };
Set<String> allPaths = new HashSet<String>();
Set<String> franklinPaths = new HashSet<String>();
Stream<String> wordsStream = zipFile.stream()
.flatMap(zipEntry ->
{
// jdk.localedata/sun/util/resources/provider/LocaleDataProvider.java
var fullPath = zipEntry.getName();
var firstSlash = fullPath.indexOf('/');
var secondSlash = fullPath.indexOf('/', firstSlash + 1);
if (secondSlash == -1) // jdk.management/module-info.java
return Stream.empty();
var packageName = fullPath.substring(firstSlash + 1, secondSlash);
if (!packageName.startsWith("java"))
return Stream.empty();
if (!fullPath.endsWith(".java"))
return Stream.<String>empty();
fullPathArr[0] = fullPath;
allPaths.add(fullPath);
ai.incrementAndGet();
try
{
return new BufferedReader(new InputStreamReader(zipFile.getInputStream(zipEntry))).lines();
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
})
.flatMap(line -> pattern.matcher(line).results().map(MatchResult::group))
.filter(word ->
{
if (word.equals("Franklin"))
franklinPaths.add(fullPathArr[0]);
// Allow if more small letters than capitals
for (int i = 0, half = word.length() / 2, noOfSmallCase = 0; i < word.length(); i++)
{
char c = word.charAt(i);
if (c >= 'a' && c <= 'z')
{
noOfSmallCase++;
if (noOfSmallCase > half)
return true;
}
}
return false;
});
Map<String, Long> repCountByWord = wordsStream
.collect(Collectors.groupingBy(Function.identity(),
() -> new TreeMap<>(),
Collectors.counting()));
franklinPaths.forEach(System.out::println);
System.out.println(franklinPaths.size());
allPaths.removeAll(franklinPaths);
System.out.println("Missing Franklin: " + allPaths);
System.out.println("Number of Java classses: " + ai.get());
System.out.printf("Total number of unique words matching pattern %s: %d%n%n", pattern.pattern(), repCountByWord.size());
int maxWordLength = 0;
long maxRepCount = 0;
for (Entry<String, Long> entry : repCountByWord.entrySet())
{
maxWordLength = Math.max(maxWordLength, entry.getKey().length());
maxRepCount = Math.max(maxRepCount, entry.getValue());
}
maxWordLength = Math.min(maxWordLength, 30);
String format = "%-" + maxWordLength + "s %," + (("" + maxRepCount).length() + 1) + "d%n";
Map<Long, Set<String>> wordsByRepCount = repCountByWord.entrySet().stream()
.collect(Collectors.groupingBy(Entry::getValue,
() -> new TreeMap<Long, Set<String>>(Comparator.reverseOrder()),
Collectors.mapping(Entry::getKey, Collectors.toCollection(TreeSet::new))));
wordsByRepCount.entrySet().stream()
.limit(topN)
.forEachOrdered(entry ->
{
Long wordCount = entry.getKey();
Set<String> words = entry.getValue();
for (String word : words)
System.out.printf(format, word, wordCount);
});
}
}
static void topClassFilesBySize() throws IOException
{
var basePath = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules");
try (var ps = Files.walk(basePath))
{
Map<Long, List<String>> pathsBySize = ps
.map(path ->
{
try
{
// path modules/java.base/java/lang/Object.class
if (!path.getFileName().toString().endsWith(".class"))
return null;
String pkgStartName = path.getName(2).toString();
if (!pkgStartName.startsWith("java"))
return null;
var pathWithoutModuleName = path.subpath(2, path.getNameCount()).toString().replace('/', '.');
return Map.entry(Files.size(path), pathWithoutModuleName);
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
})
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Entry::getKey,
() -> new TreeMap<Long, List<String>>(Comparator.reverseOrder()),
Collectors.mapping(Entry::getValue, Collectors.toCollection(ArrayList::new))));
System.out.println("-----------------");
System.out.println(" Size | Classes");
System.out.println("-----------------");
pathsBySize.entrySet().stream()
.limit(10)
.forEach(entry ->
{
var classNames = entry.getValue();
classNames.sort(Comparator.naturalOrder());
System.out.printf("%,6d | %s%n", entry.getKey(), String.join(", ", classNames));
});
}
/**
* <pre>
Size | Classes
-----------------
99,260 | java.awt.Component.class
82,650 | javax.swing.plaf.nimbus.NimbusDefaults.class
76,896 | javax.swing.JTable.class
64,480 | java.util.concurrent.ConcurrentHashMap.class
63,643 | java.math.BigDecimal.class
62,932 | java.util.Arrays.class
61,693 | javax.swing.JComponent.class
61,447 | java.util.concurrent.CompletableFuture.class
59,067 | java.math.BigInteger.class
58,990 | javax.swing.plaf.basic.BasicLookAndFeel.class
* </pre>
*/
}
static void topClassFilesBySizeInclusingInnerClasses() throws IOException
{
var basePath = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules");
try (var ps = Files.walk(basePath))
{
Map<String, List<Entry<String, Long>>> classNameAndSizesByParentClassName = ps
.map(path ->
{
try
{
// path modules/java.base/java/lang/Object.class
if (!path.getFileName().toString().endsWith(".class"))
return null;
String pkgStartName = path.getName(2).toString();
if (!pkgStartName.startsWith("java"))
return null;
var pathWithoutModuleName = path.subpath(2, path.getNameCount()).toString().replace('/', '.');
var pathWithoutExtn = pathWithoutModuleName.substring(0, pathWithoutModuleName.length() - 6);
var dollarIndex = pathWithoutExtn.lastIndexOf('$');
var parentClassName = dollarIndex == -1 ? pathWithoutExtn : pathWithoutExtn.substring(0, dollarIndex);
return Map.entry(parentClassName, Map.entry(pathWithoutExtn, Files.size(path)));
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
})
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Entry::getKey,
Collectors.mapping(Entry::getValue, Collectors.toList())));
Map<Long, List<Entry<String, Long>>> classNameAnsSizesByTotalSize = classNameAndSizesByParentClassName.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getValue().stream().mapToLong(Entry::getValue).sum(),
Entry::getValue,
(l1, l2) ->
{
l1.addAll(l2);
return l1;
},
() -> new TreeMap<Long, List<Entry<String, Long>>>(Comparator.reverseOrder())));
//
System.out.println("-------------------");
System.out.println(" Size | Classes");
System.out.println("-------------------");
classNameAnsSizesByTotalSize.entrySet().stream()
.limit(10)
.forEach(entry ->
{
var classNames = entry.getValue();
var max = Collections.max(classNames, Entry.comparingByKey());
System.out.printf("%,8d | %s + %2d inner classes%n", entry.getKey(), max.getKey(), classNames.size() - 1);
});
/**
* <pre>
Started
-------------------
Size | Classes
-------------------
250,052 | java.util.concurrent.ConcurrentHashMap + 53 inner classes
200,321 | java.util.Collections + 45 inner classes
154,180 | java.lang.invoke.BoundMethodHandle + 38 inner classes
139,571 | java.util.concurrent.CompletableFuture + 33 inner classes
135,156 | java.util.regex.Pattern + 58 inner classes
132,122 | java.awt.Component + 13 inner classes
124,450 | javax.swing.JTable + 23 inner classes
123,970 | java.time.format.DateTimeFormatterBuilder + 23 inner classes
111,738 | javax.swing.plaf.basic.BasicTreeUI + 21 inner classes
102,551 | javax.swing.plaf.basic.BasicTabbedPaneUI + 14 inner classes
Completed
* </pre>
*/
}
}
static void topClassFilesByNoOfInnerClasses() throws IOException
{
var basePath = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules");
try (var ps = Files.walk(basePath))
{
Map<String, List<String>> innerClassesByParentClassName = ps
.map(path ->
{
// path e.g. modules/java.base/java/lang/Object.class
if (!path.getFileName().toString().endsWith(".class"))
return null;
String pkgStartName = path.getName(2).toString();
if (!pkgStartName.startsWith("java"))
return null;
var pathWithoutModuleName = path.subpath(2, path.getNameCount()).toString().replace('/', '.');
var pathWithoutExtn = pathWithoutModuleName.substring(0, pathWithoutModuleName.length() - 6);
var dollarIndex = pathWithoutExtn.lastIndexOf('$');
var parentClassName = dollarIndex == -1 ? pathWithoutExtn : pathWithoutExtn.substring(0, dollarIndex);
return Map.entry(parentClassName, pathWithoutExtn);
})
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Entry::getKey,
Collectors.mapping(Entry::getValue, Collectors.toList())));
Map<Integer, List<List<String>>> innerClassesByCount = innerClassesByParentClassName.entrySet().stream()
.collect(Collectors.groupingBy(
entry -> entry.getValue().size(),
() -> new TreeMap<Integer, List<List<String>>>(Comparator.reverseOrder()),
Collectors.mapping(Entry::getValue, Collectors.toList())));
System.out.println("------------------------------------------------");
System.out.println(" No Of Inner Classes | Parent Class ");
System.out.println("------------------------------------------------");
innerClassesByCount.entrySet().stream()
.limit(10)
.forEach(entry ->
{
var noOfInnerClasses = entry.getKey();
for (List<String> innerClasses : entry.getValue())
{
var parentClass = Collections.min(innerClasses, Comparator.naturalOrder());
System.out.printf("%21d | %s%n", noOfInnerClasses, parentClass);
}
});
/**
* <pre>
------------------------------------------------
No Of Inner Classes | Parent Class
------------------------------------------------
77 | javax.imageio.plugins.tiff.BaselineTIFFTagSet
59 | java.util.regex.Pattern
58 | javax.imageio.plugins.tiff.ExifTIFFTagSet
54 | java.util.concurrent.ConcurrentHashMap
48 | java.beans.MetaData
46 | java.util.Collections
39 | java.lang.invoke.BoundMethodHandle
36 | java.util.stream.ReduceOps
34 | javax.swing.text.DefaultEditorKit
34 | java.util.concurrent.CompletableFuture
32 | javax.imageio.plugins.tiff.ExifGPSTagSet
* </pre>
*/
}
}
static void publicStaticFields() throws Throwable
{
var basePath = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules");
try (var pathStream = Files.walk(basePath))
{
for (var path : (Iterable<Path>) pathStream::iterator)
{
if (path.getNameCount() == 1)
System.out.println(path);
if (path.getNameCount() < 3)
continue;
String pkgStartName = path.getName(2).toString();
if (!pkgStartName.equals("java"))
continue;
Path fileNamePath = path.getFileName();
if (fileNamePath == null || !fileNamePath.toString().endsWith(".class"))
continue;
// path e.g. modules/java.base/java/lang/Object.class
var pathWithoutModuleName = path.subpath(2, path.getNameCount()).toString().replace('/', '.');
var pathWithoutClassExtn = pathWithoutModuleName.substring(0, pathWithoutModuleName.lastIndexOf('.'));
Class<?> cls = Class.forName(pathWithoutClassExtn);
if (!Modifier.isPublic(cls.getModifiers()))
continue;
for (var field : cls.getFields())
{
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())
&& field.getType().isArray())
System.out.println(field);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment